Save This Page
Home » openjdk-7 » com.sun.org.apache.xerces.internal » dom » [javadoc | source]
    1   /*
    2    * reserved comment block
    3    * DO NOT REMOVE OR ALTER!
    4    */
    5   /*
    6    * Copyright 1999-2002,2004 The Apache Software Foundation.
    7    *
    8    * Licensed under the Apache License, Version 2.0 (the "License");
    9    * you may not use this file except in compliance with the License.
   10    * You may obtain a copy of the License at
   11    *
   12    *      http://www.apache.org/licenses/LICENSE-2.0
   13    *
   14    * Unless required by applicable law or agreed to in writing, software
   15    * distributed under the License is distributed on an "AS IS" BASIS,
   16    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   17    * See the License for the specific language governing permissions and
   18    * limitations under the License.
   19    */
   20   
   21   package com.sun.org.apache.xerces.internal.dom;
   22   
   23   import org.w3c.dom.Node;
   24   import org.w3c.dom.NodeList;
   25   
   26   import java.util.Vector;
   27   
   28   /**
   29    * This class implements the DOM's NodeList behavior for
   30    * Element.getElementsByTagName()
   31    * <P>
   32    * The DOM describes NodeList as follows:
   33    * <P>
   34    * 1) It may represent EITHER nodes scattered through a subtree (when
   35    * returned by Element.getElementsByTagName), or just the immediate
   36    * children (when returned by Node.getChildNodes). The latter is easy,
   37    * but the former (which this class addresses) is more challenging.
   38    * <P>
   39    * 2) Its behavior is "live" -- that is, it always reflects the
   40    * current state of the document tree. To put it another way, the
   41    * NodeLists obtained before and after a series of insertions and
   42    * deletions are effectively identical (as far as the user is
   43    * concerned, the former has been dynamically updated as the changes
   44    * have been made).
   45    * <P>
   46    * 3) Its API accesses individual nodes via an integer index, with the
   47    * listed nodes numbered sequentially in the order that they were
   48    * found during a preorder depth-first left-to-right search of the tree.
   49    * (Of course in the case of getChildNodes, depth is not involved.) As
   50    * nodes are inserted or deleted in the tree, and hence the NodeList,
   51    * the numbering of nodes that follow them in the NodeList will
   52    * change.
   53    * <P>
   54    * It is rather painful to support the latter two in the
   55    * getElementsByTagName case. The current solution is for Nodes to
   56    * maintain a change count (eventually that may be a Digest instead),
   57    * which the NodeList tracks and uses to invalidate itself.
   58    * <P>
   59    * Unfortunately, this does _not_ respond efficiently in the case that
   60    * the dynamic behavior was supposed to address: scanning a tree while
   61    * it is being extended. That requires knowing which subtrees have
   62    * changed, which can become an arbitrarily complex problem.
   63    * <P>
   64    * We save some work by filling the vector only as we access the
   65    * item()s... but I suspect the same users who demanded index-based
   66    * access will also start by doing a getLength() to control their loop,
   67    * blowing this optimization out of the water.
   68    * <P>
   69    * NOTE: Level 2 of the DOM will probably _not_ use NodeList for its
   70    * extended search mechanisms, partly for the reasons just discussed.
   71    *
   72    * @xerces.internal
   73    *
   74    * @since  PR-DOM-Level-1-19980818.
   75    */
   76   public class DeepNodeListImpl
   77       implements NodeList {
   78   
   79       //
   80       // Data
   81       //
   82   
   83       protected NodeImpl rootNode; // Where the search started
   84       protected String tagName;   // Or "*" to mean all-tags-acceptable
   85       protected int changes=0;
   86       protected Vector nodes;
   87   
   88       protected String nsName;
   89       protected boolean enableNS = false;
   90   
   91       //
   92       // Constructors
   93       //
   94   
   95       /** Constructor. */
   96       public DeepNodeListImpl(NodeImpl rootNode, String tagName) {
   97           this.rootNode = rootNode;
   98           this.tagName  = tagName;
   99           nodes = new Vector();
  100       }
  101   
  102       /** Constructor for Namespace support. */
  103       public DeepNodeListImpl(NodeImpl rootNode,
  104                               String nsName, String tagName) {
  105           this(rootNode, tagName);
  106           this.nsName = (nsName != null && !nsName.equals("")) ? nsName : null;
  107           enableNS = true;
  108       }
  109   
  110       //
  111       // NodeList methods
  112       //
  113   
  114       /** Returns the length of the node list. */
  115       public int getLength() {
  116           // Preload all matching elements. (Stops when we run out of subtree!)
  117           item(java.lang.Integer.MAX_VALUE);
  118           return nodes.size();
  119       }
  120   
  121       /** Returns the node at the specified index. */
  122       public Node item(int index) {
  123           Node thisNode;
  124   
  125           // Tree changed. Do it all from scratch!
  126           if(rootNode.changes() != changes) {
  127               nodes   = new Vector();
  128               changes = rootNode.changes();
  129           }
  130   
  131           // In the cache
  132           if (index < nodes.size())
  133               return (Node)nodes.elementAt(index);
  134   
  135           // Not yet seen
  136           else {
  137   
  138               // Pick up where we left off (Which may be the beginning)
  139                   if (nodes.size() == 0)
  140                       thisNode = rootNode;
  141                   else
  142                       thisNode=(NodeImpl)(nodes.lastElement());
  143   
  144                   // Add nodes up to the one we're looking for
  145                   while(thisNode != null && index >= nodes.size()) {
  146                           thisNode=nextMatchingElementAfter(thisNode);
  147                           if (thisNode != null)
  148                               nodes.addElement(thisNode);
  149                       }
  150   
  151               // Either what we want, or null (not avail.)
  152                       return thisNode;
  153               }
  154   
  155       } // item(int):Node
  156   
  157       //
  158       // Protected methods (might be overridden by an extending DOM)
  159       //
  160   
  161       /**
  162        * Iterative tree-walker. When you have a Parent link, there's often no
  163        * need to resort to recursion. NOTE THAT only Element nodes are matched
  164        * since we're specifically supporting getElementsByTagName().
  165        */
  166       protected Node nextMatchingElementAfter(Node current) {
  167   
  168               Node next;
  169               while (current != null) {
  170                       // Look down to first child.
  171                       if (current.hasChildNodes()) {
  172                               current = (current.getFirstChild());
  173                       }
  174   
  175                       // Look right to sibling (but not from root!)
  176                       else if (current != rootNode && null != (next = current.getNextSibling())) {
  177                                   current = next;
  178                           }
  179   
  180                           // Look up and right (but not past root!)
  181                           else {
  182                                   next = null;
  183                                   for (; current != rootNode; // Stop when we return to starting point
  184                                           current = current.getParentNode()) {
  185   
  186                                           next = current.getNextSibling();
  187                                           if (next != null)
  188                                                   break;
  189                                   }
  190                                   current = next;
  191                           }
  192   
  193                           // Have we found an Element with the right tagName?
  194                           // ("*" matches anything.)
  195                       if (current != rootNode
  196                           && current != null
  197                           && current.getNodeType() ==  Node.ELEMENT_NODE) {
  198                           if (!enableNS) {
  199                               if (tagName.equals("*") ||
  200                                   ((ElementImpl) current).getTagName().equals(tagName))
  201                               {
  202                                   return current;
  203                               }
  204                           } else {
  205                               // DOM2: Namespace logic.
  206                               if (tagName.equals("*")) {
  207                                   if (nsName != null && nsName.equals("*")) {
  208                                       return current;
  209                                   } else {
  210                                       ElementImpl el = (ElementImpl) current;
  211                                       if ((nsName == null
  212                                            && el.getNamespaceURI() == null)
  213                                           || (nsName != null
  214                                               && nsName.equals(el.getNamespaceURI())))
  215                                       {
  216                                           return current;
  217                                       }
  218                                   }
  219                               } else {
  220                                   ElementImpl el = (ElementImpl) current;
  221                                   if (el.getLocalName() != null
  222                                       && el.getLocalName().equals(tagName)) {
  223                                       if (nsName != null && nsName.equals("*")) {
  224                                           return current;
  225                                       } else {
  226                                           if ((nsName == null
  227                                                && el.getNamespaceURI() == null)
  228                                               || (nsName != null &&
  229                                                   nsName.equals(el.getNamespaceURI())))
  230                                           {
  231                                               return current;
  232                                           }
  233                                       }
  234                                   }
  235                               }
  236                           }
  237                       }
  238   
  239                   // Otherwise continue walking the tree
  240               }
  241   
  242               // Fell out of tree-walk; no more instances found
  243               return null;
  244   
  245       } // nextMatchingElementAfter(int):Node
  246   
  247   } // class DeepNodeListImpl

Save This Page
Home » openjdk-7 » com.sun.org.apache.xerces.internal » dom » [javadoc | source]