View Javadoc

1   package org.jaxen.jdom;
2   
3   /*
4    * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/jdom/DocumentNavigator.java,v 1.28 2005/04/09 21:56:31 elharo Exp $
5    * $Revision: 1.28 $
6    * $Date: 2005/04/09 21:56:31 $
7    *
8    * ====================================================================
9    *
10   * Copyright (C) 2000-2005 bob mcwhirter & James Strachan.
11   * All rights reserved.
12   *
13   * Redistribution and use in source and binary forms, with or without
14   * modification, are permitted provided that the following conditions
15   * are met:
16   *
17   * 1. Redistributions of source code must retain the above copyright
18   *    notice, this list of conditions, and the following disclaimer.
19   *
20   * 2. Redistributions in binary form must reproduce the above copyright
21   *    notice, this list of conditions, and the disclaimer that follows
22   *    these conditions in the documentation and/or other materials
23   *    provided with the distribution.
24   *
25   * 3. The name "Jaxen" must not be used to endorse or promote products
26   *    derived from this software without prior written permission.  For
27   *    written permission, please contact license@jaxen.org.
28   *
29   * 4. Products derived from this software may not be called "Jaxen", nor
30   *    may "Jaxen" appear in their name, without prior written permission
31   *    from the Jaxen Project Management (pm@jaxen.org).
32   *
33   * In addition, we request (but do not require) that you include in the
34   * end-user documentation provided with the redistribution and/or in the
35   * software itself an acknowledgement equivalent to the following:
36   *     "This product includes software developed by the
37   *      Jaxen Project (http://www.jaxen.org/)."
38   * Alternatively, the acknowledgment may be graphical using the logos
39   * available at http://www.jaxen.org/
40   *
41   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
42   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44   * DISCLAIMED.  IN NO EVENT SHALL THE Jaxen AUTHORS OR THE PROJECT
45   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
48   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
49   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
51   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52   * SUCH DAMAGE.
53   *
54   * ====================================================================
55   * This software consists of voluntary contributions made by many
56   * individuals on behalf of the Jaxen Project and was originally
57   * created by bob mcwhirter <bob@werken.com> and
58   * James Strachan <jstrachan@apache.org>.  For more information on the
59   * Jaxen Project, please see <http://www.jaxen.org/>.
60   *
61   * $Id: DocumentNavigator.java,v 1.28 2005/04/09 21:56:31 elharo Exp $
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 }