KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > om > NamespaceIterator


1 package net.sf.saxon.om;
2
3 import net.sf.saxon.Configuration;
4 import net.sf.saxon.event.Receiver;
5 import net.sf.saxon.pattern.AnyNodeTest;
6 import net.sf.saxon.pattern.NodeKindTest;
7 import net.sf.saxon.pattern.NodeTest;
8 import net.sf.saxon.trans.XPathException;
9 import net.sf.saxon.type.Type;
10 import net.sf.saxon.value.StringValue;
11 import net.sf.saxon.value.Value;
12
13 import java.util.Set JavaDoc;
14 import java.util.HashSet JavaDoc;
15 import java.util.Iterator JavaDoc;
16
17 /**
18  * This class provides an implementation of the namespace axis over any implementation
19  * of the data model. It relies on element nodes to implement the method
20  * {@link NodeInfo#getDeclaredNamespaces(int[])}
21  */

22 public class NamespaceIterator implements AxisIterator {
23
24     private NodeInfo element;
25     private NodeTest test;
26     private int index;
27     private int position;
28     private NamespaceNodeImpl next;
29     private NamespaceNodeImpl current;
30     private Iterator JavaDoc nsIterator;
31     private int count;
32
33
34     private static final Integer JavaDoc xmlnscode = new Integer JavaDoc(NamespaceConstant.XML_NAMESPACE_CODE);
35
36     public NamespaceIterator(NodeInfo element, NodeTest test) {
37         this.element = element;
38         this.test = test;
39         if (test instanceof AnyNodeTest || test == NodeKindTest.NAMESPACE) {
40             this.test = null;
41         }
42         index = -1;
43
44         Set JavaDoc undeclared = new HashSet JavaDoc(10);
45         Set JavaDoc declared = new HashSet JavaDoc(10);
46         int[] buffer = new int[10];
47         NodeInfo node = element;
48         declared.add(xmlnscode);
49         while (node != null && node.getNodeKind() == Type.ELEMENT) {
50
51             int[] nslist = node.getDeclaredNamespaces(buffer);
52             if (nslist != null) {
53                 for (int i=0; i<nslist.length; i++) {
54                     if (nslist[i] ==-1) {
55                         break;
56                     }
57                     short uriCode = (short)(nslist[i] & 0xffff);
58                     short prefixCode = (short)(nslist[i] >> 16);
59                     if (uriCode == 0) {
60                         // this is an undeclaration
61
undeclared.add(new Integer JavaDoc(prefixCode));
62                     } else {
63                         Integer JavaDoc key = new Integer JavaDoc(prefixCode);
64                         if (!undeclared.contains(key)) {
65                             declared.add(new Integer JavaDoc(nslist[i]));
66                             undeclared.add(key);
67                         }
68                     }
69                 }
70             }
71             node = node.getParent();
72         }
73         count = declared.size();
74         nsIterator = declared.iterator();
75     }
76
77     /**
78      * Get the next item in the sequence.
79      */

80
81     public void advance() {
82         while (nsIterator.hasNext()) {
83             int nscode = ((Integer JavaDoc)nsIterator.next()).intValue();
84             next = new NamespaceNodeImpl(element, nscode, index++);
85             if (test == null || test.matches(next)) {
86                return;
87             }
88         }
89         next = null;
90     }
91
92     /**
93      * Get the next item in the sequence. <BR>
94      *
95      * @return the next Item. If there are no more nodes, return null.
96      */

97
98     public Item next() {
99         if (index == -1) {
100             advance();
101             index = 0;
102         }
103         current = next;
104         if (current == null) {
105             position = -1;
106             return null;
107         }
108         advance();
109         position++;
110         return current;
111     }
112
113     /**
114      * Get the current item in the sequence.
115      *
116      * @return the current item, that is, the item most recently returned by
117      * next()
118      */

119
120     public Item current() {
121         return current;
122     }
123
124     /**
125      * Get the current position
126      *
127      * @return the position of the current item (the item most recently
128      * returned by next()), starting at 1 for the first node
129      */

130
131     public int position() {
132         return position;
133     }
134
135     /**
136      * Get another iterator over the same sequence of items, positioned at the
137      * start of the sequence
138      *
139      * @return a new iterator over the same sequence
140      */

141
142     public SequenceIterator getAnother() {
143         return new NamespaceIterator(element, test);
144     }
145
146     /**
147      * Get properties of this iterator, as a bit-significant integer.
148      *
149      * @return the properties of this iterator. This will be some combination of
150      * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
151      * and {@link LOOKAHEAD}. It is always
152      * acceptable to return the value zero, indicating that there are no known special properties.
153      * It is acceptable for the properties of the iterator to change depending on its state.
154      */

155
156     public int getProperties() {
157         return 0;
158     }
159
160     /**
161      * Get a list of in-scope namespace codes. If an array of namespace codes is needed, without
162      * actually constructing the namespace nodes, a caller may create the NamespaceIterator and then
163      * call this method. The result is an array of integers, each containing a prefix code in the top
164      * half and a uri code in the bottom half. Note that calling this method is destructive: the
165      * iterator is consumed and cannot be used again.
166      */

167
168     public int[] getInScopeNamespaceCodes() {
169         int[] codes = new int[count];
170         int i = 0;
171         while (nsIterator.hasNext()) {
172             codes[i++] = ((Integer JavaDoc)nsIterator.next()).intValue();
173         }
174         return codes;
175     }
176
177     /**
178      * Inner class: a model-independent representation of a namespace node
179      */

180
181     public static class NamespaceNodeImpl implements NodeInfo, FingerprintedNode {
182
183         NodeInfo element;
184         int nscode;
185         int position;
186         int namecode;
187
188         public NamespaceNodeImpl(NodeInfo element, int nscode, int position) {
189             this.element = element;
190             this.nscode = nscode;
191             this.position = position;
192             NamePool pool = element.getNamePool();
193             String JavaDoc prefix = pool.getPrefixFromNamespaceCode(nscode);
194             if ("".equals(prefix)) {
195                 this.namecode = -1;
196             } else {
197                 this.namecode = pool.allocate("", "", prefix);
198             }
199         }
200
201         /**
202          * Get the kind of node. This will be a value such as Type.ELEMENT or Type.ATTRIBUTE
203          *
204          * @return an integer identifying the kind of node. These integer values are the
205          * same as those used in the DOM
206          * @see net.sf.saxon.type.Type
207          */

208
209         public int getNodeKind() {
210             return Type.NAMESPACE;
211         }
212
213         /**
214          * Determine whether this is the same node as another node.
215          * Note: a.isSameNodeInfo(b) if and only if generateId(a)==generateId(b).
216          * This method has the same semantics as isSameNode() in DOM Level 3, but
217          * works on Saxon NodeInfo objects rather than DOM Node objects.
218          *
219          * @param other the node to be compared with this node
220          * @return true if this NodeInfo object and the supplied NodeInfo object represent
221          * the same node in the tree.
222          */

223
224         public boolean isSameNodeInfo(NodeInfo other) {
225             if (!(other instanceof NamespaceNodeImpl)) {
226                 return false;
227             }
228             return element.isSameNodeInfo(((NamespaceNodeImpl)other).element) &&
229                     nscode == ((NamespaceNodeImpl)other).nscode;
230
231         }
232
233         /**
234          * Get the System ID for the node.
235          *
236          * @return the System Identifier of the entity in the source document
237          * containing the node, or null if not known. Note this is not the
238          * same as the base URI: the base URI can be modified by xml:base, but
239          * the system ID cannot.
240          */

241
242         public String JavaDoc getSystemId() {
243             return element.getSystemId();
244         }
245
246         /**
247          * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained
248          * in the node. This will be the same as the System ID unless xml:base has been used.
249          *
250          * @return the base URI of the node
251          */

252
253         public String JavaDoc getBaseURI() {
254             return element.getBaseURI();
255         }
256
257         /**
258          * Get line number
259          *
260          * @return the line number of the node in its original source document; or
261          * -1 if not available
262          */

263
264         public int getLineNumber() {
265             return element.getLineNumber();
266         }
267
268         /**
269          * Determine the relative position of this node and another node, in document order.
270          * The other node will always be in the same document.
271          *
272          * @param other The other node, whose position is to be compared with this
273          * node
274          * @return -1 if this node precedes the other node, +1 if it follows the
275          * other node, or 0 if they are the same node. (In this case,
276          * isSameNode() will always return true, and the two nodes will
277          * produce the same result for generateId())
278          */

279
280         public int compareOrder(NodeInfo other) {
281             if (other instanceof NamespaceNodeImpl && element.isSameNodeInfo(((NamespaceNodeImpl)other).element)) {
282                 // JDK 1.5: return Integer.signum(position - ((NamespaceNodeI)other).position);
283
int c = position - ((NamespaceNodeImpl)other).position;
284                 if (c == 0) return 0;
285                 if (c < 0) return -1;
286                 return +1;
287             } else {
288                 return element.compareOrder(other);
289             }
290         }
291
292         /**
293          * Return the string value of the node. The interpretation of this depends on the type
294          * of node. For a namespace node, it is the namespace URI.
295          *
296          * @return the string value of the node
297          */

298
299         public String JavaDoc getStringValue() {
300             return element.getNamePool().getURIFromURICode((short)(nscode & 0xffff));
301         }
302
303         /**
304          * Get the value of the item as a CharSequence. This is in some cases more efficient than
305          * the version of the method that returns a String.
306          */

307
308         public CharSequence JavaDoc getStringValueCS() {
309             return getStringValue();
310         }
311
312         /**
313          * Get name code. The name code is a coded form of the node name: two nodes
314          * with the same name code have the same namespace URI, the same local name,
315          * and the same prefix. By masking the name code with &0xfffff, you get a
316          * fingerprint: two nodes with the same fingerprint have the same local name
317          * and namespace URI.
318          *
319          * @return an integer name code, which may be used to obtain the actual node
320          * name from the name pool
321          * @see NamePool#allocate allocate
322          * @see NamePool#getFingerprint getFingerprint
323          */

324
325         public int getNameCode() {
326             return namecode;
327         }
328
329         /**
330          * Get fingerprint. The fingerprint is a coded form of the expanded name
331          * of the node: two nodes
332          * with the same name code have the same namespace URI and the same local name.
333          * A fingerprint of -1 should be returned for a node with no name.
334          *
335          * @return an integer fingerprint; two nodes with the same fingerprint have
336          * the same expanded QName
337          */

338
339         public int getFingerprint() {
340             if (namecode == -1) {
341                 return -1;
342             }
343             return namecode & NamePool.FP_MASK;
344         }
345
346         /**
347          * Get the local part of the name of this node. This is the name after the ":" if any.
348          *
349          * @return the local part of the name. For an unnamed node, returns "". Unlike the DOM
350          * interface, this returns the full name in the case of a non-namespaced name.
351          */

352
353         public String JavaDoc getLocalPart() {
354             if (namecode == -1) {
355                 return "";
356             } else {
357                 return element.getNamePool().getLocalName(namecode);
358             }
359         }
360
361         /**
362          * Get the URI part of the name of this node. This is the URI corresponding to the
363          * prefix, or the URI of the default namespace if appropriate.
364          *
365          * @return The URI of the namespace of this node. Since the name of a namespace
366          * node is always an NCName (the namespace prefix), this method always returns "".
367          */

368
369         public String JavaDoc getURI() {
370             return "";
371         }
372
373         /**
374          * Get the display name of this node. For elements and attributes this is [prefix:]localname.
375          * For unnamed nodes, it is an empty string.
376          *
377          * @return The display name of this node. For a node with no name, return
378          * an empty string.
379          */

380
381         public String JavaDoc getDisplayName() {
382             return getLocalPart();
383         }
384
385         /**
386          * Get the prefix of the name of the node. This is defined only for elements and attributes.
387          * If the node has no prefix, or for other kinds of node, return a zero-length string.
388          *
389          * @return The prefix of the name of the node.
390          */

391
392         public String JavaDoc getPrefix() {
393             return "";
394         }
395
396         /**
397          * Get the configuration
398          */

399
400         public Configuration getConfiguration() {
401             return element.getConfiguration();
402         }
403
404         /**
405          * Get the NamePool that holds the namecode for this node
406          *
407          * @return the namepool
408          */

409
410         public NamePool getNamePool() {
411             return element.getNamePool();
412         }
413
414         /**
415          * Get the type annotation of this node, if any.
416          * Returns -1 for kinds of nodes that have no annotation, and for elements annotated as
417          * untyped, and attributes annotated as untypedAtomic.
418          *
419          * @return the type annotation of the node.
420          * @see net.sf.saxon.type.Type
421          */

422
423         public int getTypeAnnotation() {
424             return -1;
425         }
426
427         /**
428          * Get the NodeInfo object representing the parent of this node
429          *
430          * @return the parent of this node; null if this node has no parent
431          */

432
433         public NodeInfo getParent() {
434             return element;
435         }
436
437         /**
438          * Return an iteration over all the nodes reached by the given axis from this node
439          *
440          * @param axisNumber an integer identifying the axis; one of the constants
441          * defined in class net.sf.saxon.om.Axis
442          * @return an AxisIterator that scans the nodes reached by the axis in
443          * turn.
444          * @throws UnsupportedOperationException if the namespace axis is
445          * requested and this axis is not supported for this implementation.
446          * @see Axis
447          */

448
449         public AxisIterator iterateAxis(byte axisNumber) {
450             return iterateAxis(axisNumber, new AnyNodeTest());
451         }
452
453         /**
454          * Return an iteration over all the nodes reached by the given axis from this node
455          * that match a given NodeTest
456          *
457          * @param axisNumber an integer identifying the axis; one of the constants
458          * defined in class net.sf.saxon.om.Axis
459          * @param nodeTest A pattern to be matched by the returned nodes; nodes
460          * that do not match this pattern are not included in the result
461          * @return a NodeEnumeration that scans the nodes reached by the axis in
462          * turn.
463          * @throws UnsupportedOperationException if the namespace axis is
464          * requested and this axis is not supported for this implementation.
465          * @see Axis
466          */

467
468         public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) {
469             switch (axisNumber) {
470                 case Axis.ANCESTOR:
471                     return element.iterateAxis(Axis.ANCESTOR_OR_SELF, nodeTest);
472
473                 case Axis.ANCESTOR_OR_SELF:
474                     if (nodeTest.matches(this)) {
475                         return new PrependIterator(this, element.iterateAxis(Axis.ANCESTOR_OR_SELF, nodeTest));
476                     } else {
477                         return element.iterateAxis(Axis.ANCESTOR_OR_SELF, nodeTest);
478                     }
479
480                 case Axis.ATTRIBUTE:
481                 case Axis.CHILD:
482                 case Axis.DESCENDANT:
483                 case Axis.DESCENDANT_OR_SELF:
484                 case Axis.FOLLOWING_SIBLING:
485                 case Axis.NAMESPACE:
486                 case Axis.PRECEDING_SIBLING:
487                      return EmptyIterator.getInstance();
488
489                 case Axis.FOLLOWING:
490                     return new Navigator.AxisFilter(
491                             new Navigator.FollowingEnumeration(this),
492                             nodeTest);
493
494                 case Axis.PARENT:
495                      if (nodeTest.matches(element)) {
496                          return SingletonIterator.makeIterator(element);
497                      }
498                      return EmptyIterator.getInstance();
499
500                 case Axis.PRECEDING:
501                     return new Navigator.AxisFilter(
502                             new Navigator.PrecedingEnumeration(this, false),
503                             nodeTest);
504
505                 case Axis.SELF:
506                     if (nodeTest.matches(this)) {
507                         return SingletonIterator.makeIterator(this);
508                     }
509                     return EmptyIterator.getInstance();
510
511                 case Axis.PRECEDING_OR_ANCESTOR:
512                     return new Navigator.AxisFilter(
513                             new Navigator.PrecedingEnumeration(this, true),
514                             nodeTest);
515                 default:
516                      throw new IllegalArgumentException JavaDoc("Unknown axis number " + axisNumber);
517             }
518         }
519
520         /**
521          * Get the value of a given attribute of this node
522          *
523          * @param fingerprint The fingerprint of the attribute name
524          * @return the attribute value if it exists or null if not
525          */

526
527         public String JavaDoc getAttributeValue(int fingerprint) {
528             return null;
529         }
530
531         /**
532          * Get the root node of the tree containing this node
533          *
534          * @return the NodeInfo representing the top-level ancestor of this node.
535          * This will not necessarily be a document node
536          */

537
538         public NodeInfo getRoot() {
539             return element.getRoot();
540         }
541
542         /**
543          * Get the root node, if it is a document node.
544          *
545          * @return the DocumentInfo representing the containing document. If this
546          * node is part of a tree that does not have a document node as its
547          * root, return null.
548          */

549
550         public DocumentInfo getDocumentRoot() {
551             return element.getDocumentRoot();
552         }
553
554         /**
555          * Determine whether the node has any children. <br />
556          * Note: the result is equivalent to <br />
557          * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext()
558          *
559          * @return True if the node has one or more children
560          */

561
562         public boolean hasChildNodes() {
563             return false;
564         }
565
566         /**
567          * Get a character string that uniquely identifies this node.
568          * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b)
569          *
570          * @return a string that uniquely identifies this node, across all
571          * documents.
572          */

573
574         public String JavaDoc generateId() {
575             return element.generateId() + 'n' + position;
576         }
577
578         /**
579          * Get the document number of the document containing this node. For a free-standing
580          * orphan node, just return the hashcode.
581          */

582
583         public int getDocumentNumber() {
584             return element.getDocumentNumber();
585         }
586
587         /**
588          * Copy this node to a given outputter
589          *
590          * @param out the Receiver to which the node should be copied
591          * @param whichNamespaces in the case of an element, controls
592          * which namespace nodes should be copied. Values are {@link #NO_NAMESPACES},
593          * {@link #LOCAL_NAMESPACES}, {@link #ALL_NAMESPACES}
594          * @param copyAnnotations indicates whether the type annotations
595          * of element and attribute nodes should be copied
596          * @param locationId If non-zero, identifies the location of the instruction
597          * that requested this copy. If zero, indicates that the location information
598          * for the original node is to be copied; in this case the Receiver must be
599          * a LocationCopier
600          * @throws net.sf.saxon.trans.XPathException
601          *
602          */

603
604         public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException {
605             out.namespace(nscode, 0);
606         }
607
608         /**
609          * Output all namespace nodes associated with this element. Does nothing if
610          * the node is not an element.
611          *
612          * @param out The relevant outputter
613          * @param includeAncestors True if namespaces declared on ancestor
614          */

615
616         public void sendNamespaceDeclarations(Receiver out, boolean includeAncestors) throws XPathException {
617
618         }
619
620         /**
621          * Get all namespace undeclarations and undeclarations defined on this element.
622          *
623          * @param buffer If this is non-null, and the result array fits in this buffer, then the result
624          * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap.
625          * @return An array of integers representing the namespace declarations and undeclarations present on
626          * this element. For a node other than an element, return null. Otherwise, the returned array is a
627          * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The
628          * top half word of each namespace code represents the prefix, the bottom half represents the URI.
629          * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration.
630          * The XML namespace is never included in the list. If the supplied array is larger than required,
631          * then the first unused entry will be set to -1.
632          * <p/>
633          * <p>For a node other than an element, the method returns null.</p>
634          */

635
636         public int[] getDeclaredNamespaces(int[] buffer) {
637             return null;
638         }
639
640         /**
641          * Set the system identifier for this Source.
642          * <p/>
643          * <p>The system identifier is optional if the source does not
644          * get its data from a URL, but it may still be useful to provide one.
645          * The application can use a system identifier, for example, to resolve
646          * relative URIs and to include in error messages and warnings.</p>
647          *
648          * @param systemId The system identifier as a URL string.
649          */

650         public void setSystemId(String JavaDoc systemId) {
651
652         }
653
654         /**
655          * Get the typed value of the item
656          *
657          * @return the typed value of the item. In general this will be a sequence
658          * @throws net.sf.saxon.trans.XPathException
659          * where no typed value is available, e.g. for
660          * an element with complex content
661          */

662
663         public SequenceIterator getTypedValue() throws XPathException {
664             return SingletonIterator.makeIterator(new StringValue(getStringValueCS()));
665         }
666
667         /**
668          * Get the typed value. The result of this method will always be consistent with the method
669          * {@link Item#getTypedValue()}. However, this method is often more convenient and may be
670          * more efficient, especially in the common case where the value is expected to be a singleton.
671          *
672          * @return the typed value. If requireSingleton is set to true, the result will always be an
673          * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic
674          * values.
675          * @since 8.5
676          */

677
678         public Value atomize() throws XPathException {
679             return new StringValue(getStringValueCS());
680         }
681     }
682 }
683
Popular Tags