KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > jdom > NodeWrapper


1 package net.sf.saxon.jdom;
2 import net.sf.saxon.Configuration;
3 import net.sf.saxon.event.Receiver;
4 import net.sf.saxon.om.*;
5 import net.sf.saxon.pattern.AnyNodeTest;
6 import net.sf.saxon.pattern.NodeTest;
7 import net.sf.saxon.style.StandardNames;
8 import net.sf.saxon.trans.XPathException;
9 import net.sf.saxon.type.Type;
10 import net.sf.saxon.value.UntypedAtomicValue;
11 import net.sf.saxon.value.Value;
12 import org.jdom.*;
13
14 import java.util.Iterator JavaDoc;
15 import java.util.List JavaDoc;
16 import java.util.ListIterator JavaDoc;
17 import java.util.ArrayList JavaDoc;
18
19 /**
20   * A node in the XML parse tree representing an XML element, character content, or attribute.<P>
21   * This is the implementation of the NodeInfo interface used as a wrapper for JDOM nodes.
22   * @author Michael H. Kay
23   */

24
25 public class NodeWrapper implements NodeInfo, VirtualNode, SiblingCountingNode {
26
27     protected Object JavaDoc node; // the JDOM node to which this XPath node is mapped; or a List of
28
// adjacent text nodes
29
protected short nodeKind;
30     private NodeWrapper parent; // null means unknown
31
protected DocumentWrapper docWrapper;
32     protected int index; // -1 means unknown
33
//private int span = 1; // number of adjacent JDOM nodes mapped to one text wrapper node
34

35     /**
36      * This constructor is protected: nodes should be created using the wrap
37      * factory method on the DocumentWrapper class
38      * @param node The JDOM node to be wrapped
39      * @param parent The NodeWrapper that wraps the parent of this node
40      * @param index Position of this node among its siblings
41      */

42     protected NodeWrapper(Object JavaDoc node, NodeWrapper parent, int index) {
43         this.node = node;
44         this.parent = parent;
45         this.index = index;
46     }
47
48     /**
49      * Factory method to wrap a JDOM node with a wrapper that implements the Saxon
50      * NodeInfo interface.
51      * @param node The JDOM node
52      * @param docWrapper The wrapper for the Document containing this node
53      * @return The new wrapper for the supplied node
54      */

55     protected NodeWrapper makeWrapper(Object JavaDoc node, DocumentWrapper docWrapper) {
56         return makeWrapper(node, docWrapper, null, -1);
57     }
58
59     /**
60      * Factory method to wrap a JDOM node with a wrapper that implements the Saxon
61      * NodeInfo interface.
62      * @param node The JDOM node
63      * @param docWrapper The wrapper for the Document containing this node
64      * @param parent The wrapper for the parent of the JDOM node
65      * @param index The position of this node relative to its siblings
66      * @return The new wrapper for the supplied node
67      */

68
69     protected NodeWrapper makeWrapper(Object JavaDoc node, DocumentWrapper docWrapper,
70                                       NodeWrapper parent, int index) {
71         NodeWrapper wrapper;
72         if (node instanceof Document) {
73             return docWrapper;
74         } else if (node instanceof Element) {
75             wrapper = new NodeWrapper(node, parent, index);
76             wrapper.nodeKind = Type.ELEMENT;
77         } else if (node instanceof Attribute) {
78             wrapper = new NodeWrapper(node, parent, index);
79             wrapper.nodeKind = Type.ATTRIBUTE;
80         } else if (node instanceof String JavaDoc || node instanceof Text) {
81             wrapper = new NodeWrapper(node, parent, index);
82             wrapper.nodeKind = Type.TEXT;
83         } else if (node instanceof Comment) {
84             wrapper = new NodeWrapper(node, parent, index);
85             wrapper.nodeKind = Type.COMMENT;
86         } else if (node instanceof ProcessingInstruction) {
87             wrapper = new NodeWrapper(node, parent, index);
88             wrapper.nodeKind = Type.PROCESSING_INSTRUCTION;
89         } else if (node instanceof Namespace) {
90             throw new IllegalArgumentException JavaDoc("Cannot wrap JDOM namespace objects");
91         } else {
92             throw new IllegalArgumentException JavaDoc("Bad node type in JDOM! " + node.getClass() + " instance " + node.toString());
93         }
94         wrapper.docWrapper = docWrapper;
95         return wrapper;
96     }
97
98     /**
99     * Get the underlying JDOM node, to implement the VirtualNode interface
100     */

101
102     public Object JavaDoc getUnderlyingNode() {
103         if (node instanceof List JavaDoc) {
104             return ((List JavaDoc)node).get(0);
105         } else {
106             return node;
107         }
108     }
109
110     /**
111      * Get the configuration
112      */

113
114     public Configuration getConfiguration() {
115         return docWrapper.getConfiguration();
116     }
117
118     /**
119      * Get the name pool for this node
120      * @return the NamePool
121      */

122
123     public NamePool getNamePool() {
124         return docWrapper.getNamePool();
125     }
126
127     /**
128     * Return the type of node.
129     * @return one of the values Node.ELEMENT, Node.TEXT, Node.ATTRIBUTE, etc.
130     */

131
132     public int getNodeKind() {
133         return nodeKind;
134     }
135
136     /**
137     * Get the typed value of the item
138     */

139
140     public SequenceIterator getTypedValue() {
141         return SingletonIterator.makeIterator(new UntypedAtomicValue(getStringValueCS()));
142     }
143
144     /**
145      * Get the typed value. The result of this method will always be consistent with the method
146      * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be
147      * more efficient, especially in the common case where the value is expected to be a singleton.
148      *
149      * @return the typed value. If requireSingleton is set to true, the result will always be an
150      * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic
151      * values.
152      * @since 8.5
153      */

154
155     public Value atomize() throws XPathException {
156         return new UntypedAtomicValue(getStringValueCS());
157     }
158
159     /**
160     * Get the type annotation
161     * @return -1 (there is no type annotation)
162     */

163
164     public int getTypeAnnotation() {
165         return -1;
166     }
167
168     /**
169     * Determine whether this is the same node as another node. <br />
170     * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b)
171     * @return true if this Node object and the supplied Node object represent the
172     * same node in the tree.
173     */

174
175     public boolean isSameNodeInfo(NodeInfo other) {
176         if (!(other instanceof NodeWrapper)) {
177             return false;
178         }
179         NodeWrapper ow = (NodeWrapper)other;
180 // if (node instanceof Namespace) {
181
// return this.getLocalPart().equals(ow.getLocalPart()) && this.getParent().isSameNodeInfo(ow.getParent());
182
// }
183
return node.equals(ow.node);
184     }
185
186     /**
187     * Get the System ID for the node.
188     * @return the System Identifier of the entity in the source document containing the node,
189     * or null if not known. Note this is not the same as the base URI: the base URI can be
190     * modified by xml:base, but the system ID cannot.
191     */

192
193     public String JavaDoc getSystemId() {
194         return docWrapper.baseURI;
195     }
196
197     public void setSystemId(String JavaDoc uri) {
198         docWrapper.baseURI = uri;
199     }
200
201     /**
202      * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained
203      * in the node. In the JDOM model, base URIs are held only an the document level.
204     */

205
206     public String JavaDoc getBaseURI() {
207         if (getNodeKind() == Type.NAMESPACE) {
208             return null;
209         }
210         NodeInfo n = this;
211         if (getNodeKind() != Type.ELEMENT) {
212             n = getParent();
213         }
214         // Look for an xml:base attribute
215
while (n != null) {
216             String JavaDoc xmlbase = n.getAttributeValue(StandardNames.XML_BASE);
217             if (xmlbase != null) {
218                 return xmlbase;
219             }
220             n = n.getParent();
221         }
222         // if not found, return the base URI of the document node
223
return docWrapper.baseURI;
224     }
225
226     /**
227     * Get line number
228     * @return the line number of the node in its original source document; or -1 if not available.
229      * Always returns -1 in this implementation.
230     */

231
232     public int getLineNumber() {
233         return -1;
234     }
235
236     /**
237     * Determine the relative position of this node and another node, in document order.
238     * The other node will always be in the same document.
239     * @param other The other node, whose position is to be compared with this node
240     * @return -1 if this node precedes the other node, +1 if it follows the other
241     * node, or 0 if they are the same node. (In this case, isSameNode() will always
242     * return true, and the two nodes will produce the same result for generateId())
243     */

244
245     public int compareOrder(NodeInfo other) {
246         if (other instanceof SiblingCountingNode) {
247             return Navigator.compareOrder(this, (SiblingCountingNode)other);
248         } else {
249             // it must be a namespace node
250
return -other.compareOrder(this);
251         }
252     }
253
254     /**
255     * Return the string value of the node. The interpretation of this depends on the type
256     * of node. For an element it is the accumulated character content of the element,
257     * including descendant elements.
258     * @return the string value of the node
259     */

260
261     public String JavaDoc getStringValue() {
262         return getStringValueCS().toString();
263     }
264
265     /**
266      * Get the value of the item as a CharSequence. This is in some cases more efficient than
267      * the version of the method that returns a String.
268      */

269
270     public CharSequence JavaDoc getStringValueCS() {
271         if (node instanceof List JavaDoc) {
272             // This wrapper is mapped to a list of adjacent text nodes
273
List JavaDoc nodes = (List JavaDoc)node;
274             FastStringBuffer fsb = new FastStringBuffer(100);
275             for (int i=0; i<nodes.size(); i++) {
276                 Text o = (Text)nodes.get(i);
277                 fsb.append(getStringValue(o));
278             }
279             return fsb;
280         } else {
281             return getStringValue(node);
282         }
283     }
284
285     /**
286      * Supporting method to get the string value of a node
287      */

288
289     private static String JavaDoc getStringValue(Object JavaDoc node) {
290         if (node instanceof Document) {
291             List JavaDoc children1 = ((Document)node).getContent();
292             FastStringBuffer sb1 = new FastStringBuffer(2048);
293             expandStringValue(children1, sb1);
294             return sb1.toString();
295         } else if (node instanceof Element) {
296             return ((Element)node).getValue();
297         } else if (node instanceof Attribute) {
298             return ((Attribute)node).getValue();
299         } else if (node instanceof Text) {
300             return ((Text)node).getText();
301         } else if (node instanceof String JavaDoc) {
302             return (String JavaDoc)node;
303         } else if (node instanceof Comment) {
304             return ((Comment)node).getText();
305         } else if (node instanceof ProcessingInstruction) {
306             return ((ProcessingInstruction)node).getData();
307         } else if (node instanceof Namespace) {
308             return ((Namespace)node).getURI();
309         } else {
310             return "";
311         }
312     }
313
314     /**
315      * Get the string values of all the nodes in a list, concatenating the values into
316      * a supplied string buffer
317      * @param list the list containing the nodes
318      * @param sb the StringBuffer to contain the result
319      */

320     private static void expandStringValue(List JavaDoc list, FastStringBuffer sb) {
321         Iterator JavaDoc iter = list.iterator();
322         while (iter.hasNext()) {
323             Object JavaDoc obj = iter.next();
324             if (obj instanceof Element) {
325                 sb.append(((Element)obj).getValue());
326             } else if (obj instanceof Text) {
327                 sb.append(((Text)obj).getText());
328             } else if (obj instanceof EntityRef) {
329                 throw new IllegalStateException JavaDoc("Unexpanded entity in JDOM tree");
330             } else if (obj instanceof DocType) {
331                 // do nothing: can happen in JDOM beta 10
332
} else {
333                 throw new AssertionError JavaDoc("Unknown JDOM node type");
334             }
335         }
336     }
337
338     /**
339     * Get name code. The name code is a coded form of the node name: two nodes
340     * with the same name code have the same namespace URI, the same local name,
341     * and the same prefix. By masking the name code with &0xfffff, you get a
342     * fingerprint: two nodes with the same fingerprint have the same local name
343     * and namespace URI.
344     * @see net.sf.saxon.om.NamePool#allocate allocate
345     */

346
347     public int getNameCode() {
348         switch (nodeKind) {
349             case Type.ELEMENT:
350             case Type.ATTRIBUTE:
351             case Type.PROCESSING_INSTRUCTION:
352             case Type.NAMESPACE:
353                 return docWrapper.getNamePool().allocate(getPrefix(),
354                                                     getURI(),
355                                                     getLocalPart());
356             default:
357                 return -1;
358         }
359     }
360
361     /**
362     * Get fingerprint. The fingerprint is a coded form of the expanded name
363     * of the node: two nodes
364     * with the same name code have the same namespace URI and the same local name.
365     * A fingerprint of -1 should be returned for a node with no name.
366     */

367
368     public int getFingerprint() {
369         int nc = getNameCode();
370         if (nc == -1) {
371             return -1;
372         } else {
373             return nc&0xfffff;
374         }
375     }
376
377     /**
378     * Get the local part of the name of this node. This is the name after the ":" if any.
379     * @return the local part of the name. For an unnamed node, returns "".
380     */

381
382     public String JavaDoc getLocalPart() {
383         switch (nodeKind) {
384             case Type.ELEMENT:
385                 return ((Element)node).getName();
386             case Type.ATTRIBUTE:
387                 return ((Attribute)node).getName();
388             case Type.TEXT:
389             case Type.COMMENT:
390             case Type.DOCUMENT:
391                 return "";
392             case Type.PROCESSING_INSTRUCTION:
393                 return ((ProcessingInstruction)node).getTarget();
394             case Type.NAMESPACE:
395                 return ((Namespace)node).getPrefix();
396             default:
397                 return null;
398         }
399     }
400
401     /**
402     * Get the prefix part of the name of this node. This is the name before the ":" if any.
403      * (Note, this method isn't required as part of the NodeInfo interface.)
404     * @return the prefix part of the name. For an unnamed node, return an empty string.
405     */

406
407     public String JavaDoc getPrefix() {
408         switch (nodeKind) {
409             case Type.ELEMENT:
410                 return ((Element)node).getNamespacePrefix();
411             case Type.ATTRIBUTE:
412                 return ((Attribute)node).getNamespacePrefix();
413             default:
414                 return "";
415         }
416     }
417
418     /**
419     * Get the URI part of the name of this node. This is the URI corresponding to the
420     * prefix, or the URI of the default namespace if appropriate.
421      * @return The URI of the namespace of this node. For an unnamed node,
422      * or for a node with an empty prefix, return an empty
423      * string.
424     */

425
426     public String JavaDoc getURI() {
427         switch (nodeKind) {
428             case Type.ELEMENT:
429                 return ((Element)node).getNamespaceURI();
430             case Type.ATTRIBUTE:
431                 return ((Attribute)node).getNamespaceURI();
432             default:
433                 return "";
434         }
435     }
436
437     /**
438     * Get the display name of this node. For elements and attributes this is [prefix:]localname.
439     * For unnamed nodes, it is an empty string.
440     * @return The display name of this node.
441     * For a node with no name, return an empty string.
442     */

443
444     public String JavaDoc getDisplayName() {
445         switch (nodeKind) {
446             case Type.ELEMENT:
447                 return ((Element)node).getQualifiedName();
448             case Type.ATTRIBUTE:
449                 return ((Attribute)node).getQualifiedName();
450             case Type.PROCESSING_INSTRUCTION:
451             case Type.NAMESPACE:
452                 return getLocalPart();
453             default:
454                 return "";
455
456         }
457     }
458
459     /**
460     * Get the NodeInfo object representing the parent of this node
461     */

462
463     public NodeInfo getParent() {
464         if (parent==null) {
465             if (node instanceof Element) {
466                 if (((Element)node).isRootElement()) {
467                     parent = makeWrapper(((Element)node).getDocument(), docWrapper);
468                 } else {
469                     parent = makeWrapper(((Element)node).getParent(), docWrapper);
470                 }
471             } else if (node instanceof Text) {
472                 parent = makeWrapper(((Text)node).getParent(), docWrapper);
473             } else if (node instanceof Comment) {
474                 parent = makeWrapper(((Comment)node).getParent(), docWrapper);
475             } else if (node instanceof ProcessingInstruction) {
476                 parent = makeWrapper(((ProcessingInstruction)node).getParent(), docWrapper);
477             } else if (node instanceof Attribute) {
478                 parent = makeWrapper(((Attribute)node).getParent(), docWrapper);
479             } else if (node instanceof Document) {
480                 parent = null;
481             } else if (node instanceof Namespace) {
482                 throw new UnsupportedOperationException JavaDoc("Cannot find parent of JDOM namespace node");
483             } else {
484                 throw new IllegalStateException JavaDoc("Unknown JDOM node type " + node.getClass());
485             }
486         }
487         return parent;
488     }
489
490     /**
491      * Get the index position of this node among its siblings (starting from 0)
492      * In the case of a text node that maps to several adjacent siblings in the JDOM,
493      * the numbering actually refers to the position of the underlying JDOM nodes;
494      * thus the sibling position for the text node is that of the first JDOM node
495      * to which it relates, and the numbering of subsequent XPath nodes is not necessarily
496      * consecutive.
497      */

498
499     public int getSiblingPosition() {
500         if (index == -1) {
501             int ix = 0;
502             getParent();
503             AxisIterator iter;
504             switch (nodeKind) {
505                 case Type.ELEMENT:
506                 case Type.TEXT:
507                 case Type.COMMENT:
508                 case Type.PROCESSING_INSTRUCTION:
509                     iter = parent.iterateAxis(Axis.CHILD);
510                     break;
511                 case Type.ATTRIBUTE:
512                     iter = parent.iterateAxis(Axis.ATTRIBUTE);
513                     break;
514                 case Type.NAMESPACE:
515                     iter = parent.iterateAxis(Axis.NAMESPACE);
516                     break;
517                 default:
518                     index = 0;
519                     return index;
520             }
521             while (true) {
522                 NodeInfo n = (NodeInfo)iter.next();
523                 if (n == null) {
524                     break;
525                 }
526                 if (n.isSameNodeInfo(this)) {
527                     index = ix;
528                     return index;
529                 }
530                 if (((NodeWrapper)n).node instanceof List JavaDoc) {
531                     ix += ((List JavaDoc)(((NodeWrapper)n).node)).size();
532                 } else {
533                     ix++;
534                 }
535             }
536             throw new IllegalStateException JavaDoc("JDOM node not linked to parent node");
537         }
538         return index;
539     }
540
541     /**
542     * Return an iteration over the nodes reached by the given axis from this node
543     * @param axisNumber the axis to be used
544     * @return a SequenceIterator that scans the nodes reached by the axis in turn.
545     */

546
547     public AxisIterator iterateAxis(byte axisNumber) {
548         return iterateAxis(axisNumber, AnyNodeTest.getInstance());
549     }
550
551     /**
552     * Return an iteration over the nodes reached by the given axis from this node
553     * @param axisNumber the axis to be used
554     * @param nodeTest A pattern to be matched by the returned nodes
555     * @return a SequenceIterator that scans the nodes reached by the axis in turn.
556     */

557
558     public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) {
559         switch (axisNumber) {
560             case Axis.ANCESTOR:
561                 if (nodeKind==Type.DOCUMENT) return EmptyIterator.getInstance();
562                 return new Navigator.AxisFilter(
563                             new Navigator.AncestorEnumeration(this, false),
564                             nodeTest);
565
566             case Axis.ANCESTOR_OR_SELF:
567                 if (nodeKind==Type.DOCUMENT) return EmptyIterator.getInstance();
568                 return new Navigator.AxisFilter(
569                             new Navigator.AncestorEnumeration(this, true),
570                             nodeTest);
571
572             case Axis.ATTRIBUTE:
573                 if (nodeKind!=Type.ELEMENT) return EmptyIterator.getInstance();
574                 return new Navigator.AxisFilter(
575                             new AttributeEnumeration(this),
576                             nodeTest);
577
578             case Axis.CHILD:
579                 if (hasChildNodes()) {
580                     return new Navigator.AxisFilter(
581                             new ChildEnumeration(this, true, true),
582                             nodeTest);
583                 } else {
584                     return EmptyIterator.getInstance();
585                 }
586
587             case Axis.DESCENDANT:
588                 if (hasChildNodes()) {
589                     return new Navigator.AxisFilter(
590                             new Navigator.DescendantEnumeration(this, false, true),
591                             nodeTest);
592                 } else {
593                     return EmptyIterator.getInstance();
594                 }
595
596             case Axis.DESCENDANT_OR_SELF:
597                  return new Navigator.AxisFilter(
598                             new Navigator.DescendantEnumeration(this, true, true),
599                             nodeTest);
600
601             case Axis.FOLLOWING:
602                  return new Navigator.AxisFilter(
603                             new Navigator.FollowingEnumeration(this),
604                             nodeTest);
605
606             case Axis.FOLLOWING_SIBLING:
607                  switch (nodeKind) {
608                     case Type.DOCUMENT:
609                     case Type.ATTRIBUTE:
610                     case Type.NAMESPACE:
611                         return EmptyIterator.getInstance();
612                     default:
613                         return new Navigator.AxisFilter(
614                             new ChildEnumeration(this, false, true),
615                             nodeTest);
616                  }
617
618             case Axis.NAMESPACE:
619                  if (nodeKind!=Type.ELEMENT) {
620                      return EmptyIterator.getInstance();
621                  }
622                  return new NamespaceIterator(this, nodeTest);
623
624             case Axis.PARENT:
625                  getParent();
626                  if (parent==null) return EmptyIterator.getInstance();
627                  if (nodeTest.matches(parent)) {
628                     return SingletonIterator.makeIterator(parent);
629                  }
630                  return EmptyIterator.getInstance();
631
632             case Axis.PRECEDING:
633                  return new Navigator.AxisFilter(
634                             new Navigator.PrecedingEnumeration(this, false),
635                             nodeTest);
636
637             case Axis.PRECEDING_SIBLING:
638                  switch (nodeKind) {
639                     case Type.DOCUMENT:
640                     case Type.ATTRIBUTE:
641                     case Type.NAMESPACE:
642                         return EmptyIterator.getInstance();
643                     default:
644                         return new Navigator.AxisFilter(
645                             new ChildEnumeration(this, false, false),
646                             nodeTest);
647                  }
648
649             case Axis.SELF:
650                  if (nodeTest.matches(this)) {
651                      return SingletonIterator.makeIterator(this);
652                  }
653                  return EmptyIterator.getInstance();
654
655             case Axis.PRECEDING_OR_ANCESTOR:
656                  return new Navigator.AxisFilter(
657                             new Navigator.PrecedingEnumeration(this, true),
658                             nodeTest);
659
660             default:
661                  throw new IllegalArgumentException JavaDoc("Unknown axis number " + axisNumber);
662         }
663     }
664
665     /**
666     * Get the value of a given attribute of this node
667     * @param fingerprint The fingerprint of the attribute name
668     * @return the attribute value if it exists, or null if not
669     */

