KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jaxen > dom > DocumentNavigator


1 package org.jaxen.dom;
2
3 /*
4  * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/dom/DocumentNavigator.java,v 1.44 2005/06/15 17:58:32 elharo Exp $
5  * $Revision: 1.44 $
6  * $Date: 2005/06/15 17:58:32 $
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.44 2005/06/15 17:58:32 elharo Exp $
62 */

63
64 import javax.xml.parsers.DocumentBuilder JavaDoc;
65 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
66 import javax.xml.parsers.ParserConfigurationException JavaDoc;
67
68 import java.io.IOException JavaDoc;
69 import java.util.HashMap JavaDoc;
70 import java.util.Iterator JavaDoc;
71 import java.util.NoSuchElementException JavaDoc;
72
73 import org.jaxen.DefaultNavigator;
74 import org.jaxen.FunctionCallException;
75 import org.jaxen.Navigator;
76 import org.jaxen.XPath;
77 import org.jaxen.JaxenConstants;
78 import org.w3c.dom.Attr JavaDoc;
79 import org.w3c.dom.Document JavaDoc;
80 import org.w3c.dom.NamedNodeMap JavaDoc;
81 import org.w3c.dom.Node JavaDoc;
82 import org.w3c.dom.NodeList JavaDoc;
83 import org.w3c.dom.ProcessingInstruction JavaDoc;
84 import org.xml.sax.SAXException JavaDoc;
85
86 /** Interface for navigating around the W3C DOM Level 2 object model.
87  *
88  * <p>
89  * This class is not intended for direct usage, but is
90  * used by the Jaxen engine during evaluation.
91  * </p>
92  *
93  * <p>This class implements the {@link org.jaxen.DefaultNavigator} interface
94  * for the Jaxen XPath library. This adapter allows the Jaxen
95  * library to be used to execute XPath queries against any object tree
96  * that implements the DOM level 2 interfaces.</p>
97  *
98  * <p>Note: DOM level 2 does not include a node representing an XPath
99  * namespace node. This navigator will return namespace nodes
100  * as instances of the custom {@link NamespaceNode} class, and
101  * users will have to check result sets to locate and isolate
102  * these.</p>
103  *
104  * @author David Megginson
105  * @author James Strachan
106  *
107  * @see XPath
108  * @see NamespaceNode
109  */

110 public class DocumentNavigator extends DefaultNavigator
111 {
112
113     
114     ////////////////////////////////////////////////////////////////////
115
// Constants.
116
////////////////////////////////////////////////////////////////////
117

118     /**
119      * Constant: navigator.
120      */

121     private final static DocumentNavigator SINGLETON = new DocumentNavigator();
122
123
124     
125     ////////////////////////////////////////////////////////////////////
126
// Constructor.
127
////////////////////////////////////////////////////////////////////
128

129
130     /**
131      * Default constructor.
132      */

133     public DocumentNavigator ()
134     {
135     }
136
137
138     /**
139      * Get a constant DocumentNavigator for efficiency.
140      *
141      * @return a constant instance of a DocumentNavigator.
142      */

143     public static Navigator getInstance ()
144     {
145         return SINGLETON;
146     }
147
148
149     
150     ////////////////////////////////////////////////////////////////////
151
// Implementation of org.jaxen.DefaultNavigator.
152
////////////////////////////////////////////////////////////////////
153

154
155     /**
156      * Get an iterator over all of this node's children.
157      *
158      * @param contextNode the context node for the child axis.
159      * @return a possibly-empty iterator (not null)
160      */

161     public Iterator JavaDoc getChildAxisIterator (Object JavaDoc contextNode)
162     {
163         return new NodeIterator ((Node JavaDoc)contextNode) {
164                 protected Node JavaDoc getFirstNode (Node JavaDoc node)
165                 {
166                     return node.getFirstChild();
167                 }
168                 protected Node JavaDoc getNextNode (Node JavaDoc node)
169                 {
170                     return node.getNextSibling();
171                 }
172             };
173     }
174
175
176     /**
177      * Get a (single-member) iterator over this node's parent.
178      *
179      * @param contextNode the context node for the parent axis
180      * @return a possibly-empty iterator (not null)
181      */

182     public Iterator JavaDoc getParentAxisIterator (Object JavaDoc contextNode)
183     {
184         Node JavaDoc node = (Node JavaDoc)contextNode;
185
186         if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
187             return new NodeIterator (node) {
188                     protected Node JavaDoc getFirstNode (Node JavaDoc n)
189                     {
190                         // FIXME: assumes castability.
191
return ((Attr JavaDoc)n).getOwnerElement();
192                     }
193                     protected Node JavaDoc getNextNode (Node JavaDoc n) {
194                         return null;
195                     }
196                 };
197         } else {
198             return new NodeIterator (node) {
199                     protected Node JavaDoc getFirstNode (Node JavaDoc n)
200                     {
201                         return n.getParentNode();
202                     }
203                     protected Node JavaDoc getNextNode (Node JavaDoc n) {
204                         return null;
205                     }
206                 };
207         }
208     }
209
210
211     /**
212      * Get an iterator over all following siblings.
213      *
214      * @param contextNode the context node for the sibling iterator
215      * @return a possibly-empty iterator (not null)
216      */

