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 <= 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 }