670
671     public String JavaDoc getAttributeValue(int fingerprint) {
672         if (nodeKind==Type.ELEMENT) {
673             NamePool pool = docWrapper.getNamePool();
674             String JavaDoc uri = pool.getURI(fingerprint);
675             String JavaDoc local = pool.getLocalName(fingerprint);
676             return ((Element)node).getAttributeValue(local,
677                     ( uri.equals(NamespaceConstant.XML) ?
678                             Namespace.XML_NAMESPACE :
679                             Namespace.getNamespace(uri)));
680                 // JDOM doesn't allow getNamespace() on the XML namespace URI
681
}
682         return null;
683     }
684
685     /**
686     * Get the root node - always a document node with this tree implementation
687     * @return the NodeInfo representing the containing document
688     */

689
690     public NodeInfo getRoot() {
691         return docWrapper;
692     }
693
694     /**
695     * Get the root (document) node
696     * @return the DocumentInfo representing the containing document
697     */

698
699     public DocumentInfo getDocumentRoot() {
700         return docWrapper;
701     }
702
703     /**
704     * Determine whether the node has any children. <br />
705     * Note: the result is equivalent to <br />
706     * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext()
707     */

708
709     public boolean hasChildNodes() {
710         switch (nodeKind) {
711             case Type.DOCUMENT:
712                 return true;
713             case Type.ELEMENT:
714                 return !((Element)node).getContent().isEmpty();
715             default:
716                 return false;
717         }
718     }
719     /**
720     * Get a character string that uniquely identifies this node.
721     * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b)
722     * @return a string that uniquely identifies this node, across all
723     * documents
724     */