217     public Iterator JavaDoc getFollowingSiblingAxisIterator (Object JavaDoc contextNode)
218     {
219         return new NodeIterator ((Node JavaDoc)contextNode) {
220                 protected Node JavaDoc getFirstNode (Node JavaDoc node)
221                 {
222                     return getNextNode(node);
223                 }
224                 protected Node JavaDoc getNextNode (Node JavaDoc node) {
225                     return node.getNextSibling();
226                 }
227             };
228     }
229
230
231     /**
232      * Get an iterator over all preceding siblings.
233      *
234      * @param contextNode the context node for the preceding sibling axis
235      * @return a possibly-empty iterator (not null)
236      */

237     public Iterator JavaDoc getPrecedingSiblingAxisIterator (Object JavaDoc contextNode)
238     {
239         return new NodeIterator ((Node JavaDoc)contextNode) {
240                 protected Node JavaDoc getFirstNode (Node JavaDoc node)
241                 {
242                     return getNextNode(node);
243                 }
244                 protected Node JavaDoc getNextNode (Node JavaDoc node) {
245                     return node.getPreviousSibling();
246                 }
247             };
248     }
249
250
251     /**
252      * Get an iterator over all following nodes, depth-first.
253      *
254      * @param contextNode the context node for the following axis
255      * @return a possibly-empty iterator (not null)
256      */

257     public Iterator JavaDoc getFollowingAxisIterator (Object JavaDoc contextNode)
258     {
259         return new NodeIterator ((Node JavaDoc)contextNode) {
260                 protected Node JavaDoc getFirstNode (Node JavaDoc node)
261                 {
262                     if (node == null)
263                         return null;
264                     else {
265                         Node JavaDoc sibling = node.getNextSibling();
266                         if (sibling == null)
267                             return getFirstNode(node.getParentNode());
268                         else
269                             return sibling;
270                     }
271                 }
272                 protected Node JavaDoc getNextNode (Node JavaDoc node) {
273                     if (node == null)
274                         return null;
275                     else {
276                         Node JavaDoc n = node.getFirstChild();
277                         if (n == null)
278                             n = node.getNextSibling();
279                         if (n == null)
280                             return getFirstNode(node.getParentNode());
281                         else
282                             return n;
283                     }
284                 }
285             };
286     }
287
288
289     /**
290      * Get an iterator over all attributes.
291      *
292      * @param contextNode the context node for the attribute axis
293      * @return a possibly-empty iterator (not null)
294      */

295     public Iterator JavaDoc getAttributeAxisIterator (Object JavaDoc contextNode)
296     {
297         if (isElement(contextNode)) {
298             return new AttributeIterator((Node JavaDoc)contextNode);
299         } else {
300             return JaxenConstants.EMPTY_ITERATOR;
301         }
302     }
303
304
305     /**
306      * Get an iterator over all declared namespaces.
307      *
308      * <p>Note: this iterator is not live: it takes a snapshot
309      * and that snapshot remains static during the life of
310      * the iterator (i.e. it won't reflect subsequent changes
311      * to the DOM).</p>
312      *
313      * @param contextNode the context node for the namespace axis
314      * @return a possibly-empty iterator (not null)
315      */

