1 package org.jaxen.dom4j;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 import java.util.ArrayList;
52 import java.util.HashSet;
53 import java.util.Iterator;
54 import java.util.List;
55
56 import org.dom4j.Attribute;
57 import org.dom4j.Branch;
58 import org.dom4j.CDATA;
59 import org.dom4j.Comment;
60 import org.dom4j.Document;
61 import org.dom4j.DocumentException;
62 import org.dom4j.Element;
63 import org.dom4j.Namespace;
64 import org.dom4j.Node;
65 import org.dom4j.ProcessingInstruction;
66 import org.dom4j.QName;
67 import org.dom4j.Text;
68 import org.dom4j.io.SAXReader;
69 import org.jaxen.DefaultNavigator;
70 import org.jaxen.FunctionCallException;
71 import org.jaxen.NamedAccessNavigator;
72 import org.jaxen.Navigator;
73 import org.jaxen.XPath;
74 import org.jaxen.JaxenConstants;
75 import org.jaxen.saxpath.SAXPathException;
76 import org.jaxen.util.SingleObjectIterator;
77
78 /***
79 * Interface for navigating around the DOM4J object model.
80 *
81 * <p>
82 * This class is not intended for direct usage, but is
83 * used by the Jaxen engine during evaluation.
84 * </p>
85 *
86 * @see XPath
87 *
88 * @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
89 * @author Stephen Colebourne
90 */
91 public class DocumentNavigator extends DefaultNavigator implements NamedAccessNavigator
92 {
93
94 /***
95 *
96 */
97 private static final long serialVersionUID = 5582300797286535936L;
98 private transient SAXReader reader;
99
100 /*** Singleton implementation.
101 */
102 private static class Singleton
103 {
104 /*** Singleton instance.
105 */
106 private static DocumentNavigator instance = new DocumentNavigator();
107 }
108
109 /*** Retrieve the singleton instance of this <code>DocumentNavigator</code>.
110 */
111 public static Navigator getInstance()
112 {
113 return Singleton.instance;
114 }
115
116 public boolean isElement(Object obj)
117 {
118 return obj instanceof Element;
119 }
120
121 public boolean isComment(Object obj)
122 {
123 return obj instanceof Comment;
124 }
125
126 public boolean isText(Object obj)
127 {
128 return ( obj instanceof Text
129 ||
130 obj instanceof CDATA );
131 }
132
133 public boolean isAttribute(Object obj)
134 {
135 return obj instanceof Attribute;
136 }
137
138 public boolean isProcessingInstruction(Object obj)
139 {
140 return obj instanceof ProcessingInstruction;
141 }
142
143 public boolean isDocument(Object obj)
144 {
145 return obj instanceof Document;
146 }
147
148 public boolean isNamespace(Object obj)
149 {
150 return obj instanceof Namespace;
151 }
152
153 public String getElementName(Object obj)
154 {
155 Element elem = (Element) obj;
156
157 return elem.getName();
158 }
159
160 public String getElementNamespaceUri(Object obj)
161 {
162 Element elem = (Element) obj;
163
164 String uri = elem.getNamespaceURI();
165 if ( uri == null)
166 return "";
167 else
168 return uri;
169 }
170
171 public String getElementQName(Object obj)
172 {
173 Element elem = (Element) obj;
174
175 return elem.getQualifiedName();
176 }
177
178 public String getAttributeName(Object obj)
179 {
180 Attribute attr = (Attribute) obj;
181
182 return attr.getName();
183 }
184
185 public String getAttributeNamespaceUri(Object obj)
186 {
187 Attribute attr = (Attribute) obj;
188
189 String uri = attr.getNamespaceURI();
190 if ( uri == null)
191 return "";
192 else
193 return uri;
194 }
195
196 public String getAttributeQName(Object obj)
197 {
198 Attribute attr = (Attribute) obj;
199
200 return attr.getQualifiedName();
201 }
202
203 public Iterator getChildAxisIterator(Object contextNode)
204 {
205 Iterator result = null;
206 if ( contextNode instanceof Branch )
207 {
208 Branch node = (Branch) contextNode;
209 result = node.nodeIterator();
210 }
211 if (result != null) {
212 return result;
213 }
214 return JaxenConstants.EMPTY_ITERATOR;
215 }
216
217 /***
218 * Retrieves an <code>Iterator</code> over the child elements that
219 * match the supplied name.
220 *
221 * @param contextNode the origin context node
222 * @param localName the local name of the children to return, always present
223 * @param namespacePrefix the prefix of the namespace of the children to return
224 * @param namespaceURI the uri of the namespace of the children to return
225 *
226 * @return an Iterator that traverses the named children, or null if none
227 */
228 public Iterator getChildAxisIterator(
229 Object contextNode, String localName, String namespacePrefix, String namespaceURI) {
230
231 if ( contextNode instanceof Element ) {
232 Element node = (Element) contextNode;
233 return node.elementIterator(QName.get(localName, namespacePrefix, namespaceURI));
234 }
235 if ( contextNode instanceof Document ) {
236 Document node = (Document) contextNode;
237 Element el = node.getRootElement();
238 if (el == null || el.getName().equals(localName) == false) {
239 return JaxenConstants.EMPTY_ITERATOR;
240 }
241 if (namespaceURI != null) {
242 if (namespaceURI.equals(el.getNamespaceURI()) == false) {
243 return JaxenConstants.EMPTY_ITERATOR;
244 }
245 }
246 return new SingleObjectIterator(el);
247 }
248
249 return JaxenConstants.EMPTY_ITERATOR;
250 }
251
252 public Iterator getParentAxisIterator(Object contextNode)
253 {
254 if ( contextNode instanceof Document )
255 {
256 return JaxenConstants.EMPTY_ITERATOR;
257 }
258
259 Node node = (Node) contextNode;
260
261 Object parent = node.getParent();
262
263 if ( parent == null )
264 {
265 parent = node.getDocument();
266 }
267
268 return new SingleObjectIterator( parent );
269 }
270
271 public Iterator getAttributeAxisIterator(Object contextNode)
272 {
273 if ( ! ( contextNode instanceof Element ) )
274 {
275 return JaxenConstants.EMPTY_ITERATOR;
276 }
277
278 Element elem = (Element) contextNode;
279
280 return elem.attributeIterator();
281 }
282
283 /***
284 * Retrieves an <code>Iterator</code> over the attribute elements that
285 * match the supplied name.
286 *
287 * @param contextNode the origin context node
288 * @param localName the local name of the attributes to return, always present
289 * @param namespacePrefix the prefix of the namespace of the attributes to return
290 * @param namespaceURI the URI of the namespace of the attributes to return
291 * @return an Iterator that traverses the named attributes, not null
292 */
293 public Iterator getAttributeAxisIterator(
294 Object contextNode, String localName, String namespacePrefix, String namespaceURI) {
295
296 if ( contextNode instanceof Element ) {
297 Element node = (Element) contextNode;
298 Attribute attr = node.attribute(QName.get(localName, namespacePrefix, namespaceURI));
299 if (attr == null) {
300 return JaxenConstants.EMPTY_ITERATOR;
301 }
302 return new SingleObjectIterator(attr);
303 }
304 return JaxenConstants.EMPTY_ITERATOR;
305 }
306
307 public Iterator getNamespaceAxisIterator(Object contextNode)
308 {
309 if ( ! ( contextNode instanceof Element ) )
310 {
311 return JaxenConstants.EMPTY_ITERATOR;
312 }
313
314 Element element = (Element) contextNode;
315 List nsList = new ArrayList();
316 HashSet prefixes = new HashSet();
317 for ( Element context = element; context != null; context = context.getParent() ) {
318 List declaredNS = new ArrayList(context.declaredNamespaces());
319 declaredNS.add(context.getNamespace());
320
321 for ( Iterator iter = context.attributes().iterator(); iter.hasNext(); )
322 {
323 Attribute attr = (Attribute) iter.next();
324 declaredNS.add(attr.getNamespace());
325 }
326
327 for ( Iterator iter = declaredNS.iterator(); iter.hasNext(); )
328 {
329 Namespace namespace = (Namespace) iter.next();
330 if (namespace != Namespace.NO_NAMESPACE)
331 {
332 String prefix = namespace.getPrefix();
333 if ( ! prefixes.contains( prefix ) ) {
334 prefixes.add( prefix );
335 nsList.add( namespace.asXPathResult( element ) );
336 }
337 }
338 }
339 }
340 nsList.add( Namespace.XML_NAMESPACE.asXPathResult( element ) );
341 return nsList.iterator();
342 }
343
344 public Object getDocumentNode(Object contextNode)
345 {
346 if ( contextNode instanceof Document )
347 {
348 return contextNode;
349 }
350 else if ( contextNode instanceof Node )
351 {
352 Node node = (Node) contextNode;
353 return node.getDocument();
354 }
355 return null;
356 }
357
358 /*** Returns a parsed form of the given XPath string, which will be suitable
359 * for queries on DOM4J documents.
360 */
361 public XPath parseXPath (String xpath) throws SAXPathException
362 {
363 return new Dom4jXPath(xpath);
364 }
365
366 public Object getParentNode(Object contextNode)
367 {
368 if ( contextNode instanceof Node )
369 {
370 Node node = (Node) contextNode;
371 Object answer = node.getParent();
372 if ( answer == null )
373 {
374 answer = node.getDocument();
375 if (answer == contextNode) {
376 return null;
377 }
378 }
379 return answer;
380 }
381 return null;
382 }
383
384 public String getTextStringValue(Object obj)
385 {
386 return getNodeStringValue( (Node) obj );
387 }
388
389 public String getElementStringValue(Object obj)
390 {
391 return getNodeStringValue( (Node) obj );
392 }
393
394 public String getAttributeStringValue(Object obj)
395 {
396 return getNodeStringValue( (Node) obj );
397 }
398
399 private String getNodeStringValue(Node node)
400 {
401 return node.getStringValue();
402 }
403
404 public String getNamespaceStringValue(Object obj)
405 {
406 Namespace ns = (Namespace) obj;
407
408 return ns.getURI();
409 }
410
411 public String getNamespacePrefix(Object obj)
412 {
413 Namespace ns = (Namespace) obj;
414
415 return ns.getPrefix();
416 }
417
418 public String getCommentStringValue(Object obj)
419 {
420 Comment cmt = (Comment) obj;
421
422 return cmt.getText();
423 }
424
425 public String translateNamespacePrefixToUri(String prefix, Object context)
426 {
427 Element element = null;
428 if ( context instanceof Element )
429 {
430 element = (Element) context;
431 }
432 else if ( context instanceof Node )
433 {
434 Node node = (Node) context;
435 element = node.getParent();
436 }
437 if ( element != null )
438 {
439 Namespace namespace = element.getNamespaceForPrefix( prefix );
440
441 if ( namespace != null )
442 {
443 return namespace.getURI();
444 }
445 }
446 return null;
447 }
448
449 public short getNodeType(Object node)
450 {
451 if ( node instanceof Node )
452 {
453 return ((Node) node).getNodeType();
454 }
455 return 0;
456 }
457
458 public Object getDocument(String uri) throws FunctionCallException
459 {
460 try
461 {
462 return getSAXReader().read( uri );
463 }
464 catch (DocumentException e)
465 {
466 throw new FunctionCallException("Failed to parse document for URI: " + uri, e);
467 }
468 }
469
470 public String getProcessingInstructionTarget(Object obj)
471 {
472 ProcessingInstruction pi = (ProcessingInstruction) obj;
473
474 return pi.getTarget();
475 }
476
477 public String getProcessingInstructionData(Object obj)
478 {
479 ProcessingInstruction pi = (ProcessingInstruction) obj;
480
481 return pi.getText();
482 }
483
484
485
486 public SAXReader getSAXReader()
487 {
488 if ( reader == null )
489 {
490 reader = new SAXReader();
491 reader.setMergeAdjacentText( true );
492 }
493 return reader;
494 }
495
496 public void setSAXReader(SAXReader reader)
497 {
498 this.reader = reader;
499 }
500
501 }