725
726     public String JavaDoc generateId() {
727         return Navigator.getSequentialKey(this);
728     }
729
730     /**
731      * Get the document number of the document containing this node. For a free-standing
732      * orphan node, just return the hashcode.
733      */

734
735     public int getDocumentNumber() {
736         return getDocumentRoot().getDocumentNumber();
737     }
738
739     /**
740     * Copy this node to a given outputter (deep copy)
741     */

742
743     public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException {
744         Navigator.copy(this, out, docWrapper.getNamePool(), whichNamespaces, copyAnnotations, locationId);
745     }
746
747     /**
748     * Output all namespace nodes associated with this element. Does nothing if
749     * the node is not an element.
750     * @param out The relevant outputter
751      * @param includeAncestors True if namespaces declared on ancestor elements must
752      */

753
754     public void sendNamespaceDeclarations(Receiver out, boolean includeAncestors)
755         throws XPathException {
756         Navigator.sendNamespaceDeclarations(this, out, includeAncestors);
757     }
758
759     /**
760      * Get all namespace undeclarations and undeclarations defined on this element.
761      *
762      * @param buffer If this is non-null, and the result array fits in this buffer, then the result
763      * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap.
764      * @return An array of integers representing the namespace declarations and undeclarations present on
765      * this element. For a node other than an element, return null. Otherwise, the returned array is a
766      * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The
767      * top half word of each namespace code represents the prefix, the bottom half represents the URI.
768      * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration.
769      * The XML namespace is never included in the list. If the supplied array is larger than required,
770      * then the first unused entry will be set to -1.
771      * <p/>
772      * <p>For a node other than an element, the method returns null.</p>
773      */