316     public Iterator JavaDoc getNamespaceAxisIterator (Object JavaDoc contextNode)
317     {
318         // Only elements have namespace nodes
319
if (isElement(contextNode)) {
320
321             HashMap JavaDoc nsMap = new HashMap JavaDoc();
322
323             // Starting at the current node, walk
324
// up to the root, noting the namespace
325
// declarations in scope.
326
for (Node JavaDoc n = (Node JavaDoc)contextNode;
327                  n != null;
328                  n = n.getParentNode()) {
329                 
330                 // 1. Look for namespace attributes
331
if (n.hasAttributes()) {
332                     NamedNodeMap JavaDoc atts = n.getAttributes();
333                     int length = atts.getLength();
334                     for (int i = 0; i < length; i++) {
335                         Attr JavaDoc att = (Attr JavaDoc) atts.item(i);
336                         // work around crimson bug by testing URI rather than name
337
String JavaDoc attributeNamespace = att.getNamespaceURI();
338                         if ("http://www.w3.org/2000/xmlns/".equals(attributeNamespace)) {
339                             NamespaceNode ns =
340                                 new NamespaceNode((Node JavaDoc)contextNode, att);
341                             // Add only if there's not a closer
342
// declaration in force.
343
String JavaDoc name = ns.getNodeName();
344                             if (!nsMap.containsKey(name)) nsMap.put(name, ns);
345                         }
346                         else if (attributeNamespace != null) {
347                             String JavaDoc prefix = att.getPrefix();
348                             NamespaceNode ns =
349                                 new NamespaceNode((Node JavaDoc)contextNode, prefix, attributeNamespace);
350                             // Add only if there's not a closer
351
// declaration in force.
352
if (!nsMap.containsKey(prefix)) nsMap.put(prefix, ns);
353                             
354                         }
355                     }
356                 }
357                 
358                 // 2. Look for the namespace of the element itself
359
String JavaDoc myNamespace = n.getNamespaceURI();
360                 if (myNamespace != null && ! "".equals(myNamespace)) {
361                     String JavaDoc myPrefix = n.getPrefix();
362                     if (!nsMap.containsKey(myPrefix)) {
363                         NamespaceNode ns = new NamespaceNode((Node JavaDoc) contextNode, myPrefix, myNamespace);
364                         nsMap.put(myPrefix, ns);
365                     }
366                 }
367                 
368             }
369             // Section 5.4 of the XPath rec requires
370
// this to be present.
371
nsMap.put("xml",
372                       new
373                       NamespaceNode((Node JavaDoc)contextNode,
374                                     "xml",
375                                     "http://www.w3.org/XML/1998/namespace"));
376
377             // An empty default namespace cancels
378
// any previous default.
379
NamespaceNode defaultNS = (NamespaceNode)nsMap.get("");
380             if (defaultNS != null && defaultNS.getNodeValue().length() == 0)
381                 nsMap.remove("");
382             return nsMap.values().iterator();
383         } else {
384             return JaxenConstants.EMPTY_ITERATOR;
385         }
386     }
387
388     /** Returns a parsed form of the given XPath string, which will be suitable
389      * for queries on DOM documents.
390      */

391     public XPath parseXPath (String JavaDoc xpath) throws org.jaxen.saxpath.SAXPathException
392     {
393         return new DOMXPath(xpath);
394     }
395
396     /**
397      * Get the top-level document node.
398      *
399      * @param contextNode any node in the document
400      * @return the root node
401      */

402     public Object JavaDoc getDocumentNode (Object JavaDoc contextNode)
403     {
404         if (isDocument(contextNode)) return contextNode;
405         else return ((Node JavaDoc)contextNode).getOwnerDocument();
406     }
407
408
409     /**
410      * Get the namespace URI of an element.
411      *
412      * @param object the target node
413      * @return a string (possibly empty) if the node is an element,
414      * and null otherwise
415      */

