Clover coverage report - groovy - 1.0-beta-7
Coverage timestamp: Wed Sep 29 2004 16:55:52 BST
file stats: LOC: 645   Methods: 51
NCLOC: 424   Classes: 5
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
XmlSlurper.java 0% 0% 0% 0%
coverage
 1   
 package org.codehaus.groovy.sandbox.util;
 2   
 import groovy.lang.Closure;
 3   
 import groovy.lang.GroovyObject;
 4   
 import groovy.lang.GroovyObjectSupport;
 5   
 import groovy.lang.Writable;
 6   
 
 7   
 import java.io.File;
 8   
 import java.io.FileInputStream;
 9   
 import java.io.IOException;
 10   
 import java.io.InputStream;
 11   
 import java.io.Reader;
 12   
 import java.io.StringReader;
 13   
 import java.io.Writer;
 14   
 import java.security.AccessController;
 15   
 import java.security.PrivilegedActionException;
 16   
 import java.security.PrivilegedExceptionAction;
 17   
 import java.util.HashMap;
 18   
 import java.util.Iterator;
 19   
 import java.util.LinkedList;
 20   
 import java.util.List;
 21   
 import java.util.Map;
 22   
 
 23   
 import javax.xml.parsers.ParserConfigurationException;
 24   
 import javax.xml.parsers.SAXParser;
 25   
 import javax.xml.parsers.SAXParserFactory;
 26   
 
 27   
 import org.codehaus.groovy.sandbox.markup.Buildable;
 28   
 import org.xml.sax.Attributes;
 29   
 import org.xml.sax.InputSource;
 30   
 import org.xml.sax.SAXException;
 31   
 import org.xml.sax.XMLReader;
 32   
 import org.xml.sax.helpers.DefaultHandler;
 33   
 
 34   
 
 35   
 public class XmlSlurper extends DefaultHandler {
 36   
     private final XMLReader reader;
 37   
     private List result = null;
 38   
     private List body = null;
 39   
     private final StringBuffer charBuffer = new StringBuffer();
 40   
 
 41  0
     public XmlSlurper() throws ParserConfigurationException, SAXException {
 42  0
         this(false, true);
 43   
     }
 44   
 
 45  0
     public XmlSlurper(final boolean validating, final boolean namespaceAware) throws ParserConfigurationException, SAXException {
 46  0
         SAXParserFactory factory = null;
 47   
         
 48  0
             try {
 49  0
                 factory = (SAXParserFactory) AccessController.doPrivileged(new PrivilegedExceptionAction() {
 50  0
                     public Object run() throws ParserConfigurationException {
 51  0
                         return SAXParserFactory.newInstance();
 52   
                     }
 53   
                 });
 54   
             } catch (final PrivilegedActionException pae) {
 55  0
             final Exception e = pae.getException();
 56   
                 
 57  0
                 if (e instanceof ParserConfigurationException) {
 58  0
                     throw (ParserConfigurationException) e;
 59   
                 } else {
 60  0
                     throw new RuntimeException(e);
 61   
                 }
 62   
             }
 63  0
         factory.setNamespaceAware(namespaceAware);
 64  0
         factory.setValidating(validating);
 65   
 
 66  0
         final SAXParser parser = factory.newSAXParser();
 67  0
         this.reader = parser.getXMLReader();
 68   
     }
 69   
 
 70  0
     public XmlSlurper(final XMLReader reader) {
 71  0
         this.reader = reader;
 72   
     }
 73   
 
 74  0
     public XmlSlurper(final SAXParser parser) throws SAXException {
 75  0
         this(parser.getXMLReader());
 76   
     }
 77   
 
 78   
     /**
 79   
      * Parse the content of the specified input source into a List
 80   
      */
 81  0
     public XmlList parse(final InputSource input) throws IOException, SAXException {
 82  0
             this.reader.setContentHandler(this);
 83  0
             this.reader.parse(input);
 84   
         
 85  0
         return (XmlList)this.result.get(0);
 86   
     }
 87   
     
 88   
     /**
 89   
      * Parses the content of the given file as XML turning it into a List
 90   
      */
 91  0
     public XmlList parse(final File file) throws IOException, SAXException {
 92  0
     final InputSource input = new InputSource(new FileInputStream(file));
 93   
     
 94  0
         input.setSystemId("file://" + file.getAbsolutePath());
 95   
         
 96  0
         return parse(input);
 97   
 
 98   
     }
 99   
 
 100   
     /**
 101   
      * Parse the content of the specified input stream into a List.
 102   
      * Note that using this method will not provide the parser with any URI
 103   
      * for which to find DTDs etc
 104   
      */
 105  0
     public XmlList parse(final InputStream input) throws IOException, SAXException {
 106  0
         return parse(new InputSource(input));
 107   
     }
 108   
 
 109   
     /**
 110   
      * Parse the content of the specified reader into a List.
 111   
      * Note that using this method will not provide the parser with any URI
 112   
      * for which to find DTDs etc
 113   
      */
 114  0
     public XmlList parse(final Reader in) throws IOException, SAXException {
 115  0
         return parse(new InputSource(in));
 116   
     }
 117   
 
 118   
     /**
 119   
      * Parse the content of the specified URI into a List
 120   
      */
 121  0
     public XmlList parse(final String uri) throws IOException, SAXException {
 122  0
         return parse(new InputSource(uri));
 123   
     }
 124   
 
 125   
     /**
 126   
      * A helper method to parse the given text as XML
 127   
      * 
 128   
      * @param text
 129   
      * @return
 130   
      */
 131  0
     public XmlList parseText(final String text) throws IOException, SAXException {
 132  0
         return parse(new StringReader(text));
 133   
     }
 134   
     
 135   
 
 136   
     // ContentHandler interface
 137   
     //-------------------------------------------------------------------------                    
 138   
     
 139   
     /* (non-Javadoc)
 140   
      * @see org.xml.sax.ContentHandler#startDocument()
 141   
      */
 142  0
     public void startDocument() throws SAXException {
 143  0
         this.result = null;
 144  0
         this.body = new LinkedList();
 145  0
         this.charBuffer.setLength(0);
 146   
     }
 147   
     
 148   
     /* (non-Javadoc)
 149   
      * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
 150   
      */
 151  0
     public void startElement(final String namespaceURI, final String localName, final String qName, final Attributes atts) throws SAXException {
 152  0
         addNonWhitespaceCdata();
 153   
         
 154  0
         final Map attributes = new HashMap();
 155   
         
 156  0
         for (int i = atts.getLength() - 1; i != -1; i--) {
 157  0
             if (atts.getURI(i).length() == 0) {
 158  0
                 attributes.put(atts.getQName(i), atts.getValue(i));
 159   
             } else {
 160   
                 //
 161   
                 // Note this is strictly incorrect the name is really localname + URI
 162   
                 // We need to figure out what to do with paramenters in namespaces
 163   
                 //
 164  0
                 attributes.put(atts.getLocalName(i), atts.getValue(i));
 165   
             }
 166   
             
 167   
         }
 168   
         
 169  0
         final List newBody = new LinkedList();
 170   
 
 171  0
         newBody.add(attributes);
 172   
         
 173  0
         newBody.add(this.body);
 174   
 
 175  0
         this.body = newBody;
 176   
     }
 177   
 
 178   
     /* (non-Javadoc)
 179   
      * @see org.xml.sax.ContentHandler#characters(char[], int, int)
 180   
      */
 181  0
     public void characters(final char[] ch, final int start, final int length) throws SAXException {
 182  0
         this.charBuffer.append(ch, start, length);
 183   
     }
 184   
     
 185   
     /* (non-Javadoc)
 186   
      * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
 187   
      */
 188  0
     public void endElement(final String namespaceURI, final String localName, final String qName) throws SAXException {
 189  0
         addNonWhitespaceCdata();
 190   
         
 191  0
         final List children = this.body;
 192   
         
 193  0
         final Map attributes = (Map)this.body.remove(0);
 194   
         
 195  0
         this.body = (List)this.body.remove(0);
 196   
         
 197  0
         if (namespaceURI.length() == 0) {
 198  0
             this.body.add(new XmlList(qName, attributes, children, namespaceURI));
 199   
         } else {
 200  0
             this.body.add(new XmlList(localName, attributes, children, namespaceURI));
 201   
         }
 202   
     }
 203   
     
 204   
     /* (non-Javadoc)
 205   
      * @see org.xml.sax.ContentHandler#endDocument()
 206   
      */
 207  0
     public void endDocument() throws SAXException {
 208  0
         this.result = this.body;
 209  0
         this.body = null;
 210   
     }
 211   
 
 212   
     // Implementation methods
 213   
     //-------------------------------------------------------------------------           
 214   
 
 215   
     /**
 216   
      * 
 217   
      */
 218  0
     private void addNonWhitespaceCdata() {
 219  0
         if (this.charBuffer.length() != 0) {
 220   
             //
 221   
             // This element is preceeded by CDATA if it's not whitespace add it to the body
 222   
             // Note that, according to the XML spec, we should preserve the CDATA if it's all whitespace
 223   
             // but for the sort of work I'm doing ignoring the whitespace is preferable
 224   
             //
 225  0
             final String cdata = this.charBuffer.toString();
 226   
             
 227  0
             this.charBuffer.setLength(0);
 228  0
             if (cdata.trim().length() != 0) {
 229  0
                 this.body.add(cdata);
 230   
             }
 231   
         }        
 232   
     }
 233   
 }
 234   
 
 235   
 class XmlList extends GroovyObjectSupport implements Writable, Buildable {
 236   
     final String name;
 237   
     final Map attributes;
 238   
     final Object[] children;
 239   
     final String namespaceURI;
 240   
     
 241  0
     public XmlList(final String name, final Map attributes, final List body, final String namespaceURI) {
 242  0
         super();
 243   
         
 244  0
         this.name = name;
 245  0
         this.attributes = attributes;
 246  0
         this.children = body.toArray();
 247  0
         this.namespaceURI = namespaceURI;
 248   
     }
 249   
     
 250  0
     public Object getProperty(final String elementName) {
 251  0
             if (elementName.startsWith("@")) {
 252  0
                 return this.attributes.get(elementName.substring(1));
 253   
             } else {
 254  0
             final int indexOfFirst = getNextXmlElement(elementName, -1);
 255   
             
 256  0
                 if (indexOfFirst == -1) { // no elements match the element name
 257  0
                     return new ElementCollection() {
 258  0
                         protected ElementCollection getResult(final String property) {
 259  0
                             return this;
 260   
                         }
 261   
 
 262   
                                 /**
 263   
                                  * 
 264   
                                  * Used by the Invoker when it wants to iterate over this object
 265   
                                  * 
 266   
                                  * @return
 267   
                                  */
 268  0
                                 public ElementIterator iterator() {
 269  0
                                     return new ElementIterator(new XmlList[]{XmlList.this}, new int[]{-1}) {
 270   
                                         {
 271  0
                                             findNextChild();        // set up the element indexes
 272   
                                         }
 273   
                                         
 274  0
                                     protected void findNextChild() {
 275  0
                                         this.nextParentElements[0] = -1;
 276   
                                     }
 277   
                                     };
 278   
                                 }
 279   
                     };
 280   
                 }
 281   
                 
 282  0
                 if (getNextXmlElement(elementName, indexOfFirst) == -1) {    // one element matches the element name
 283  0
                     return this.children[indexOfFirst];
 284   
                 } else {        // > 1 element matches the element name
 285  0
                         return new ElementCollection() {
 286  0
                             protected ElementCollection getResult(final String property) {
 287  0
                                 return new ComplexElementCollection(new XmlList[]{XmlList.this},
 288   
                                                                  new int[] {indexOfFirst},
 289   
                                                                 new String[] {elementName},
 290   
                                                                 property);
 291   
                             }
 292   
     
 293   
                                 /**
 294   
                                  * 
 295   
                                  * Used by the Invoker when it wants to iterate over this object
 296   
                                  * 
 297   
                                  * @return
 298   
                                  */
 299  0
                                 public ElementIterator iterator() {
 300  0
                                     return new ElementIterator(new XmlList[]{XmlList.this}, new int[]{indexOfFirst}) {
 301  0
                                     protected void findNextChild() {
 302  0
                                         this.nextParentElements[0] = XmlList.this.getNextXmlElement(elementName, this.nextParentElements[0]);
 303   
                                     }
 304   
                                     };
 305   
                                 }
 306   
                         };
 307   
                 }
 308   
             }
 309   
     }
 310   
     
 311  0
     public Object getAt(final int index) {
 312  0
             if (index == 0) {
 313  0
                 return this;
 314   
             } else {
 315  0
                 throw new ArrayIndexOutOfBoundsException(index);
 316   
             }
 317   
         }
 318   
     
 319  0
     public int size() {
 320  0
             return 1;
 321   
     }
 322   
 
 323  0
     public Object invokeMethod(final String name, final Object args) {
 324  0
         if ("attributes".equals(name)) {
 325  0
             return this.attributes;
 326  0
         } else if ("name".equals(name)) {
 327  0
             return this.name;
 328  0
         } else if ("children".equals(name)) {
 329  0
             return this.children;
 330  0
         } else if ("contents".equals(name)) {
 331  0
             return new Buildable() {
 332  0
                 public void build(GroovyObject builder) {
 333  0
                     buildChildren(builder);
 334   
                 }
 335   
             };
 336  0
         } else if ("text".equals(name)) {
 337  0
             return text();
 338  0
         } else if ("getAt".equals(name) && ((Object[])args)[0] instanceof String) {
 339  0
             return getProperty((String)((Object[])args)[0]);
 340  0
         } else if ("depthFirst".equals(name)) {
 341   
             //
 342   
             // TODO: replace this with an iterator
 343   
             //
 344   
             
 345  0
             return new GroovyObjectSupport() {
 346  0
                 public Object invokeMethod(final String name, final Object args) {
 347  0
                     if ("getAt".equals(name) && ((Object[])args)[0] instanceof String) {
 348  0
                         return getProperty((String)((Object[])args)[0]);
 349   
                     } else {
 350  0
                         return XmlList.this.invokeMethod(name, args);
 351   
                     }
 352   
                 }
 353   
                 
 354  0
                 public Object getProperty(final String property) {
 355  0
                     if (property.startsWith("@")) {
 356  0
                         return XmlList.this.getProperty(property);
 357   
                     } else {
 358  0
                     final List result = new LinkedList();
 359   
 
 360  0
                         depthFirstGetProperty(property, XmlList.this.children, result);
 361   
                         
 362  0
                         return result;
 363   
                     }
 364   
                 }
 365   
                 
 366  0
                 private void depthFirstGetProperty(final String property, final Object[] contents, final List result) {
 367  0
                         for (int i = 0; i != contents.length; i++) {
 368  0
                         final Object item = contents[i];
 369   
                         
 370  0
                             if (item instanceof XmlList) {
 371  0
                                 if (((XmlList)item).name.equals(property)) {
 372  0
                                     result.add(item);
 373   
                                 }
 374   
                                 
 375  0
                                 depthFirstGetProperty(property, ((XmlList)item).children, result);
 376   
                             }
 377   
                     }
 378   
                 }
 379   
             };
 380   
             } else {
 381  0
                 return getMetaClass().invokeMethod(this, name, args);
 382   
             }
 383   
     }
 384   
     
 385   
     /* (non-Javadoc)
 386   
      * @see groovy.lang.Writable#writeTo(java.io.Writer)
 387   
      */
 388  0
     public Writer writeTo(Writer out) throws IOException {
 389   
 
 390  0
         for (int i = 0; i != this.children.length; i++) {
 391  0
         final Object child = this.children[i];
 392   
         
 393  0
             if (child instanceof String) {
 394  0
                 out.write((String)child);
 395   
             } else {
 396  0
                 ((XmlList)child).writeTo(out);
 397   
             }
 398   
         }
 399   
         
 400  0
         return out;
 401   
     }
 402   
     
 403   
     /* (non-Javadoc)
 404   
      * @see org.codehaus.groovy.sandbox.markup.Buildable#build(groovy.lang.GroovyObject)
 405   
      */
 406  0
     public void build(final GroovyObject builder) {
 407   
         // TODO handle Namespaces
 408  0
     final Closure rest = new Closure(null) {
 409  0
         public Object doCall(final Object o) {
 410  0
             buildChildren(builder);
 411   
             
 412  0
             return null;
 413   
         }
 414   
     };
 415   
 
 416  0
         builder.invokeMethod(this.name, new Object[]{this.attributes, rest});
 417   
         
 418   
     }
 419   
     
 420  0
     public String toString() {
 421  0
         return text();
 422   
     }
 423   
     
 424  0
     private String text() {
 425  0
     final StringBuffer buff = new StringBuffer();
 426   
 
 427  0
         for (int i = 0; i != this.children.length; i++) {
 428  0
         final Object child = this.children[i];
 429   
         
 430  0
             if (child instanceof String) {
 431  0
                 buff.append(child);
 432   
             } else {
 433  0
                 buff.append(((XmlList)child).text());
 434   
             }
 435   
         }    
 436   
     
 437  0
         return buff.toString();
 438   
     }
 439   
     
 440  0
     private void buildChildren(final GroovyObject builder) {
 441  0
         for (int i = 0; i != this.children.length; i++) {
 442  0
             if (this.children[i] instanceof Buildable) {
 443  0
                 ((Buildable)this.children[i]).build(builder);
 444   
             } else {
 445  0
                 builder.getProperty("mkp");
 446  0
                 builder.invokeMethod("yield", new Object[]{this.children[i]});
 447   
             }
 448   
         }
 449   
     }
 450   
 
 451  0
         protected int getNextXmlElement(final String name, final int lastFound) {
 452  0
             for (int i = lastFound + 1; i < this.children.length; i++) {
 453  0
             final Object item = this.children[i];
 454   
                 
 455  0
                 if (item instanceof XmlList && ((XmlList)item).name.equals(name)) {
 456  0
                     return i;
 457   
                 }
 458   
             }
 459   
             
 460  0
             return -1;
 461   
         }
 462   
 }
 463   
 
 464   
 abstract class ElementIterator implements Iterator {
 465   
     protected final XmlList[] parents;
 466   
     protected final int[] nextParentElements;
 467   
     
 468  0
     protected ElementIterator(final XmlList[] parents, int[] nextParentElements) {
 469  0
         this.parents = new XmlList[parents.length];
 470  0
         System.arraycopy(parents, 0, this.parents, 0, parents.length);
 471   
         
 472  0
         this.nextParentElements = new int[nextParentElements.length];
 473  0
         System.arraycopy(nextParentElements, 0, this.nextParentElements, 0, nextParentElements.length);
 474   
     }
 475   
     
 476   
     /* (non-Javadoc)
 477   
      * @see java.util.Iterator#hasNext()
 478   
      */
 479  0
     public boolean hasNext() {
 480  0
         return this.nextParentElements[0] != -1;
 481   
     }
 482   
     
 483   
     /* (non-Javadoc)
 484   
      * @see java.util.Iterator#next()
 485   
      */
 486  0
     public Object next() {
 487  0
     final Object result = this.parents[0].children[this.nextParentElements[0]];
 488   
             
 489  0
         findNextChild();
 490   
     
 491  0
         return result;
 492   
     }
 493   
     
 494   
     /* (non-Javadoc)
 495   
      * @see java.util.Iterator#remove()
 496   
      */
 497  0
     public void remove() {
 498  0
         throw new UnsupportedOperationException();
 499   
     }
 500   
     
 501   
     protected abstract void findNextChild();
 502   
 }
 503   
 
 504   
 abstract class ElementCollection extends GroovyObjectSupport {
 505   
     private int count = -1;
 506   
     
 507   
     public abstract ElementIterator iterator();
 508   
     
 509   
     /* (non-Javadoc)
 510   
      * @see groovy.lang.GroovyObject#getProperty(java.lang.String)
 511   
      */
 512  0
     public Object getProperty(final String property) {
 513  0
     final ElementCollection result = getResult(property);
 514  0
     final Iterator iterator = result.iterator();
 515   
 
 516  0
         if (iterator.hasNext()) {                
 517   
             //
 518   
             // See if there's only one available
 519   
             //
 520  0
             final Object first = iterator.next();
 521   
             
 522  0
             if (!iterator.hasNext()) {
 523  0
                 return first;
 524   
             }
 525   
         }
 526   
         
 527  0
         return result;
 528   
     }
 529   
     
 530   
     protected abstract ElementCollection getResult(String property);
 531   
     
 532  0
     public synchronized Object getAt(int index) {
 533  0
             if (index >= 0) {
 534  0
         final Iterator iter = iterator();
 535   
         
 536  0
             while (iter.hasNext()) {
 537  0
                 if (index-- == 0) {
 538  0
                     return iter.next();
 539   
                 } else {
 540  0
                     iter.next();
 541   
                 }
 542   
             }
 543   
             }
 544   
             
 545  0
             throw new ArrayIndexOutOfBoundsException(index);
 546   
     }
 547   
     
 548  0
     public synchronized int size() {
 549  0
         if (this.count == -1) {
 550  0
         final Iterator iter = iterator();
 551   
         
 552  0
             this.count = 0;
 553   
             
 554  0
             while (iter.hasNext()) {
 555  0
                 this.count++;
 556  0
                 iter.next();
 557   
             }
 558   
         }
 559  0
         return this.count;
 560   
     }
 561   
 }
 562   
 
 563   
 class ComplexElementCollection extends ElementCollection {
 564   
     private final XmlList[] parents;
 565   
     private final int[] nextParentElements;
 566   
     private final String[] parentElementNames;
 567   
     
 568  0
     public ComplexElementCollection(final XmlList[] parents,
 569   
                                       final int[] nextParentElements,
 570   
                                   final String[] parentElementNames,
 571   
                                   final String childElementName)
 572   
     {
 573  0
         this.parents = new XmlList[parents.length + 1];
 574  0
         this.parents[0] = (XmlList)parents[0].children[nextParentElements[0]];
 575  0
         System.arraycopy(parents, 0, this.parents, 1, parents.length);
 576   
         
 577  0
         this.nextParentElements = new int[nextParentElements.length + 1];
 578  0
         this.nextParentElements[0] = -1;    
 579  0
         System.arraycopy(nextParentElements, 0, this.nextParentElements, 1, nextParentElements.length);
 580   
         
 581  0
         this.parentElementNames = new String[parentElementNames.length + 1];
 582  0
         this.parentElementNames[0] = childElementName;
 583  0
         System.arraycopy(parentElementNames, 0, this.parentElementNames, 1, parentElementNames.length);
 584   
         
 585   
         //
 586   
         // Use the iterator to get the index of the first element
 587   
         //
 588   
         
 589  0
         final ElementIterator iter = this.iterator();
 590   
         
 591  0
         iter.findNextChild();
 592   
         
 593  0
         this.nextParentElements[0] = iter.nextParentElements[0];
 594   
     }
 595   
     
 596  0
     protected ElementCollection getResult(final String property) {
 597  0
         return new ComplexElementCollection(this.parents,
 598   
                                                this.nextParentElements,
 599   
                                             this.parentElementNames,
 600   
                                             property);
 601   
     }
 602   
     
 603   
     /**
 604   
      * 
 605   
      * Used by the Invoker when it wants to iterate over this object
 606   
      * 
 607   
      * @return
 608   
      */
 609  0
     public ElementIterator iterator() {
 610  0
         return new ElementIterator(this.parents, this.nextParentElements) {
 611  0
                         protected void findNextChild() {    
 612  0
                             this.nextParentElements[0] = this.parents[0].getNextXmlElement(ComplexElementCollection.this.parentElementNames[0], this.nextParentElements[0]);
 613   
                             
 614  0
                             while (this.nextParentElements[0] == -1) {
 615  0
                                 this.parents[0] = findNextParent(1);
 616   
                                 
 617  0
                                 if (this.parents[0] == null) {
 618  0
                                     return;
 619   
                                 } else {
 620  0
                                     this.nextParentElements[0] = this.parents[0].getNextXmlElement(ComplexElementCollection.this.parentElementNames[0], -1);
 621   
                                 }
 622   
                             }
 623   
                         }
 624   
                         
 625  0
                         private XmlList findNextParent(final int i) {
 626  0
                             if (i == this.nextParentElements.length) return null;
 627   
                             
 628  0
                             this.nextParentElements[i] = this.parents[i].getNextXmlElement(ComplexElementCollection.this.parentElementNames[i], this.nextParentElements[i]);
 629   
                             
 630  0
                             while (this.nextParentElements[i] == -1) {
 631  0
                                 this.parents[i] = findNextParent(i + 1);
 632   
                                 
 633  0
                                 if (this.parents[i] == null) {
 634  0
                                     return null;
 635   
                                 } else {
 636  0
                                     this.nextParentElements[i] = this.parents[i].getNextXmlElement(ComplexElementCollection.this.parentElementNames[i], -1);
 637   
                                 }
 638   
                             }
 639   
                         
 640  0
                             return (XmlList)this.parents[i].children[this.nextParentElements[i]];
 641   
                         }
 642   
         };
 643   
     }
 644   
 }
 645