< prev index next >

src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/DOM2Helper.java

Print this page


   1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xml.internal.utils;
  23 
  24 import java.io.IOException;
  25 
  26 import javax.xml.parsers.DocumentBuilder;
  27 import javax.xml.parsers.DocumentBuilderFactory;
  28 import javax.xml.parsers.ParserConfigurationException;
  29 import javax.xml.transform.TransformerException;
  30 
  31 import org.w3c.dom.Attr;
  32 import org.w3c.dom.Document;
  33 import org.w3c.dom.Element;
  34 import org.w3c.dom.Node;
  35 
  36 import org.xml.sax.InputSource;
  37 
  38 /**
  39  * @deprecated Since the introduction of the DTM, this class will be removed.
  40  * This class provides a DOM level 2 "helper", which provides services currently
  41  * not provided be the DOM standard.
  42  */
  43 public class DOM2Helper extends DOMHelper
  44 {
  45 
  46   /**
  47    * Construct an instance.
  48    */
  49   public DOM2Helper(){}

  50 
  51   /**
  52    * Check node to see if it was created by a DOM implementation
  53    * that this helper is intended to support. This is currently
  54    * disabled, and assumes all nodes are acceptable rather than checking
  55    * that they implement com.sun.org.apache.xerces.internal.dom.NodeImpl.
  56    *
  57    * @param node The node to be tested.
  58    *
  59    * @throws TransformerException if the node is not one which this
  60    * DOM2Helper can support. If we return without throwing the exception,
  61    * the node is compatable.
  62    * @xsl.usage internal
  63    */
  64   public void checkNode(Node node) throws TransformerException
  65   {

  66 
  67     // if(!(node instanceof com.sun.org.apache.xerces.internal.dom.NodeImpl))
  68     //  throw new TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_XERCES_CANNOT_HANDLE_NODES, new Object[]{((Object)node).getClass()})); //"DOM2Helper can not handle nodes of type"
  69     //+((Object)node).getClass());
  70   }
  71 
  72   /**
  73    * Returns true if the DOM implementation handled by this helper
  74    * supports the SAX ContentHandler interface.

  75    *
  76    * @return true (since Xerces does).





  77    */
  78   public boolean supportsSAX()
  79   {
  80     return true;
  81   }
  82 
  83   /** Field m_doc: Document Node for the document this helper is currently
  84    * accessing or building
  85    * @see #setDocument
  86    * @see #getDocument
  87    *  */
  88   private Document m_doc;
  89 
  90   /**
  91    * Specify which document this helper is currently operating on.
  92    *
  93    * @param doc The DOM Document node for this document.
  94    * @see #getDocument
  95    */
  96   public void setDocument(Document doc)
  97   {
  98     m_doc = doc;
  99   }
 100 
 101   /**
 102    * Query which document this helper is currently operating on.








 103    *
 104    * @return The DOM Document node for this document.
 105    * @see #setDocument
 106    */
 107   public Document getDocument()
 108   {
 109     return m_doc;
 110   }
 111 
 112   /**
 113    * Parse an XML document.
 114    *
 115    * <p>Right now the Xerces DOMParser class is used.  This needs
 116    * fixing, either via jaxp, or via some other, standard method.</p>
 117    *
 118    * <p>The application can use this method to instruct the SAX parser
 119    * to begin parsing an XML document from any valid input
 120    * source (a character stream, a byte stream, or a URI).</p>
 121    *
 122    * <p>Applications may not invoke this method while a parse is in
 123    * progress (they should create a new Parser instead for each
 124    * additional XML document).  Once a parse is complete, an
 125    * application may reuse the same Parser object, possibly with a
 126    * different input source.</p>
 127    *
 128    * @param source The input source for the top-level of the
 129    *        XML document.
 130    *
 131    * @throws TransformerException if any checked exception is thrown.
 132    * @xsl.usage internal

 133    */
 134   public void parse(InputSource source) throws TransformerException
 135   {


 136 
 137     try
 138     {
 139 
 140       // I guess I should use JAXP factory here... when it's legal.
 141       // com.sun.org.apache.xerces.internal.parsers.DOMParser parser
 142       //  = new com.sun.org.apache.xerces.internal.parsers.DOMParser();
 143       DocumentBuilderFactory builderFactory =
 144         DocumentBuilderFactory.newInstance();
 145 
 146       builderFactory.setNamespaceAware(true);
 147       builderFactory.setValidating(true);
 148 
 149       DocumentBuilder parser = builderFactory.newDocumentBuilder();
 150 
 151       /*
 152       // domParser.setFeature("http://apache.org/xml/features/dom/create-entity-ref-nodes", getShouldExpandEntityRefs()? false : true);
 153       if(m_useDOM2getNamespaceURI)
 154       {
 155       parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", true);
 156       parser.setFeature("http://xml.org/sax/features/namespaces", true);
 157       }
 158       else
 159       {
 160       parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false);

 161       }











 162 
 163       parser.setFeature("http://apache.org/xml/features/allow-java-encodings", true);
 164       */
 165 
 166       parser.setErrorHandler(
 167         new com.sun.org.apache.xml.internal.utils.DefaultErrorHandler());
 168 
 169       // if(null != m_entityResolver)
 170       // {
 171       // System.out.println("Setting the entity resolver.");
 172       //  parser.setEntityResolver(m_entityResolver);
 173       // }
 174       setDocument(parser.parse(source));
 175     }
 176     catch (org.xml.sax.SAXException se)
 177     {
 178       throw new TransformerException(se);










 179     }
 180     catch (ParserConfigurationException pce)
 181     {
 182       throw new TransformerException(pce);



 183     }
 184     catch (IOException ioe)
 185     {
 186       throw new TransformerException(ioe);
 187     }
 188 
 189     // setDocument(((com.sun.org.apache.xerces.internal.parsers.DOMParser)parser).getDocument());
 190   }
 191 
 192   /**
 193    * Given an XML ID, return the element. This requires assistance from the
 194    * DOM and parser, and is meaningful only in the context of a DTD
 195    * or schema which declares attributes as being of type ID. This
 196    * information may or may not be available in all parsers, may or
 197    * may not be available for specific documents, and may or may not
 198    * be available when validation is not turned on.
 199    *
 200    * @param id The ID to search for, as a String.
 201    * @param doc The document to search within, as a DOM Document node.
 202    * @return DOM Element node with an attribute of type ID whose value
 203    * uniquely matches the requested id string, or null if there isn't
 204    * such an element or if the DOM can't answer the question for other
 205    * reasons.
 206    */
 207   public Element getElementByID(String id, Document doc)
 208   {
 209     return doc.getElementById(id);
 210   }
 211 
 212   /**
 213    * Figure out whether node2 should be considered as being later
 214    * in the document than node1, in Document Order as defined
 215    * by the XPath model. This may not agree with the ordering defined
 216    * by other XML applications.
 217    * <p>
 218    * There are some cases where ordering isn't defined, and neither are
 219    * the results of this function -- though we'll generally return true.
 220    * <p>
 221    * TODO: Make sure this does the right thing with attribute nodes!!!
 222    *
 223    * @param node1 DOM Node to perform position comparison on.
 224    * @param node2 DOM Node to perform position comparison on .
 225    *
 226    * @return false if node2 comes before node1, otherwise return true.
 227    * You can think of this as
 228    * <code>(node1.documentOrderPosition &lt;= node2.documentOrderPosition)</code>.
 229    */
 230   public static boolean isNodeAfter(Node node1, Node node2)
 231   {
 232 
 233     // Assume first that the nodes are DTM nodes, since discovering node
 234     // order is massivly faster for the DTM.
 235     if(node1 instanceof DOMOrder && node2 instanceof DOMOrder)
 236     {
 237       int index1 = ((DOMOrder) node1).getUid();
 238       int index2 = ((DOMOrder) node2).getUid();
 239 
 240       return index1 <= index2;






 241     }
 242     else
 243     {
 244 
 245       // isNodeAfter will return true if node is after countedNode
 246       // in document order. The base isNodeAfter is sloooow (relatively).
 247       return DOMHelper.isNodeAfter(node1, node2);




















 248     }
 249   }
 250 
 251   /**
 252    * Get the XPath-model parent of a node.  This version takes advantage
 253    * of the DOM Level 2 Attr.ownerElement() method; the base version we
 254    * would otherwise inherit is prepared to fall back on exhaustively
 255    * walking the document to find an Attr's parent.
 256    *
 257    * @param node Node to be examined
 258    *
 259    * @return the DOM parent of the input node, if there is one, or the
 260    * ownerElement if the input node is an Attr, or null if the node is
 261    * a Document, a DocumentFragment, or an orphan.
 262    */
 263   public static Node getParentOfNode(Node node)
 264   {
 265           Node parent=node.getParentNode();
 266           if(parent==null && (Node.ATTRIBUTE_NODE == node.getNodeType()) )
 267            parent=((Attr) node).getOwnerElement();
 268           return parent;
 269   }
 270 
 271   /**
 272    * Returns the local name of the given node, as defined by the
 273    * XML Namespaces specification. This is prepared to handle documents
 274    * built using DOM Level 1 methods by falling back upon explicitly
 275    * parsing the node name.
 276    *
 277    * @param n Node to be examined

 278    *
 279    * @return String containing the local name, or null if the node
 280    * was not assigned a Namespace.


 281    */
 282   public String getLocalNameOfNode(Node n)
 283   {
 284 
 285     String name = n.getLocalName();





















 286 
 287     return (null == name) ? super.getLocalNameOfNode(n) : name;




 288   }
 289 
 290   /**
 291    * Returns the Namespace Name (Namespace URI) for the given node.
 292    * In a Level 2 DOM, you can ask the node itself. Note, however, that
 293    * doing so conflicts with our decision in getLocalNameOfNode not
 294    * to trust the that the DOM was indeed created using the Level 2
 295    * methods. If Level 1 methods were used, these two functions will
 296    * disagree with each other.
 297    * <p>
 298    * TODO: Reconcile with getLocalNameOfNode.
 299    *
 300    * @param n Node to be examined
 301    *
 302    * @return String containing the Namespace URI bound to this DOM node
 303    * at the time the Node was created.
 304    */
 305   public String getNamespaceOfNode(Node n)
 306   {
 307     return n.getNamespaceURI();































 308   }
 309 
 310   /** Field m_useDOM2getNamespaceURI is a compile-time flag which
 311    *  gates some of the parser options used to build a DOM -- but
 312    * that code is commented out at this time and nobody else
 313    * references it, so I've commented this out as well. */
 314   //private boolean m_useDOM2getNamespaceURI = false;
 315 }
   1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.

   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  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 package com.sun.org.apache.xml.internal.utils;
  21 
  22 import com.sun.org.apache.xml.internal.dtm.ref.DTMNodeProxy;






  23 import org.w3c.dom.Attr;
  24 import org.w3c.dom.NamedNodeMap;

  25 import org.w3c.dom.Node;
  26 

  27 
  28 /**
  29  * This class provides a DOM level 2 "helper", which provides several services.
  30  *
  31  * The original class extended DOMHelper that was deprecated and then removed.
  32  */
  33 public final class DOM2Helper {

  34 
  35     /**
  36      * Construct an instance.
  37      */
  38     private DOM2Helper() {
  39     }
  40 
  41     /**
  42      * Returns the local name of the given node, as defined by the XML
  43      * Namespaces specification. This is prepared to handle documents built
  44      * using DOM Level 1 methods by falling back upon explicitly parsing the
  45      * node name.
  46      *
  47      * @param n Node to be examined
  48      *
  49      * @return String containing the local name, or null if the node was not
  50      * assigned a Namespace.


  51      */
  52     public static String getLocalNameOfNode(Node n) {
  53 
  54         String name = n.getLocalName();
  55 
  56         return (null == name) ? getLocalNameOfNodeFallback(n) : name;


  57     }
  58 
  59     /**
  60      * Returns the local name of the given node. If the node's name begins with
  61      * a namespace prefix, this is the part after the colon; otherwise it's the
  62      * full node name.
  63      *
  64      * This method is copied from
  65      * com.sun.org.apache.xml.internal.utils.DOMHelper
  66      *
  67      * @param n the node to be examined.
  68      *
  69      * @return String containing the Local Name
  70      */
  71     private static String getLocalNameOfNodeFallback(Node n) {



  72 
  73         String qname = n.getNodeName();
  74         int index = qname.indexOf(':');




  75 
  76         return (index < 0) ? qname : qname.substring(index + 1);








  77     }
  78 
  79     /**
  80      * Returns the Namespace Name (Namespace URI) for the given node. In a Level
  81      * 2 DOM, you can ask the node itself. Note, however, that doing so
  82      * conflicts with our decision in getLocalNameOfNode not to trust the that
  83      * the DOM was indeed created using the Level 2 methods. If Level 1 methods
  84      * were used, these two functions will disagree with each other.
  85      * <p>
  86      * TODO: Reconcile with getLocalNameOfNode.
  87      *
  88      * @param n Node to be examined
  89      *
  90      * @return String containing the Namespace URI bound to this DOM node at the
  91      * time the Node was created.
  92      */
  93     public static String getNamespaceOfNode(Node n) {
  94         return n.getNamespaceURI();

  95     }
  96 
  97     /**
  98      * Figure out whether node2 should be considered as being later in the
  99      * document than node1, in Document Order as defined by the XPath model.
 100      * This may not agree with the ordering defined by other XML applications.
 101      * <p>
 102      * There are some cases where ordering isn't defined, and neither are the
 103      * results of this function -- though we'll generally return true.








 104      *
 105      * @param node1 DOM Node to perform position comparison on.
 106      * @param node2 DOM Node to perform position comparison on .
 107      *
 108      * @return false if node2 comes before node1, otherwise return true. You can
 109      * think of this as
 110      * {@code (node1.documentOrderPosition &lt;= node2.documentOrderPosition)}.
 111      */
 112     public static boolean isNodeAfter(Node node1, Node node2) {
 113         if (node1 == node2 || isNodeTheSame(node1, node2)) {
 114             return true;
 115         }
 116 
 117         // Default return value, if there is no defined ordering
 118         boolean isNodeAfter = true;
 119 
 120         Node parent1 = getParentOfNode(node1);
 121         Node parent2 = getParentOfNode(node2);
 122 
 123         // Optimize for most common case
 124         if (parent1 == parent2 || isNodeTheSame(parent1, parent2)) // then we know they are siblings














 125         {
 126             if (null != parent1) {
 127                 isNodeAfter = isNodeAfterSibling(parent1, node1, node2);
 128             }
 129         } else {
 130             // General strategy: Figure out the lengths of the two
 131             // ancestor chains, reconcile the lengths, and look for
 132             // the lowest common ancestor. If that ancestor is one of
 133             // the nodes being compared, it comes before the other.
 134             // Otherwise perform a sibling compare.
 135             //
 136             // NOTE: If no common ancestor is found, ordering is undefined
 137             // and we return the default value of isNodeAfter.
 138             // Count parents in each ancestor chain
 139             int nParents1 = 2, nParents2 = 2;  // include node & parent obtained above
 140 
 141             while (parent1 != null) {
 142                 nParents1++;
 143 
 144                 parent1 = getParentOfNode(parent1);
 145             }
 146 
 147             while (parent2 != null) {
 148                 nParents2++;
 149 
 150                 parent2 = getParentOfNode(parent2);


 151             }
 152 
 153             // Initially assume scan for common ancestor starts with
 154             // the input nodes.
 155             Node startNode1 = node1, startNode2 = node2;
 156 
 157             // If one ancestor chain is longer, adjust its start point
 158             // so we're comparing at the same depths
 159             if (nParents1 < nParents2) {
 160                 // Adjust startNode2 to depth of startNode1
 161                 int adjust = nParents2 - nParents1;
 162 
 163                 for (int i = 0; i < adjust; i++) {
 164                     startNode2 = getParentOfNode(startNode2);
 165                 }
 166             } else if (nParents1 > nParents2) {
 167                 // adjust startNode1 to depth of startNode2
 168                 int adjust = nParents1 - nParents2;
 169 
 170                 for (int i = 0; i < adjust; i++) {
 171                     startNode1 = getParentOfNode(startNode1);
 172                 }



 173             }
 174 
 175             Node prevChild1 = null, prevChild2 = null;  // so we can "back up"

 176 
 177             // Loop up the ancestor chain looking for common parent
 178             while (null != startNode1) {
 179                 if (startNode1 == startNode2 || isNodeTheSame(startNode1, startNode2)) // common parent?













 180                 {
 181                     if (null == prevChild1) // first time in loop?





















 182                     {
 183 
 184                         // Edge condition: one is the ancestor of the other.
 185                         isNodeAfter = (nParents1 < nParents2) ? true : false;




 186 
 187                         break;  // from while loop
 188                     } else {
 189                         // Compare ancestors below lowest-common as siblings
 190                         isNodeAfter = isNodeAfterSibling(startNode1, prevChild1,
 191                                 prevChild2);
 192 
 193                         break;  // from while loop
 194                     }
 195                 }  // end if(startNode1 == startNode2)

 196 
 197                 // Move up one level and try again
 198                 prevChild1 = startNode1;
 199                 startNode1 = getParentOfNode(startNode1);
 200                 prevChild2 = startNode2;
 201                 startNode2 = getParentOfNode(startNode2);
 202             }  // end while(parents exist to examine)
 203         }  // end big else (not immediate siblings)
 204 
 205         return isNodeAfter;
 206     }  // end isNodeAfter(Node node1, Node node2)
 207 
 208     /**
 209      * Use DTMNodeProxy to determine whether two nodes are the same.
 210      *
 211      * @param node1 The first DOM node to compare.
 212      * @param node2 The second DOM node to compare.
 213      * @return true if the two nodes are the same.
 214      */
 215     public static boolean isNodeTheSame(Node node1, Node node2) {
 216         if (node1 instanceof DTMNodeProxy && node2 instanceof DTMNodeProxy) {
 217             return ((DTMNodeProxy) node1).equals((DTMNodeProxy) node2);
 218         } else {
 219             return (node1 == node2);
 220         }
 221     }
 222 
 223     /**
 224      * Get the XPath-model parent of a node. This version takes advantage of the
 225      * DOM Level 2 Attr.ownerElement() method; the base version we would
 226      * otherwise inherit is prepared to fall back on exhaustively walking the
 227      * document to find an Attr's parent.
 228      *
 229      * @param node Node to be examined
 230      *
 231      * @return the DOM parent of the input node, if there is one, or the
 232      * ownerElement if the input node is an Attr, or null if the node is a
 233      * Document, a DocumentFragment, or an orphan.
 234      */
 235     public static Node getParentOfNode(Node node) {
 236         Node parent = node.getParentNode();
 237         if (parent == null && (Node.ATTRIBUTE_NODE == node.getNodeType())) {
 238             parent = ((Attr) node).getOwnerElement();
 239         }
 240         return parent;
 241     }
 242 
 243     /**
 244      * Figure out if child2 is after child1 in document order.
 245      * <p>
 246      * Warning: Some aspects of "document order" are not well defined. For
 247      * example, the order of attributes is considered meaningless in XML, and
 248      * the order reported by our model will be consistent for a given invocation
 249      * but may not match that of either the source file or the serialized
 250      * output.
 251      *
 252      * @param parent Must be the parent of both child1 and child2.
 253      * @param child1 Must be the child of parent and not equal to child2.
 254      * @param child2 Must be the child of parent and not equal to child1.
 255      * @return true if child 2 is after child1 in document order.
 256      */
 257     private static boolean isNodeAfterSibling(Node parent, Node child1,
 258             Node child2) {
 259 
 260         boolean isNodeAfterSibling = false;
 261         short child1type = child1.getNodeType();
 262         short child2type = child2.getNodeType();
 263 
 264         if ((Node.ATTRIBUTE_NODE != child1type)
 265                 && (Node.ATTRIBUTE_NODE == child2type)) {
 266 
 267             // always sort attributes before non-attributes.
 268             isNodeAfterSibling = false;
 269         } else if ((Node.ATTRIBUTE_NODE == child1type)
 270                 && (Node.ATTRIBUTE_NODE != child2type)) {
 271 
 272             // always sort attributes before non-attributes.
 273             isNodeAfterSibling = true;
 274         } else if (Node.ATTRIBUTE_NODE == child1type) {
 275             NamedNodeMap children = parent.getAttributes();
 276             int nNodes = children.getLength();
 277             boolean found1 = false, found2 = false;
 278 
 279             // Count from the start until we find one or the other.
 280             for (int i = 0; i < nNodes; i++) {
 281                 Node child = children.item(i);
 282 
 283                 if (child1 == child || isNodeTheSame(child1, child)) {
 284                     if (found2) {
 285                         isNodeAfterSibling = false;
 286 
 287                         break;
 288                     }
 289 
 290                     found1 = true;
 291                 } else if (child2 == child || isNodeTheSame(child2, child)) {
 292                     if (found1) {
 293                         isNodeAfterSibling = true;
 294 
 295                         break;
 296                     }
 297 
 298                     found2 = true;
 299                 }
 300             }
 301         } else {
 302             // TODO: Check performance of alternate solution:
 303             // There are two choices here: Count from the start of
 304             // the document until we find one or the other, or count
 305             // from one until we find or fail to find the other.
 306             // Either can wind up scanning all the siblings in the worst
 307             // case, which on a wide document can be a lot of work but
 308             // is more typically is a short list.
 309             // Scanning from the start involves two tests per iteration,
 310             // but it isn't clear that scanning from the middle doesn't
 311             // yield more iterations on average.
 312             // We should run some testcases.
 313             Node child = parent.getFirstChild();
 314             boolean found1 = false, found2 = false;
 315 
 316             while (null != child) {
 317 
 318                 // Node child = children.item(i);
 319                 if (child1 == child || isNodeTheSame(child1, child)) {
 320                     if (found2) {
 321                         isNodeAfterSibling = false;
 322 
 323                         break;
 324                     }
 325 
 326                     found1 = true;
 327                 } else if (child2 == child || isNodeTheSame(child2, child)) {
 328                     if (found1) {
 329                         isNodeAfterSibling = true;
 330 
 331                         break;
 332                     }
 333 
 334                     found2 = true;
 335                 }
 336 
 337                 child = child.getNextSibling();
 338             }
 339         }
 340 
 341         return isNodeAfterSibling;
 342     }  // end isNodeAfterSibling(Node parent, Node child1, Node child2)



 343 }
< prev index next >