416     public String JavaDoc getElementNamespaceUri (Object JavaDoc object)
417     {
418         String JavaDoc uri = ((Node JavaDoc)object).getNamespaceURI();
419         return uri;
420     }
421
422
423     /**
424      * Get the local name of an element.
425      *
426      * @param object the target node
427      * @return a string representing the unqualified local name
428      * if the node is an element, or null otherwise
429      */

430     public String JavaDoc getElementName (Object JavaDoc object)
431     {
432         String JavaDoc name = ((Node JavaDoc)object).getLocalName();
433         if (name == null) name = ((Node JavaDoc)object).getNodeName();
434         return name;
435     }
436
437
438     /**
439      * Get the qualified name of an element.
440      *
441      * @param object the target node
442      * @return a string representing the qualified (i.e. possibly
443      * prefixed) name if the node is an element, or null otherwise
444      */

445     public String JavaDoc getElementQName (Object JavaDoc object)
446     {
447         String JavaDoc qname = ((Node JavaDoc)object).getNodeName();
448         if (qname == null) qname = ((Node JavaDoc)object).getLocalName();
449         return qname;
450     }
451
452
453     /**
454      * Get the Namespace URI of an attribute.
455      *
456      * @param object the target node
457      */

458     public String JavaDoc getAttributeNamespaceUri (Object JavaDoc object)
459     {
460         String JavaDoc uri = ((Node JavaDoc)object).getNamespaceURI();
461         return uri;
462     }
463
464
465     /**
466      * Get the local name of an attribute.
467      *
468      * @param object the target node
469      * @return a string representing the unqualified local name
470      * if the node is an attribute, or null otherwise
471      */

472     public String JavaDoc getAttributeName (Object JavaDoc object)
473     {
474         String JavaDoc name = ((Node JavaDoc)object).getLocalName();
475         if (name == null) name = ((Node JavaDoc)object).getNodeName();
476         return name;
477     }
478
479
480     /**
481      * Get the qualified name of an attribute.
482      *
483      * @param object the target node
484      * @return a string representing the qualified (i.e. possibly
485      * prefixed) name if the node is an attribute, or null otherwise
486      */

487     public String JavaDoc getAttributeQName (Object JavaDoc object)
488     {
489         String JavaDoc qname = ((Node JavaDoc)object).getNodeName();
490         if (qname == null) qname = ((Node JavaDoc)object).getLocalName();
491         return qname;
492     }
493
494
495     /**
496      * Test if a node is a top-level document.
497      *
498      * @param object the target node
499      * @return true if the node is the document root, false otherwise
500      */

501     public boolean isDocument (Object JavaDoc object)
502     {
503         return (object instanceof Node JavaDoc) &&
504             (((Node JavaDoc)object).getNodeType() == Node.DOCUMENT_NODE);
505     }
506
507
508     /**
509      * Test if a node is a namespace.
510      *
511      * @param object the target node
512      * @return true if the node is a namespace, false otherwise
513      */

514     public boolean isNamespace (Object JavaDoc object)
515     {
516         return (object instanceof NamespaceNode);
517     }
518
519
520     /**
521      * Test if a node is an element.
522      *
523      * @param object the target node
524      * @return true if the node is an element, false otherwise
525      */

526     public boolean isElement (Object JavaDoc object)
527     {
528         return (object instanceof Node JavaDoc) &&
529             (((Node JavaDoc)object).getNodeType() == Node.ELEMENT_NODE);
530     }
531
532
533     /**
534      * Test if a node is an attribute. <code>xmlns</code> and
535      * <code>xmlns:pre</code> attributes do not count as attributes
536      * for the purposes of XPath.
537      *
538      * @param object the target node
539      * @return true if the node is an attribute, false otherwise
540      */

541     public boolean isAttribute (Object JavaDoc object)
542     {
543         return (object instanceof Node JavaDoc) &&
544             (((Node JavaDoc)object).getNodeType() == Node.ATTRIBUTE_NODE)
545             && ! "http://www.w3.org/2000/xmlns/".equals(((Node JavaDoc) object).getNamespaceURI());
546     }
547
548
549     /**
550      * Test if a node is a comment.
551      *
552      * @param object the target node
553      * @return true if the node is a comment, false otherwise
554      */

