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