774
775     public int[] getDeclaredNamespaces(int[] buffer) {
776         if (node instanceof Element) {
777             Element elem = (Element)node;
778             List JavaDoc addl = elem.getAdditionalNamespaces();
779             int size = addl.size() + 1;
780             int[] result = (size <= buffer.length ? buffer : new int[size]);
781             NamePool pool = getNamePool();
782             Namespace ns = elem.getNamespace();
783             String JavaDoc prefix = ns.getPrefix();
784             String JavaDoc uri = ns.getURI();
785             result[0] = pool.allocateNamespaceCode(prefix, uri);
786             int i = 1;
787             if (addl.size() > 0) {
788                 Iterator JavaDoc itr = addl.iterator();
789                 while (itr.hasNext()) {
790                     ns = (Namespace) itr.next();
791                     result[i++] = pool.allocateNamespaceCode(ns.getPrefix(), ns.getURI());
792                 }
793             }
794             if (size < buffer.length) {
795                 result[size] = -1;
796             }
797             return result;
798         } else {
799             return null;
800         }
801     }
802     ///////////////////////////////////////////////////////////////////////////////
803
// Axis enumeration classes
804
///////////////////////////////////////////////////////////////////////////////
805

806
807     private final class AttributeEnumeration extends Navigator.BaseEnumeration {
808
809         private Iterator JavaDoc atts;
810         private int ix = 0;
811         private NodeWrapper start;
812
813         public AttributeEnumeration(NodeWrapper start) {
814             this.start = start;
815             atts = ((Element)start.node).getAttributes().iterator();
816         }
817
818         public void advance() {
819             if (atts.hasNext()) {
820                 current = makeWrapper(atts.next(), docWrapper, start, ix++);
821             } else {
822                 current = null;
823             }
824         }
825
826         public SequenceIterator getAnother() {
827             return new AttributeEnumeration(start);
828         }
829
830     } // end of class AttributeEnumeration
831

