1 package org.jaxen.jdom;
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.HashMap;
65 import java.util.Iterator;
66 import java.util.List;
67 import java.util.Map;
68
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 import org.jdom.Attribute;
78 import org.jdom.CDATA;
79 import org.jdom.Comment;
80 import org.jdom.Document;
81 import org.jdom.Element;
82 import org.jdom.Namespace;
83 import org.jdom.ProcessingInstruction;
84 import org.jdom.Text;
85 import org.jdom.input.SAXBuilder;
86
87 /***
88 * Interface for navigating around the JDOM object model.
89 *
90 * <p>
91 * This class is not intended for direct usage, but is
92 * used by the Jaxen engine during evaluation.
93 * </p>
94 *
95 * @see XPath
96 *
97 * @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
98 * @author Stephen Colebourne
99 */
100 public class DocumentNavigator extends DefaultNavigator implements NamedAccessNavigator
101 {
102 /*** Singleton implementation.
103 */
104 private static class Singleton
105 {
106 /*** Singleton instance.
107 */
108 private static DocumentNavigator instance = new DocumentNavigator();
109 }
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 || obj instanceof XPathNamespace;
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 && uri.length() == 0 )
166 return null;
167 else
168 return uri;
169 }
170
171 public String getAttributeName(Object obj)
172 {
173 Attribute attr = (Attribute) obj;
174
175 return attr.getName();
176 }
177
178 public String getAttributeNamespaceUri(Object obj)
179 {
180 Attribute attr = (Attribute) obj;
181
182 String uri = attr.getNamespaceURI();
183 if ( uri != null && uri.length() == 0 )
184 return null;
185 else
186 return uri;
187 }
188
189 public Iterator getChildAxisIterator(Object contextNode)
190 {
191 if ( contextNode instanceof Element )
192 {
193 return ((Element)contextNode).getContent().iterator();
194 }
195 else if ( contextNode instanceof Document )
196 {
197 return ((Document)contextNode).getContent().iterator();
198 }
199
200 return JaxenConstants.EMPTY_ITERATOR;
201 }
202
203 /***
204 * Retrieves an <code>Iterator</code> over the child elements that
205 * match the supplied name.
206 *
207 * @param contextNode the origin context node
208 * @param localName the local name of the children to return, always present
209 * @param namespacePrefix the prefix of the namespace of the children to return
210 * @param namespaceURI the uri of the namespace of the children to return
211 * @return an Iterator that traverses the named children, or null if none
212 */
213 public Iterator getChildAxisIterator(
214 Object contextNode, String localName, String namespacePrefix, String namespaceURI) {
215
216 if ( contextNode instanceof Element ) {
217 Element node = (Element) contextNode;
218 if (namespaceURI == null) {
219 return node.getChildren(localName).iterator();
220 }
221 return node.getChildren(localName, Namespace.getNamespace(namespacePrefix, namespaceURI)).iterator();
222 }
223 if ( contextNode instanceof Document ) {
224 Document node = (Document) contextNode;
225
226 Element el = node.getRootElement();
227 if (el.getName().equals(localName) == false) {
228 return JaxenConstants.EMPTY_ITERATOR;
229 }
230 if (namespaceURI != null) {
231 if (Namespace.getNamespace(namespacePrefix, namespaceURI).equals(el.getNamespace()) == false) {
232 return JaxenConstants.EMPTY_ITERATOR;
233 }
234 }
235 return new SingleObjectIterator(el);
236 }
237
238 return JaxenConstants.EMPTY_ITERATOR;
239 }
240
241 public Iterator getNamespaceAxisIterator(Object contextNode)
242 {
243 if ( ! ( contextNode instanceof Element ) )
244 {
245 return JaxenConstants.EMPTY_ITERATOR;
246 }
247
248 Element elem = (Element) contextNode;
249
250 Map nsMap = new HashMap();
251
252 Element current = elem;
253
254 while ( current != null ) {
255
256 Namespace ns = current.getNamespace();
257
258 if ( ns != Namespace.NO_NAMESPACE ) {
259 if ( !nsMap.containsKey(ns.getPrefix()) )
260 nsMap.put( ns.getPrefix(), new XPathNamespace(elem, ns) );
261 }
262
263 Iterator additional = current.getAdditionalNamespaces().iterator();
264
265 while ( additional.hasNext() ) {
266
267 ns = (Namespace)additional.next();
268 if ( !nsMap.containsKey(ns.getPrefix()) )
269 nsMap.put( ns.getPrefix(), new XPathNamespace(elem, ns) );
270 }
271
272 if (current.getParent() instanceof Element) {
273 current = (Element)current.getParent();
274 } else {
275 current = null;
276 }
277 }
278
279 nsMap.put( "xml", new XPathNamespace(elem, Namespace.XML_NAMESPACE) );
280
281 return nsMap.values().iterator();
282 }
283
284 public Iterator getParentAxisIterator(Object contextNode)
285 {
286 Object parent = null;
287
288 if ( contextNode instanceof Document )
289 {
290 return JaxenConstants.EMPTY_ITERATOR;
291 }
292 else if ( contextNode instanceof Element )
293 {
294 parent = ((Element)contextNode).getParent();
295
296 if ( parent == null )
297 {
298 if ( ((Element)contextNode).isRootElement() )
299 {
300 parent = ((Element)contextNode).getDocument();
301 }
302 }
303 }
304 else if ( contextNode instanceof Attribute )
305 {
306 parent = ((Attribute)contextNode).getParent();
307 }
308 else if ( contextNode instanceof XPathNamespace )
309 {
310 parent = ((XPathNamespace)contextNode).getJDOMElement();
311 }
312 else if ( contextNode instanceof ProcessingInstruction )
313 {
314 parent = ((ProcessingInstruction)contextNode).getParent();
315 }
316 else if ( contextNode instanceof Comment )
317 {
318 parent = ((Comment)contextNode).getParent();
319 }
320 else if ( contextNode instanceof Text )
321 {
322 parent = ((Text)contextNode).getParent();
323 }
324
325 if ( parent != null )
326 {
327 return new SingleObjectIterator( parent );
328 }
329
330 return JaxenConstants.EMPTY_ITERATOR;
331 }
332
333 public Iterator getAttributeAxisIterator(Object contextNode)
334 {
335 if ( ! ( contextNode instanceof Element ) )
336 {
337 return JaxenConstants.EMPTY_ITERATOR;
338 }
339
340 Element elem = (Element) contextNode;
341
342 return elem.getAttributes().iterator();
343 }
344
345 /***
346 * Retrieves an <code>Iterator</code> over the attribute elements that
347 * match the supplied name.
348 *
349 * @param contextNode the origin context node
350 * @param localName the local name of the attributes to return, always present
351 * @param namespacePrefix the prefix of the namespace of the attributes to return
352 * @param namespaceURI the URI of the namespace of the attributes to return
353 * @return an Iterator that traverses the named attributes, not null
354 */
355 public Iterator getAttributeAxisIterator(
356 Object contextNode, String localName, String namespacePrefix, String namespaceURI) {
357
358 if ( contextNode instanceof Element ) {
359 Element node = (Element) contextNode;
360 Namespace namespace = (namespaceURI == null ? Namespace.NO_NAMESPACE :
361 Namespace.getNamespace(namespacePrefix, namespaceURI));
362 Attribute attr = node.getAttribute(localName, namespace);
363 if (attr != null) {
364 return new SingleObjectIterator(attr);
365 }
366 }
367 return JaxenConstants.EMPTY_ITERATOR;
368 }
369
370 /*** Returns a parsed form of the given XPath string, which will be suitable
371 * for queries on JDOM documents.
372 */
373 public XPath parseXPath (String xpath) throws SAXPathException
374 {
375 return new JDOMXPath(xpath);
376 }
377
378 public Object getDocumentNode(Object contextNode)
379 {
380 if ( contextNode instanceof Document )
381 {
382 return contextNode;
383 }
384
385 Element elem = (Element) contextNode;
386
387 return elem.getDocument();
388 }
389
390 public String getElementQName(Object obj)
391 {
392 Element elem = (Element) obj;
393
394 String prefix = elem.getNamespacePrefix();
395
396 if ( prefix == null || prefix.length() == 0 )
397 {
398 return elem.getName();
399 }
400
401 return prefix + ":" + elem.getName();
402 }
403
404 public String getAttributeQName(Object obj)
405 {
406 Attribute attr = (Attribute) obj;
407
408 String prefix = attr.getNamespacePrefix();
409
410 if ( prefix == null || "".equals( prefix ) )
411 {
412 return attr.getName();
413 }
414
415 return prefix + ":" + attr.getName();
416 }
417
418 public String getNamespaceStringValue(Object obj)
419 {
420 if (obj instanceof Namespace) {
421
422 Namespace ns = (Namespace) obj;
423 return ns.getURI();
424 } else {
425
426 XPathNamespace ns = (XPathNamespace) obj;
427 return ns.getJDOMNamespace().getURI();
428 }
429
430 }
431
432 public String getNamespacePrefix(Object obj)
433 {
434 if (obj instanceof Namespace) {
435
436 Namespace ns = (Namespace) obj;
437 return ns.getPrefix();
438 } else {
439
440 XPathNamespace ns = (XPathNamespace) obj;
441 return ns.getJDOMNamespace().getPrefix();
442 }
443 }
444
445 public String getTextStringValue(Object obj)
446 {
447 if ( obj instanceof Text )
448 {
449 return ((Text)obj).getText();
450 }
451
452 if ( obj instanceof CDATA )
453 {
454 return ((CDATA)obj).getText();
455 }
456
457 return "";
458 }
459
460 public String getAttributeStringValue(Object obj)
461 {
462 Attribute attr = (Attribute) obj;
463
464 return attr.getValue();
465 }
466
467 public String getElementStringValue(Object obj)
468 {
469 Element elem = (Element) obj;
470
471 StringBuffer buf = new StringBuffer();
472
473 List content = elem.getContent();
474 Iterator contentIter = content.iterator();
475 Object each = null;
476
477 while ( contentIter.hasNext() )
478 {
479 each = contentIter.next();
480
481 if ( each instanceof Text )
482 {
483 buf.append( ((Text)each).getText() );
484 }
485 else if ( each instanceof CDATA )
486 {
487 buf.append( ((CDATA)each).getText() );
488 }
489 else if ( each instanceof Element )
490 {
491 buf.append( getElementStringValue( each ) );
492 }
493 }
494
495 return buf.toString();
496 }
497
498 public String getProcessingInstructionTarget(Object obj)
499 {
500 ProcessingInstruction pi = (ProcessingInstruction) obj;
501
502 return pi.getTarget();
503 }
504
505 public String getProcessingInstructionData(Object obj)
506 {
507 ProcessingInstruction pi = (ProcessingInstruction) obj;
508
509 return pi.getData();
510 }
511
512 public String getCommentStringValue(Object obj)
513 {
514 Comment cmt = (Comment) obj;
515
516 return cmt.getText();
517 }
518
519 public String translateNamespacePrefixToUri(String prefix, Object context)
520 {
521 Element element = null;
522 if ( context instanceof Element )
523 {
524 element = (Element) context;
525 }
526 else if ( context instanceof Text )
527 {
528 element = (Element)((Text)context).getParent();
529 }
530 else if ( context instanceof Attribute )
531 {
532 element = ((Attribute)context).getParent();
533 }
534 else if ( context instanceof XPathNamespace )
535 {
536 element = ((XPathNamespace)context).getJDOMElement();
537 }
538 else if ( context instanceof Comment )
539 {
540 element = (Element)((Comment)context).getParent();
541 }
542 else if ( context instanceof ProcessingInstruction )
543 {
544 element = (Element)((ProcessingInstruction)context).getParent();
545 }
546
547 if ( element != null )
548 {
549 Namespace namespace = element.getNamespace( prefix );
550
551 if ( namespace != null )
552 {
553 return namespace.getURI();
554 }
555 }
556 return null;
557 }
558
559 public Object getDocument(String url) throws FunctionCallException
560 {
561 try
562 {
563 SAXBuilder builder = new SAXBuilder();
564
565 return builder.build( url );
566 }
567 catch (Exception e)
568 {
569 throw new FunctionCallException( e.getMessage() );
570 }
571 }
572 }