555     public boolean isComment (Object JavaDoc object)
556     {
557         return (object instanceof Node JavaDoc) &&
558             (((Node JavaDoc)object).getNodeType() == Node.COMMENT_NODE);
559     }
560
561
562     /**
563      * Test if a node is plain text.
564      *
565      * @param object the target node
566      * @return true if the node is a text node, false otherwise
567      */

568     public boolean isText (Object JavaDoc object)
569     {
570         if (object instanceof Node JavaDoc) {
571             switch (((Node JavaDoc)object).getNodeType()) {
572                 case Node.TEXT_NODE:
573                 case Node.CDATA_SECTION_NODE:
574                     return true;
575                 default:
576                     return false;
577             }
578         } else {
579             return false;
580         }
581     }
582
583
584     /**
585      * Test if a node is a processing instruction.
586      *
587      * @param object the target node
588      * @return true if the node is a processing instruction, false otherwise
589      */

590     public boolean isProcessingInstruction (Object JavaDoc object)
591     {
592         return (object instanceof Node JavaDoc) &&
593             (((Node JavaDoc)object).getNodeType() == Node.PROCESSING_INSTRUCTION_NODE);
594     }
595
596
597     /**
598      * Get the string value of an element node.
599      *
600      * @param object the target node
601      * @return the text inside the node and its descendants if the node
602      * is an element, null otherwise
603      */

604     public String JavaDoc getElementStringValue (Object JavaDoc object)
605     {
606         if (isElement(object)) {
607             return getStringValue((Node JavaDoc)object, new StringBuffer JavaDoc()).toString();
608         }
609         else {
610             return null;
611         }
612     }
613
614
615     /**
616      * Construct an element's string value recursively.
617      *
618      * @param node the current node
619      * @param buffer the buffer for building the text
620      * @return the buffer passed as a parameter (for convenience)
621      */

622     private StringBuffer JavaDoc getStringValue (Node JavaDoc node, StringBuffer JavaDoc buffer)
623     {
624         if (isText(node)) {
625             buffer.append(node.getNodeValue());
626         } else {
627             NodeList JavaDoc children = node.getChildNodes();
628             int length = children.getLength();
629             for (int i = 0; i < length; i++) {
630                 getStringValue(children.item(i), buffer);
631             }
632         }
633         return buffer;
634     }
635
636
637     /**
638      * Get the string value of an attribute node.
639      *
640      * @param object the target node
641      * @return the text of the attribute value if the node is an
642      * attribute, null otherwise
643      */

644     public String JavaDoc getAttributeStringValue (Object JavaDoc object)
645     {
646         if (isAttribute(object)) return ((Node JavaDoc)object).getNodeValue();
647         else return null;
648     }
649
650
651     /**
652      * Get the string value of text.
653      *
654      * @param object the target node
655      * @return the string of text if the node is text, null otherwise
656      */

657     public String JavaDoc getTextStringValue (Object JavaDoc object)
658     {
659         if (isText(object)) return ((Node JavaDoc)object).getNodeValue();
660         else return null;
661     }
662
663
664     /**
665      * Get the string value of a comment node.
666      *
667      * @param object the target node
668      * @return the text of the comment if the node is a comment,
669      * null otherwise
670      */

671     public String JavaDoc getCommentStringValue (Object JavaDoc object)
672     {
673         if (isComment(object)) return ((Node JavaDoc)object).getNodeValue();
674         else return null;
675     }
676
677
678     /**
679      * Get the string value of a namespace node.
680      *
681      * @param object the target node
682      * @return the namespace URI as a (possibly empty) string if the
683      * node is a namespace node, null otherwise
684      */

685     public String JavaDoc getNamespaceStringValue (Object JavaDoc object)
686     {
687         if (isNamespace(object)) return ((NamespaceNode)object).getNodeValue();
688         else return null;
689     }
690
691     /**
692      * Get the prefix value of a Namespace node.
693      *
694      * @param object the target node
695      * @return the Namespace prefix a (possibly empty) string if the
696      * node is a namespace node, null otherwise
697      */