832
833     /**
834     * The class ChildEnumeration handles not only the child axis, but also the
835     * following-sibling and preceding-sibling axes. It can also iterate the children
836     * of the start node in reverse order, something that is needed to support the
837     * preceding and preceding-or-ancestor axes (the latter being used by xsl:number)
838     */

839
840     private final class ChildEnumeration extends Navigator.BaseEnumeration {
841
842         private NodeWrapper start;
843         private NodeWrapper commonParent;
844         private ListIterator JavaDoc children;
845         private int ix = 0;
846         private boolean downwards; // iterate children of start node (not siblings)
847
private boolean forwards; // iterate in document order (not reverse order)
848

849         public ChildEnumeration(NodeWrapper start,
850                                 boolean downwards, boolean forwards) {
851             this.start = start;
852             this.downwards = downwards;
853             this.forwards = forwards;
854
855             if (downwards) {
856                 commonParent = start;
857             } else {
858                 commonParent = (NodeWrapper)start.getParent();
859             }
860
861             if (commonParent.getNodeKind()==Type.DOCUMENT) {
862                 children = ((Document)commonParent.node).getContent().listIterator();
863             } else {
864                 children = ((Element)commonParent.node).getContent().listIterator();
865             }
866
867             if (downwards) {
868                 if (!forwards) {
869                     // backwards enumeration: go to the end
870
while (children.hasNext()) {
871                         children.next();
872                         ix++;
873                     }
874                 }
875             } else {
876                 ix = start.getSiblingPosition();
877                 // find the start node among the list of siblings
878
Object JavaDoc n = null;
879                 if (forwards) {
880                     for (int i=0; i<=ix; i++) {
881                         n = children.next();
882                     }
883                     if (n instanceof Text) {
884                         // move to the last of a sequence of adjacent text nodes
885
boolean atEnd = false;
886                         while (n instanceof Text) {
887                             if (children.hasNext()) {
888                                 n = children.next();
889                                 ix++;
890                             } else {
891                                 atEnd = true;
892                                 break;
893                             }
894                         }
895                         if (!atEnd) {
896                             children.previous();
897                         }
898                     } else {
899                         ix++;
900                     }
901                 } else {
902                     for (int i=0; i<ix; i++) {
903                         children.next();
904                     }
905                     ix--;
906                 }
907             }
908         }
909
910         public void advance() {
911             if (forwards) {
912                 if (children.hasNext()) {
913                     Object JavaDoc nextChild = children.next();
914                     if (nextChild instanceof DocType) {
915                         advance();
916                         return;
917                     }
918                     if (nextChild instanceof EntityRef) {
919                         throw new IllegalStateException JavaDoc("Unexpanded entity in JDOM tree");
920                     } else if (nextChild instanceof Text) {
921                         // handle possible adjacent text nodes
922
if (isAtomizing()) {
923                             FastStringBuffer fsb = new FastStringBuffer(100);
924                             fsb.append(getStringValue(node));
925                             while (children.hasNext()) {
926                                 Object JavaDoc n = children.next();
927                                 if (n instanceof Text) {
928                                     fsb.append(getStringValue(n));
929                                     ix++;
930                                 } else {
931                                     // we've looked ahead too far
932
children.previous();
933                                     break;
934                                 }
935                             }
936                             current = new UntypedAtomicValue(fsb);
937                         } else {
938                             current = makeWrapper(nextChild, docWrapper, commonParent, ix++);
939                             List JavaDoc list = null;
940                             while (children.hasNext()) {
941                                 Object JavaDoc n = children.next();
942                                 if (n instanceof Text) {
943                                     if (list == null) {
944                                         list = new ArrayList JavaDoc(4);
945                                         list.add(((NodeWrapper)current).node);
946                                     }
947                                     list.add(n);
948                                     ix++;
949                                 } else {
950                                     // we've looked ahead too far
951
children.previous();
952                                     break;
953                                 }
954                             }
955                             if (list != null) {
956                                 ((NodeWrapper)current).node = list;
957                             }
958                         }
959                     } else {
960                         if (isAtomizing()) {
961                             current = new UntypedAtomicValue(getStringValue(node));
962                         } else {
963                             current = makeWrapper(nextChild, docWrapper, commonParent, ix++);
964                         }
965                     }
966                 } else {
967                     current = null;
968                 }
969             } else { // backwards
970
if (children.hasPrevious()) {
971                     Object JavaDoc nextChild = children.previous();
972                     if (nextChild instanceof DocType) {
973                         advance();
974                         return;
975                     }
976                     if (nextChild instanceof EntityRef) {
977                         throw new IllegalStateException JavaDoc("Unexpanded entity in JDOM tree");
978                     } else if (nextChild instanceof Text) {
979                         // handle possible adjacent text nodes
980
if (isAtomizing()) {
981                             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(100);
982                             sb.insert(0, getStringValue(nextChild));
983                             while (children.hasPrevious()) {
984                                 Object JavaDoc n = children.previous();
985                                 if (n instanceof Text) {
986                                     sb.insert(0, getStringValue(n));
987                                     ix--;
988                                 } else {
989                                     // we've looked ahead too far
990
children.next();
991                                     break;
992                                 }
993                             }
994                             current = new UntypedAtomicValue(sb);
995                         } else {
996                             current = makeWrapper(nextChild, docWrapper, commonParent, ix--);
997                             List JavaDoc list = null;
998                             while (children.hasPrevious()) {
999                                 Object JavaDoc n = children.previous();
1000                                if (n instanceof Text) {
1001                                    if (list == null) {
1002                                        list = new ArrayList JavaDoc(4);
1003                                        list.add(((NodeWrapper)current).node);
1004                                    }
1005                                    list.add(0, n);
1006                                    ix--;
1007                                } else {
1008                                    // we've looked ahead too far
1009
children.next();
1010                                    break;
1011                                }
1012                            }
1013                            if (list != null) {
1014                                ((NodeWrapper)current).node = list;
1015                            }
1016                        }
1017                    } else {
1018                        if (isAtomizing()) {
1019                            current = new UntypedAtomicValue(getStringValue(node));
1020                        } else {
1021                            current = makeWrapper(nextChild, docWrapper, commonParent, ix--);
1022                        }
1023                    }
1024                } else {
1025                    current = null;
1026                }
1027            }
1028        }
1029
1030        public SequenceIterator getAnother() {
1031            return new ChildEnumeration(start, downwards, forwards);
1032        }
1033
1034    } // end of class ChildEnumeration
1035

1036}
1037
1038//
1039
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
1040
// you may not use this file except in compliance with the License. You may obtain a copy of the
1041
// License at http://www.mozilla.org/MPL/
1042
//
1043
// Software distributed under the License is distributed on an "AS IS" basis,
1044
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
1045
// See the License for the specific language governing rights and limitations under the License.
1046
//
1047
// The Original Code is: all this file.
1048
//
1049
// The Initial Developer of the Original Code is Michael Kay
1050
//
1051
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
1052
//
1053
// Contributor(s): none.
1054
//
1055
Popular Tags