001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: DOM2Helper.java 468655 2006-10-28 07:12:06Z minchau $
020     */
021    package org.apache.xml.utils;
022    
023    import java.io.IOException;
024    
025    import javax.xml.parsers.DocumentBuilder;
026    import javax.xml.parsers.DocumentBuilderFactory;
027    import javax.xml.parsers.ParserConfigurationException;
028    import javax.xml.transform.TransformerException;
029    
030    import org.w3c.dom.Attr;
031    import org.w3c.dom.Document;
032    import org.w3c.dom.Element;
033    import org.w3c.dom.Node;
034    
035    import org.xml.sax.InputSource;
036    
037    /**
038     * @deprecated Since the introduction of the DTM, this class will be removed.
039     * This class provides a DOM level 2 "helper", which provides services currently 
040     * not provided be the DOM standard.
041     */
042    public class DOM2Helper extends DOMHelper
043    {
044    
045      /**
046       * Construct an instance.
047       */
048      public DOM2Helper(){}
049    
050      /**
051       * Check node to see if it was created by a DOM implementation
052       * that this helper is intended to support. This is currently
053       * disabled, and assumes all nodes are acceptable rather than checking
054       * that they implement org.apache.xerces.dom.NodeImpl.
055       *
056       * @param node The node to be tested.
057       *
058       * @throws TransformerException if the node is not one which this
059       * DOM2Helper can support. If we return without throwing the exception,
060       * the node is compatable.
061       * @xsl.usage internal
062       */
063      public void checkNode(Node node) throws TransformerException
064      {
065    
066        // if(!(node instanceof org.apache.xerces.dom.NodeImpl))
067        //  throw new TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_XERCES_CANNOT_HANDLE_NODES, new Object[]{((Object)node).getClass()})); //"DOM2Helper can not handle nodes of type"
068        //+((Object)node).getClass());
069      }
070    
071      /**
072       * Returns true if the DOM implementation handled by this helper
073       * supports the SAX ContentHandler interface.
074       *
075       * @return true (since Xerces does).
076       */
077      public boolean supportsSAX()
078      {
079        return true;
080      }
081    
082      /** Field m_doc: Document Node for the document this helper is currently
083       * accessing or building
084       * @see #setDocument
085       * @see #getDocument
086       *  */
087      private Document m_doc;
088    
089      /**
090       * Specify which document this helper is currently operating on.
091       *    
092       * @param doc The DOM Document node for this document.
093       * @see #getDocument
094       */
095      public void setDocument(Document doc)
096      {
097        m_doc = doc;
098      }
099    
100      /**
101       * Query which document this helper is currently operating on.
102       *    
103       * @return The DOM Document node for this document.
104       * @see #setDocument
105       */
106      public Document getDocument()
107      {
108        return m_doc;
109      }
110    
111      /**
112       * Parse an XML document.
113       *
114       * <p>Right now the Xerces DOMParser class is used.  This needs
115       * fixing, either via jaxp, or via some other, standard method.</p>
116       *
117       * <p>The application can use this method to instruct the SAX parser
118       * to begin parsing an XML document from any valid input
119       * source (a character stream, a byte stream, or a URI).</p>
120       *
121       * <p>Applications may not invoke this method while a parse is in
122       * progress (they should create a new Parser instead for each
123       * additional XML document).  Once a parse is complete, an
124       * application may reuse the same Parser object, possibly with a
125       * different input source.</p>
126       *
127       * @param source The input source for the top-level of the
128       *        XML document.
129       *
130       * @throws TransformerException if any checked exception is thrown.
131       * @xsl.usage internal
132       */
133      public void parse(InputSource source) throws TransformerException
134      {
135    
136        try
137        {
138    
139          // I guess I should use JAXP factory here... when it's legal.
140          // org.apache.xerces.parsers.DOMParser parser 
141          //  = new org.apache.xerces.parsers.DOMParser();
142          DocumentBuilderFactory builderFactory =
143            DocumentBuilderFactory.newInstance();
144    
145          builderFactory.setNamespaceAware(true);
146          builderFactory.setValidating(true);
147    
148          DocumentBuilder parser = builderFactory.newDocumentBuilder();
149    
150          /*
151          // domParser.setFeature("http://apache.org/xml/features/dom/create-entity-ref-nodes", getShouldExpandEntityRefs()? false : true);
152          if(m_useDOM2getNamespaceURI)
153          {
154          parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", true);
155          parser.setFeature("http://xml.org/sax/features/namespaces", true);
156          }
157          else
158          {
159          parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false);
160          }
161    
162          parser.setFeature("http://apache.org/xml/features/allow-java-encodings", true);
163          */
164    
165          parser.setErrorHandler(
166            new org.apache.xml.utils.DefaultErrorHandler());
167    
168          // if(null != m_entityResolver)
169          // {
170          // System.out.println("Setting the entity resolver.");
171          //  parser.setEntityResolver(m_entityResolver);
172          // }
173          setDocument(parser.parse(source));
174        }
175        catch (org.xml.sax.SAXException se)
176        {
177          throw new TransformerException(se);
178        }
179        catch (ParserConfigurationException pce)
180        {
181          throw new TransformerException(pce);
182        }
183        catch (IOException ioe)
184        {
185          throw new TransformerException(ioe);
186        }
187    
188        // setDocument(((org.apache.xerces.parsers.DOMParser)parser).getDocument());
189      }
190    
191      /**
192       * Given an XML ID, return the element. This requires assistance from the
193       * DOM and parser, and is meaningful only in the context of a DTD 
194       * or schema which declares attributes as being of type ID. This
195       * information may or may not be available in all parsers, may or
196       * may not be available for specific documents, and may or may not
197       * be available when validation is not turned on.
198       *
199       * @param id The ID to search for, as a String.
200       * @param doc The document to search within, as a DOM Document node.
201       * @return DOM Element node with an attribute of type ID whose value
202       * uniquely matches the requested id string, or null if there isn't
203       * such an element or if the DOM can't answer the question for other
204       * reasons.
205       */
206      public Element getElementByID(String id, Document doc)
207      {
208        return doc.getElementById(id);
209      }
210    
211      /**
212       * Figure out whether node2 should be considered as being later
213       * in the document than node1, in Document Order as defined
214       * by the XPath model. This may not agree with the ordering defined
215       * by other XML applications.
216       * <p>
217       * There are some cases where ordering isn't defined, and neither are
218       * the results of this function -- though we'll generally return true.
219       * <p>
220       * TODO: Make sure this does the right thing with attribute nodes!!!
221       *
222       * @param node1 DOM Node to perform position comparison on.
223       * @param node2 DOM Node to perform position comparison on .
224       * 
225       * @return false if node2 comes before node1, otherwise return true.
226       * You can think of this as 
227       * <code>(node1.documentOrderPosition &lt;= node2.documentOrderPosition)</code>.
228       */
229      public static boolean isNodeAfter(Node node1, Node node2)
230      {
231    
232        // Assume first that the nodes are DTM nodes, since discovering node 
233        // order is massivly faster for the DTM.
234        if(node1 instanceof DOMOrder && node2 instanceof DOMOrder)
235        {
236          int index1 = ((DOMOrder) node1).getUid();
237          int index2 = ((DOMOrder) node2).getUid();
238    
239          return index1 <= index2;
240        }
241        else
242        {
243    
244          // isNodeAfter will return true if node is after countedNode 
245          // in document order. The base isNodeAfter is sloooow (relatively).
246          return DOMHelper.isNodeAfter(node1, node2);
247        }
248      }
249    
250      /**
251       * Get the XPath-model parent of a node.  This version takes advantage
252       * of the DOM Level 2 Attr.ownerElement() method; the base version we
253       * would otherwise inherit is prepared to fall back on exhaustively
254       * walking the document to find an Attr's parent.
255       *
256       * @param node Node to be examined
257       *
258       * @return the DOM parent of the input node, if there is one, or the
259       * ownerElement if the input node is an Attr, or null if the node is
260       * a Document, a DocumentFragment, or an orphan.
261       */
262      public static Node getParentOfNode(Node node)
263      {
264              Node parent=node.getParentNode();
265              if(parent==null && (Node.ATTRIBUTE_NODE == node.getNodeType()) )
266               parent=((Attr) node).getOwnerElement();
267              return parent;
268      }
269    
270      /**
271       * Returns the local name of the given node, as defined by the
272       * XML Namespaces specification. This is prepared to handle documents
273       * built using DOM Level 1 methods by falling back upon explicitly
274       * parsing the node name.
275       *
276       * @param n Node to be examined
277       *
278       * @return String containing the local name, or null if the node
279       * was not assigned a Namespace.
280       */
281      public String getLocalNameOfNode(Node n)
282      {
283    
284        String name = n.getLocalName();
285    
286        return (null == name) ? super.getLocalNameOfNode(n) : name;
287      }
288    
289      /**
290       * Returns the Namespace Name (Namespace URI) for the given node.
291       * In a Level 2 DOM, you can ask the node itself. Note, however, that
292       * doing so conflicts with our decision in getLocalNameOfNode not
293       * to trust the that the DOM was indeed created using the Level 2
294       * methods. If Level 1 methods were used, these two functions will
295       * disagree with each other.
296       * <p>
297       * TODO: Reconcile with getLocalNameOfNode.
298       *
299       * @param n Node to be examined
300       *
301       * @return String containing the Namespace URI bound to this DOM node
302       * at the time the Node was created.
303       */
304      public String getNamespaceOfNode(Node n)
305      {
306        return n.getNamespaceURI();
307      }
308    
309      /** Field m_useDOM2getNamespaceURI is a compile-time flag which
310       *  gates some of the parser options used to build a DOM -- but 
311       * that code is commented out at this time and nobody else
312       * references it, so I've commented this out as well. */
313      //private boolean m_useDOM2getNamespaceURI = false;
314    }