698     public String JavaDoc getNamespacePrefix (Object JavaDoc object)
699     {
700         if (isNamespace(object)) return ((NamespaceNode)object).getLocalName();
701         else return null;
702     }
703
704     /**
705      * Translate a Namespace prefix to a URI.
706      */

707     public String JavaDoc translateNamespacePrefixToUri (String JavaDoc prefix, Object JavaDoc element)
708     {
709         Iterator JavaDoc it = getNamespaceAxisIterator(element);
710         while (it.hasNext()) {
711             NamespaceNode ns = (NamespaceNode)it.next();
712             if (prefix.equals(ns.getNodeName())) return ns.getNodeValue();
713         }
714         return null;
715     }
716
717     /**
718      * Use JAXP to load a namespace aware document from a given URI.
719      *
720      * @param uri is the URI of the document to load
721      * @return the new W3C DOM Level 2 Document instance
722      * @throws FunctionCallException containing a nested exception
723      * if a problem occurs trying to parse the given document
724      */

725     public Object JavaDoc getDocument(String JavaDoc uri) throws FunctionCallException
726     {
727         try
728         {
729             DocumentBuilderFactory JavaDoc factory = DocumentBuilderFactory.newInstance();
730             factory.setNamespaceAware(true);
731             DocumentBuilder JavaDoc builder = factory.newDocumentBuilder();
732             return builder.parse( uri );
733         }
734         catch (ParserConfigurationException JavaDoc e) {
735             throw new FunctionCallException("JAXP setup error in document() function: " + e.getMessage(), e);
736         }
737         catch (SAXException JavaDoc e) {
738            throw new FunctionCallException("XML error in document() function: " + e.getMessage(), e);
739         }
740         catch (IOException JavaDoc e) {
741            throw new FunctionCallException("I/O error in document() function: " + e.getMessage(), e);
742         }
743         
744     }
745
746     public String JavaDoc getProcessingInstructionTarget(Object JavaDoc obj)
747     {
748         ProcessingInstruction JavaDoc pi = (ProcessingInstruction JavaDoc) obj;
749
750         return pi.getTarget();
751     }
752
753     public String JavaDoc getProcessingInstructionData(Object JavaDoc obj)
754     {
755         ProcessingInstruction JavaDoc pi = (ProcessingInstruction JavaDoc) obj;
756
757         return pi.getData();
758     }
759
760     
761     ////////////////////////////////////////////////////////////////////
762
// Inner class: iterate over DOM nodes.
763
////////////////////////////////////////////////////////////////////
764

765
766     // FIXME: needs to recurse into
767
// DocumentFragment and EntityReference
768
// to use their children.
769

770     /**
771      * A generic iterator over DOM nodes.
772      *
773      * <p>Concrete subclasses must implement the {@link #getFirstNode}
774      * and {@link #getNextNode} methods for a specific iteration
775      * strategy.</p>
776      */

