View Javadoc
1   /*
2    * Copyright 2000-2003 bob mcwhirter & James Strachan.
3    * All rights reserved.
4    *
5    *
6    * Redistribution and use in source and binary forms, with or without
7    * modification, are permitted provided that the following conditions are
8    * met:
9    * 
10   *   * Redistributions of source code must retain the above copyright
11   *     notice, this list of conditions and the following disclaimer.
12   * 
13   *   * Redistributions in binary form must reproduce the above copyright
14   *     notice, this list of conditions and the following disclaimer in the
15   *     documentation and/or other materials provided with the distribution.
16   * 
17   *   * Neither the name of the Jaxen Project nor the names of its
18   *     contributors may be used to endorse or promote products derived 
19   *     from this software without specific prior written permission.
20   * 
21   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22   * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23   * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24   * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25   * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32   *
33   * ====================================================================
34   * This software consists of voluntary contributions made by many
35   * individuals on behalf of the Jaxen Project and was originally
36   * created by bob mcwhirter <bob@werken.com> and
37   * James Strachan <jstrachan@apache.org>.  For more information on the
38   * Jaxen Project, please see <https://github.com/jaxen-xpath/jaxen/>.
39   */
40  
41  
42  package org.jaxen.xom;
43  
44  
45  import nu.xom.Attribute;
46  import nu.xom.Comment;
47  import nu.xom.Document;
48  import nu.xom.Element;
49  import nu.xom.ProcessingInstruction;
50  import nu.xom.Text;
51  import nu.xom.Node;
52  import nu.xom.Builder;
53  import nu.xom.NodeFactory;
54  import nu.xom.ParentNode;
55  
56  import org.jaxen.XPath;
57  import org.jaxen.UnsupportedAxisException;
58  import org.jaxen.FunctionCallException;
59  import org.jaxen.BaseXPath;
60  import org.jaxen.JaxenConstants;
61  import org.jaxen.util.SingleObjectIterator;
62  
63  import org.jaxen.saxpath.SAXPathException;
64  
65  import java.util.Iterator;
66  import java.util.HashMap;
67  import java.util.Map;
68  
69  /**
70   * Interface for navigating around the XOM object model.
71   *
72   * <p>
73   * This class is not intended for direct usage, but is
74   * used by the Jaxen engine during evaluation.
75   * </p>
76   *
77   * @see XPath
78   */
79  public class DocumentNavigator extends org.jaxen.DefaultNavigator
80  {
81      /**
82       */
83      private static final long serialVersionUID = 3159311338575942877L;
84  
85      public boolean isAttribute(Object o) {
86          return o instanceof Attribute;
87      }
88  
89      public boolean isComment(Object o) {
90          return o instanceof Comment;
91      }
92  
93      public boolean isDocument(Object o) {
94          return o instanceof Document;
95      }
96  
97      public boolean isElement(Object o) {
98          return o instanceof Element;
99      }
100 
101     public boolean isNamespace(Object o) {
102         return o instanceof XPathNamespace;
103     }
104 
105     public boolean isProcessingInstruction(Object o) {
106         return o instanceof ProcessingInstruction;
107     }
108 
109     public boolean isText(Object o) {
110         return o instanceof Text;
111     }
112 
113     //
114     
115     public String getAttributeName(Object o) {
116         return (isAttribute(o) ? ((Attribute)o).getLocalName() : null);
117     }
118 
119     public String getAttributeNamespaceUri(Object o) {
120         return (isAttribute(o) ? ((Attribute)o).getNamespaceURI() : null);
121     }
122 
123     public String getAttributeQName(Object o) {
124         return (isAttribute(o) ? ((Attribute)o).getQualifiedName() : null);
125     }
126 
127     public String getAttributeStringValue(Object o) {
128         return (isAttribute(o) ? ((Attribute)o).getValue() : null);
129     }
130 
131     //
132     
133     public String getCommentStringValue(Object o) {
134         return (isComment(o) ? ((Comment)o).getValue() : null);
135     }
136 
137     public String getElementName(Object o) {
138         return (isElement(o) ? ((Element)o).getLocalName() : null);
139     }
140 
141     public String getElementNamespaceUri(Object o) {
142         return (isElement(o) ? ((Element)o).getNamespaceURI() : null);
143     }
144 
145     public String getElementQName(Object o) {
146         return (isElement(o) ? ((Element)o).getQualifiedName() : null);
147     }
148 
149     public String getElementStringValue(Object o) {
150         return (o instanceof Node ? ((Node)o).getValue() : null);
151     }
152 
153     //
154     
155     public String getNamespacePrefix(Object o) {
156         if (isElement(o)) {
157             return ((Element)o).getNamespacePrefix();
158         } else if (isAttribute(o)) {
159             return ((Attribute)o).getNamespacePrefix();
160         } else if (o instanceof XPathNamespace) {
161             return ((XPathNamespace)o).getNamespacePrefix();
162         }
163         return null;
164     }
165 
166     public String getNamespaceStringValue(Object o) {
167         if (isElement(o)) {
168             return ((Element)o).getNamespaceURI();
169         } else if (isAttribute(o)) {
170             return ((Attribute)o).getNamespaceURI();
171         } else if (o instanceof XPathNamespace) {
172             return ((XPathNamespace)o).getNamespaceURI();
173         }
174         return null;
175     }
176 
177     //
178     
179     public String getTextStringValue(Object o) {
180         return (o instanceof Text ? ((Text)o).getValue() : null);
181     }
182     
183     //
184 
185     public Object getDocument(String s) throws FunctionCallException {
186         try {
187             return new Builder(new NodeFactory()).build(s);
188         } catch (Exception pe) {
189             throw new FunctionCallException(pe);
190         }
191     }
192 
193     public Object getDocumentNode(Object o) {
194         ParentNode parent = null;
195         if (o instanceof ParentNode) {
196             parent = (ParentNode)o;
197         } else if (o instanceof Node) {
198             parent = ((Node)o).getParent();
199         }
200         return parent.getDocument();
201     }
202 
203     //
204     
205     private abstract static class IndexIterator implements Iterator {
206         private Object o = null;
207         private int pos = 0, end = -1;
208         public IndexIterator(Object o, int pos, int end) {
209             this.o = o;
210             this.pos = pos;
211             this.end = end;
212         }
213         public boolean hasNext() {
214             return pos < end;
215         }
216         public abstract Object get(Object o, int i); 
217         
218         public Object next() {
219             return get(o, pos++);
220         }
221 
222         public void remove() {
223             throw new UnsupportedOperationException();
224         }
225     }
226     
227     //
228     
229     public Iterator getAttributeAxisIterator(Object o) {
230         if (isElement(o)) {
231             return new IndexIterator(o, 0, ((Element)o).getAttributeCount()) {
232                 public Object get(Object o, int i) {
233                     return ((Element)o).getAttribute(i);
234                 }
235             };
236         }
237         return JaxenConstants.EMPTY_ITERATOR;
238     }
239 
240     public Iterator getChildAxisIterator(Object o) {
241         if (isElement(o) || (o instanceof Document)) {
242             return new IndexIterator(o, 0, ((ParentNode)o).getChildCount()) {
243                 public Object get(Object o, int i) {
244                     return ((ParentNode)o).getChild(i);
245                 }
246             };
247         }
248         return JaxenConstants.EMPTY_ITERATOR;
249     }
250 
251     //
252 
253     public Iterator getParentAxisIterator(Object o) {
254         Object parent = null;
255         if (o instanceof Node) {
256             parent = ((Node)o).getParent();
257         } else if (isNamespace(o)) {
258             parent = ((XPathNamespace)o).getElement();
259         }
260         return (parent != null ? new SingleObjectIterator(parent) : null);
261     }
262 
263     public Object getParentNode(Object o)  {
264         return (o instanceof Node ? ((Node)o).getParent() : null);
265     }
266 
267     //
268 
269     public Iterator getPrecedingAxisIterator(Object o) throws UnsupportedAxisException {
270         return super.getPrecedingAxisIterator(o);
271     }
272 
273     public Iterator getPrecedingSiblingAxisIterator(Object o) throws UnsupportedAxisException {
274         return super.getPrecedingSiblingAxisIterator(o);
275     }
276     
277     //
278 
279     public String getProcessingInstructionData(Object o) {
280         return (o instanceof ProcessingInstruction ? ((ProcessingInstruction)o).getValue() : null);
281     }
282 
283     public String getProcessingInstructionTarget(Object o) {
284         return (o instanceof ProcessingInstruction ? ((ProcessingInstruction)o).getTarget() : null);
285     }
286 
287     //
288 
289     public String translateNamespacePrefixToUri(String s, Object o) {
290         Element element = null;
291         if (o instanceof Element) {
292             element = (Element) o;
293         } else if (o instanceof ParentNode) {
294         }
295         else if (o instanceof Node) {
296             element = (Element)((Node)o).getParent();
297         }
298         else if (o instanceof XPathNamespace)
299         {
300             element = ((XPathNamespace)o).getElement();
301         }
302         if (element != null) {
303             return element.getNamespaceURI(s);
304         }
305         return null;
306     }
307 
308     //
309     
310     public XPath parseXPath(String s) throws SAXPathException {
311         return new BaseXPath(s, this);
312     }
313 
314     //
315     
316     /** Wrapper for XOM namespace nodes to give them a parent,
317      * as required by the XPath data model.
318      *
319      *  @author Erwin Bolwidt
320      */
321     private static class XPathNamespace
322     {
323         private Element element;
324 
325         private String uri, prefix;
326 
327         public XPathNamespace(Element elt, String uri, String prefix)
328         {
329             element = elt;
330             this.uri = uri;
331             this.prefix = prefix;
332         }
333 
334         /** Returns the XOM element from which this namespace node has been 
335          *  retrieved. The result may be null when the namespace node has not yet
336          *  been assigned to an element.
337          */
338         public Element getElement()
339         {
340             return element;
341         }
342 
343         public String getNamespaceURI()
344         {
345             return uri;
346         }
347 
348         public String getNamespacePrefix()
349         {
350             return prefix;
351         }
352 
353         public String toString()
354         {
355             return ( "[xmlns:" + prefix + "=\"" +
356                     uri + "\", element=" +
357                     element.getLocalName() + "]" );
358         }
359     }
360 
361     //
362     
363     private boolean addNamespaceForElement(Element elt, String uri, String prefix, Map map)
364     {
365         if (uri != null && uri.length() > 0 && (! map.containsKey(prefix))) {
366             map.put(prefix, new XPathNamespace(elt, uri, prefix));
367             return true;
368         }
369         return false;
370     }
371     
372     public Iterator getNamespaceAxisIterator(Object o)
373     {
374         if (! isElement(o)) {
375             return JaxenConstants.EMPTY_ITERATOR;
376         }
377         Map nsMap = new HashMap();
378         Element elt = (Element)o;
379         ParentNode parent = elt;
380         
381         while (parent instanceof Element) {
382             elt = (Element)parent;
383             String uri    = elt.getNamespaceURI();
384             String prefix = elt.getNamespacePrefix();
385             addNamespaceForElement(elt, uri, prefix, nsMap);
386             int count = elt.getNamespaceDeclarationCount();
387             for (int i = 0; i < count; i++) {
388                 prefix = elt.getNamespacePrefix(i);
389                 uri    = elt.getNamespaceURI(prefix);
390                 addNamespaceForElement(elt, uri, prefix, nsMap);
391             }
392             parent = elt.getParent();
393         }
394         addNamespaceForElement(elt, "http://www.w3.org/XML/1998/namespace", "xml", nsMap);
395 
396         return nsMap.values().iterator();
397     }
398 }