777     abstract class NodeIterator
778     implements Iterator JavaDoc
779     {
780
781
782         /**
783          * Constructor.
784          *
785          * @param contextNode the starting node
786          */

787         public NodeIterator (Node JavaDoc contextNode)
788         {
789             node = getFirstNode(contextNode);
790             while (!isXPathNode(node))
791                 node = getNextNode(node);
792         }
793
794
795         /**
796          * @see Iterator#hasNext
797          */

798         public boolean hasNext ()
799         {
800             return (node != null);
801         }
802
803
804         /**
805          * @see Iterator#next
806          */

807         public Object JavaDoc next ()
808         {
809             if (node == null) throw new NoSuchElementException JavaDoc();
810             Node JavaDoc ret = node;
811             node = getNextNode(node);
812             while (!isXPathNode(node)) {
813                 node = getNextNode(node);
814             }
815             return ret;
816         }
817
818
819         /**
820          * @see Iterator#remove
821          */

822         public void remove ()
823         {
824             throw new UnsupportedOperationException JavaDoc();
825         }
826
827
828         /**
829          * Get the first node for iteration.
830          *
831          * <p>This method must derive an initial node for iteration
832          * from a context node.</p>
833          *
834          * @param contextNode the starting node
835          * @return the first node in the iteration
836          * @see #getNextNode
837          */

838         protected abstract Node JavaDoc getFirstNode (Node JavaDoc contextNode);
839
840
841         /**
842          * Get the next node for iteration.
843          *
844          * <p>This method must locate a following node from the
845          * current context node.</p>
846          *
847          * @param contextNode the current node in the iteration
848          * @return the following node in the iteration, or null
849          * if there is none
850          * @see #getFirstNode
851          */

852         protected abstract Node JavaDoc getNextNode (Node JavaDoc contextNode);
853
854
855         /**
856          * Test whether a DOM node is usable by XPath.
857          *
858          * @param node the DOM node to test
859          * @return true if the node is usable, false if it should be
860          * skipped
861          */

862         private boolean isXPathNode (Node JavaDoc node)
863         {
864             // null is usable, because it means end
865
if (node == null)
866                 return true;
867
868             switch (node.getNodeType()) {
869                 case Node.DOCUMENT_FRAGMENT_NODE:
870                 case Node.DOCUMENT_TYPE_NODE:
871                 case Node.ENTITY_NODE:
872                 case Node.ENTITY_REFERENCE_NODE:
873                 case Node.NOTATION_NODE:
874                     return false;
875                 default:
876                     return true;
877             }
878         }
879
880         private Node JavaDoc node;
881     }
882
883
884     
885     ////////////////////////////////////////////////////////////////////
886
// Inner class: iterate over a DOM named node map.
887
////////////////////////////////////////////////////////////////////
888

889
890     /**
891      * An iterator over an attribute list.
892      */

893     private static class AttributeIterator implements Iterator JavaDoc
894     {
895
896         /**
897          * Constructor.
898          *
899          * @param parent the parent DOM element for the attributes.
900          */

901         AttributeIterator (Node JavaDoc parent)
902         {
903             this.map = parent.getAttributes();
904             this.pos = 0;
905             for (int i = this.map.getLength()-1; i >= 0; i--) {
906                 Node JavaDoc node = map.item(i);
907                 if (! "http://www.w3.org/2000/xmlns/".equals(node.getNamespaceURI())) {
908                     this.lastAttribute = i;
909                     break;
910                 }
911             }
912         }
913
914
915         /**
916          * @see Iterator#hasNext
917          */

918         public boolean hasNext ()
919         {
920             return pos <= lastAttribute;
921         }
922
923
924         /**
925          * @see Iterator#next
926          */

927         public Object JavaDoc next ()
928         {
929             Node JavaDoc attr = map.item(pos++);
930             if (attr == null) throw new NoSuchElementException JavaDoc();
931             else if ("http://www.w3.org/2000/xmlns/".equals(attr.getNamespaceURI())) {
932               // XPath doesn't consider namespace declarations to be attributes
933
// so skip it and go to the next one
934
return next();
935             }
936             else return attr;
937         }
938
939
940         /**
941          * @see Iterator#remove
942          */

943         public void remove ()
944         {
945             throw new UnsupportedOperationException JavaDoc();
946         }
947
948
949         private NamedNodeMap JavaDoc map;
950         private int pos;
951         private int lastAttribute = -1;
952
953     }
954
955     /**
956      * Returns the element whose ID is given by elementId.
957      * If no such element exists, returns null.
958      * Attributes with the name "ID" are not of type ID unless so defined.
959      * Attribute types are only known if when the parser understands DTD's or
960      * schemas that declare attributes of type ID. When JAXP is used, you
961      * must call <code>setValidating(true)</code> on the
962      * DocumentBuilderFactory.
963      *
964      * @param object a node from the document in which to look for the id
965      * @param elementId id to look for
966      *
967      * @return element whose ID is given by elementId, or null if no such
968      * element exists in the document or if the implementation
969      * does not know about attribute types
970      * @see javax.xml.parsers.DocumentBuilderFactory
971      */

972     public Object JavaDoc getElementById(Object JavaDoc object, String JavaDoc elementId)
973     {
974         Document JavaDoc doc = (Document JavaDoc)getDocumentNode(object);
975         if (doc != null) return doc.getElementById(elementId);
976         else return null;
977     }
978
979 }
980
981 // end of DocumentNavigator.java
982
Popular Tags