001: package net.sf.saxon.om;
002:
003: import net.sf.saxon.Configuration;
004: import net.sf.saxon.event.Receiver;
005: import net.sf.saxon.pattern.AnyNodeTest;
006: import net.sf.saxon.pattern.NodeKindTest;
007: import net.sf.saxon.pattern.NodeTest;
008: import net.sf.saxon.sort.IntHashSet;
009: import net.sf.saxon.sort.IntIterator;
010: import net.sf.saxon.trans.XPathException;
011: import net.sf.saxon.type.Type;
012: import net.sf.saxon.value.StringValue;
013: import net.sf.saxon.value.Value;
014:
015: /**
016: * This class provides an implementation of the namespace axis over any implementation
017: * of the data model. It relies on element nodes to implement the method
018: * {@link NodeInfo#getDeclaredNamespaces(int[])}
019: */
020: public class NamespaceIterator implements AxisIterator {
021:
022: private NodeInfo element;
023: private NodeTest test;
024: private int index;
025: private int position;
026: private NamespaceNodeImpl next;
027: private NamespaceNodeImpl current;
028: private IntIterator nsIterator;
029: private int count;
030:
031: //private static final Integer xmlnscode = new Integer(NamespaceConstant.XML_NAMESPACE_CODE);
032:
033: public NamespaceIterator(NodeInfo element, NodeTest test) {
034: this .element = element;
035: this .test = test;
036: if (test instanceof AnyNodeTest
037: || test == NodeKindTest.NAMESPACE) {
038: this .test = null;
039: }
040: index = -1;
041:
042: IntHashSet undeclared = new IntHashSet(8);
043: IntHashSet declared = new IntHashSet(8);
044: int[] buffer = new int[8];
045: NodeInfo node = element;
046: declared.add(NamespaceConstant.XML_NAMESPACE_CODE);
047: while (node != null && node.getNodeKind() == Type.ELEMENT) {
048:
049: int[] nslist = node.getDeclaredNamespaces(buffer);
050: if (nslist != null) {
051: for (int i = 0; i < nslist.length; i++) {
052: if (nslist[i] == -1) {
053: break;
054: }
055: short uriCode = (short) (nslist[i] & 0xffff);
056: short prefixCode = (short) (nslist[i] >> 16);
057: if (uriCode == 0) {
058: // this is an undeclaration
059: undeclared.add(prefixCode);
060: } else {
061: //Integer key = new Integer(prefixCode);
062: if (!undeclared.contains(prefixCode)) {
063: declared.add(nslist[i]);
064: undeclared.add(prefixCode);
065: }
066: }
067: }
068: }
069: node = node.getParent();
070: }
071: count = declared.size();
072: nsIterator = declared.iterator();
073: }
074:
075: /**
076: * Get the next item in the sequence.
077: */
078:
079: public void advance() {
080: while (nsIterator.hasNext()) {
081: int nscode = nsIterator.next();
082: next = new NamespaceNodeImpl(element, nscode, ++index);
083: if (test == null || test.matches(next)) {
084: return;
085: }
086: }
087: next = null;
088: }
089:
090: /**
091: * Get the next item in the sequence. <BR>
092: *
093: * @return the next Item. If there are no more nodes, return null.
094: */
095:
096: public Item next() {
097: if (index == -1) {
098: advance();
099: index = 0;
100: }
101: current = next;
102: if (current == null) {
103: position = -1;
104: return null;
105: }
106: advance();
107: position++;
108: return current;
109: }
110:
111: /**
112: * Get the current item in the sequence.
113: *
114: * @return the current item, that is, the item most recently returned by
115: * next()
116: */
117:
118: public Item current() {
119: return current;
120: }
121:
122: /**
123: * Get the current position
124: *
125: * @return the position of the current item (the item most recently
126: * returned by next()), starting at 1 for the first node
127: */
128:
129: public int position() {
130: return position;
131: }
132:
133: /**
134: * Get another iterator over the same sequence of items, positioned at the
135: * start of the sequence
136: *
137: * @return a new iterator over the same sequence
138: */
139:
140: public SequenceIterator getAnother() {
141: return new NamespaceIterator(element, test);
142: }
143:
144: /**
145: * Get properties of this iterator, as a bit-significant integer.
146: *
147: * @return the properties of this iterator. This will be some combination of
148: * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
149: * and {@link LOOKAHEAD}. It is always
150: * acceptable to return the value zero, indicating that there are no known special properties.
151: * It is acceptable for the properties of the iterator to change depending on its state.
152: */
153:
154: public int getProperties() {
155: return 0;
156: }
157:
158: /**
159: * Get a list of in-scope namespace codes. If an array of namespace codes is needed, without
160: * actually constructing the namespace nodes, a caller may create the NamespaceIterator and then
161: * call this method. The result is an array of integers, each containing a prefix code in the top
162: * half and a uri code in the bottom half. Note that calling this method is destructive: the
163: * iterator is consumed and cannot be used again.
164: */
165:
166: public int[] getInScopeNamespaceCodes() {
167: int[] codes = new int[count];
168: int i = 0;
169: while (nsIterator.hasNext()) {
170: codes[i++] = nsIterator.next();
171: }
172: return codes;
173: }
174:
175: /**
176: * Inner class: a model-independent representation of a namespace node
177: */
178:
179: public static class NamespaceNodeImpl implements NodeInfo,
180: FingerprintedNode {
181:
182: NodeInfo element;
183: int nscode;
184: int position;
185: int namecode;
186:
187: public NamespaceNodeImpl(NodeInfo element, int nscode,
188: int position) {
189: this .element = element;
190: this .nscode = nscode;
191: this .position = position;
192: NamePool pool = element.getNamePool();
193: String 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
229: .isSameNodeInfo(((NamespaceNodeImpl) other).element)
230: && nscode == ((NamespaceNodeImpl) other).nscode;
231:
232: }
233:
234: /**
235: * Get the System ID for the node.
236: *
237: * @return the System Identifier of the entity in the source document
238: * containing the node, or null if not known. Note this is not the
239: * same as the base URI: the base URI can be modified by xml:base, but
240: * the system ID cannot.
241: */
242:
243: public String getSystemId() {
244: return element.getSystemId();
245: }
246:
247: /**
248: * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained
249: * in the node. This will be the same as the System ID unless xml:base has been used.
250: *
251: * @return the base URI of the node
252: */
253:
254: public String getBaseURI() {
255: return element.getBaseURI();
256: }
257:
258: /**
259: * Get line number
260: *
261: * @return the line number of the node in its original source document; or
262: * -1 if not available
263: */
264:
265: public int getLineNumber() {
266: return element.getLineNumber();
267: }
268:
269: /**
270: * Determine the relative position of this node and another node, in document order.
271: * The other node will always be in the same document.
272: *
273: * @param other The other node, whose position is to be compared with this
274: * node
275: * @return -1 if this node precedes the other node, +1 if it follows the
276: * other node, or 0 if they are the same node. (In this case,
277: * isSameNode() will always return true, and the two nodes will
278: * produce the same result for generateId())
279: */
280:
281: public int compareOrder(NodeInfo other) {
282: if (other instanceof NamespaceNodeImpl
283: && element
284: .isSameNodeInfo(((NamespaceNodeImpl) other).element)) {
285: // JDK 1.5: return Integer.signum(position - ((NamespaceNodeI)other).position);
286: int c = position - ((NamespaceNodeImpl) other).position;
287: if (c == 0)
288: return 0;
289: if (c < 0)
290: return -1;
291: return +1;
292: } else {
293: return element.compareOrder(other);
294: }
295: }
296:
297: /**
298: * Return the string value of the node. The interpretation of this depends on the type
299: * of node. For a namespace node, it is the namespace URI.
300: *
301: * @return the string value of the node
302: */
303:
304: public String getStringValue() {
305: return element.getNamePool().getURIFromURICode(
306: (short) (nscode & 0xffff));
307: }
308:
309: /**
310: * Get the value of the item as a CharSequence. This is in some cases more efficient than
311: * the version of the method that returns a String.
312: */
313:
314: public CharSequence getStringValueCS() {
315: return getStringValue();
316: }
317:
318: /**
319: * Get name code. The name code is a coded form of the node name: two nodes
320: * with the same name code have the same namespace URI, the same local name,
321: * and the same prefix. By masking the name code with &0xfffff, you get a
322: * fingerprint: two nodes with the same fingerprint have the same local name
323: * and namespace URI.
324: *
325: * @return an integer name code, which may be used to obtain the actual node
326: * name from the name pool
327: * @see NamePool#allocate allocate
328: * @see NamePool#getFingerprint getFingerprint
329: */
330:
331: public int getNameCode() {
332: return namecode;
333: }
334:
335: /**
336: * Get fingerprint. The fingerprint is a coded form of the expanded name
337: * of the node: two nodes
338: * with the same name code have the same namespace URI and the same local name.
339: * A fingerprint of -1 should be returned for a node with no name.
340: *
341: * @return an integer fingerprint; two nodes with the same fingerprint have
342: * the same expanded QName
343: */
344:
345: public int getFingerprint() {
346: if (namecode == -1) {
347: return -1;
348: }
349: return namecode & NamePool.FP_MASK;
350: }
351:
352: /**
353: * Get the local part of the name of this node. This is the name after the ":" if any.
354: *
355: * @return the local part of the name. For an unnamed node, returns "". Unlike the DOM
356: * interface, this returns the full name in the case of a non-namespaced name.
357: */
358:
359: public String getLocalPart() {
360: if (namecode == -1) {
361: return "";
362: } else {
363: return element.getNamePool().getLocalName(namecode);
364: }
365: }
366:
367: /**
368: * Get the URI part of the name of this node. This is the URI corresponding to the
369: * prefix, or the URI of the default namespace if appropriate.
370: *
371: * @return The URI of the namespace of this node. Since the name of a namespace
372: * node is always an NCName (the namespace prefix), this method always returns "".
373: */
374:
375: public String getURI() {
376: return "";
377: }
378:
379: /**
380: * Get the display name of this node. For elements and attributes this is [prefix:]localname.
381: * For unnamed nodes, it is an empty string.
382: *
383: * @return The display name of this node. For a node with no name, return
384: * an empty string.
385: */
386:
387: public String getDisplayName() {
388: return getLocalPart();
389: }
390:
391: /**
392: * Get the prefix of the name of the node. This is defined only for elements and attributes.
393: * If the node has no prefix, or for other kinds of node, return a zero-length string.
394: *
395: * @return The prefix of the name of the node.
396: */
397:
398: public String getPrefix() {
399: return "";
400: }
401:
402: /**
403: * Get the configuration
404: */
405:
406: public Configuration getConfiguration() {
407: return element.getConfiguration();
408: }
409:
410: /**
411: * Get the NamePool that holds the namecode for this node
412: *
413: * @return the namepool
414: */
415:
416: public NamePool getNamePool() {
417: return element.getNamePool();
418: }
419:
420: /**
421: * Get the type annotation of this node, if any.
422: * Returns -1 for kinds of nodes that have no annotation, and for elements annotated as
423: * untyped, and attributes annotated as untypedAtomic.
424: *
425: * @return the type annotation of the node.
426: * @see net.sf.saxon.type.Type
427: */
428:
429: public int getTypeAnnotation() {
430: return -1;
431: }
432:
433: /**
434: * Get the NodeInfo object representing the parent of this node
435: *
436: * @return the parent of this node; null if this node has no parent
437: */
438:
439: public NodeInfo getParent() {
440: return element;
441: }
442:
443: /**
444: * Return an iteration over all the nodes reached by the given axis from this node
445: *
446: * @param axisNumber an integer identifying the axis; one of the constants
447: * defined in class net.sf.saxon.om.Axis
448: * @return an AxisIterator that scans the nodes reached by the axis in
449: * turn.
450: * @throws UnsupportedOperationException if the namespace axis is
451: * requested and this axis is not supported for this implementation.
452: * @see Axis
453: */
454:
455: public AxisIterator iterateAxis(byte axisNumber) {
456: return iterateAxis(axisNumber, new AnyNodeTest());
457: }
458:
459: /**
460: * Return an iteration over all the nodes reached by the given axis from this node
461: * that match a given NodeTest
462: *
463: * @param axisNumber an integer identifying the axis; one of the constants
464: * defined in class net.sf.saxon.om.Axis
465: * @param nodeTest A pattern to be matched by the returned nodes; nodes
466: * that do not match this pattern are not included in the result
467: * @return a NodeEnumeration that scans the nodes reached by the axis in
468: * turn.
469: * @throws UnsupportedOperationException if the namespace axis is
470: * requested and this axis is not supported for this implementation.
471: * @see Axis
472: */
473:
474: public AxisIterator iterateAxis(byte axisNumber,
475: NodeTest nodeTest) {
476: switch (axisNumber) {
477: case Axis.ANCESTOR:
478: return element.iterateAxis(Axis.ANCESTOR_OR_SELF,
479: nodeTest);
480:
481: case Axis.ANCESTOR_OR_SELF:
482: if (nodeTest.matches(this )) {
483: return new PrependIterator(this , element
484: .iterateAxis(Axis.ANCESTOR_OR_SELF,
485: nodeTest));
486: } else {
487: return element.iterateAxis(Axis.ANCESTOR_OR_SELF,
488: nodeTest);
489: }
490:
491: case Axis.ATTRIBUTE:
492: case Axis.CHILD:
493: case Axis.DESCENDANT:
494: case Axis.DESCENDANT_OR_SELF:
495: case Axis.FOLLOWING_SIBLING:
496: case Axis.NAMESPACE:
497: case Axis.PRECEDING_SIBLING:
498: return EmptyIterator.getInstance();
499:
500: case Axis.FOLLOWING:
501: return new Navigator.AxisFilter(
502: new Navigator.FollowingEnumeration(this ),
503: nodeTest);
504:
505: case Axis.PARENT:
506: if (nodeTest.matches(element)) {
507: return SingletonIterator.makeIterator(element);
508: }
509: return EmptyIterator.getInstance();
510:
511: case Axis.PRECEDING:
512: return new Navigator.AxisFilter(
513: new Navigator.PrecedingEnumeration(this , false),
514: nodeTest);
515:
516: case Axis.SELF:
517: if (nodeTest.matches(this )) {
518: return SingletonIterator.makeIterator(this );
519: }
520: return EmptyIterator.getInstance();
521:
522: case Axis.PRECEDING_OR_ANCESTOR:
523: return new Navigator.AxisFilter(
524: new Navigator.PrecedingEnumeration(this , true),
525: nodeTest);
526: default:
527: throw new IllegalArgumentException(
528: "Unknown axis number " + axisNumber);
529: }
530: }
531:
532: /**
533: * Get the value of a given attribute of this node
534: *
535: * @param fingerprint The fingerprint of the attribute name
536: * @return the attribute value if it exists or null if not
537: */
538:
539: public String getAttributeValue(int fingerprint) {
540: return null;
541: }
542:
543: /**
544: * Get the root node of the tree containing this node
545: *
546: * @return the NodeInfo representing the top-level ancestor of this node.
547: * This will not necessarily be a document node
548: */
549:
550: public NodeInfo getRoot() {
551: return element.getRoot();
552: }
553:
554: /**
555: * Get the root node, if it is a document node.
556: *
557: * @return the DocumentInfo representing the containing document. If this
558: * node is part of a tree that does not have a document node as its
559: * root, return null.
560: */
561:
562: public DocumentInfo getDocumentRoot() {
563: return element.getDocumentRoot();
564: }
565:
566: /**
567: * Determine whether the node has any children. <br />
568: * Note: the result is equivalent to <br />
569: * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext()
570: *
571: * @return True if the node has one or more children
572: */
573:
574: public boolean hasChildNodes() {
575: return false;
576: }
577:
578: /**
579: * Get a character string that uniquely identifies this node.
580: * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b)
581: *
582: * @return a string that uniquely identifies this node, across all
583: * documents.
584: */
585:
586: public String generateId() {
587: return element.generateId() + 'n' + position;
588: }
589:
590: /**
591: * Get the document number of the document containing this node. For a free-standing
592: * orphan node, just return the hashcode.
593: */
594:
595: public int getDocumentNumber() {
596: return element.getDocumentNumber();
597: }
598:
599: /**
600: * Copy this node to a given outputter
601: *
602: * @param out the Receiver to which the node should be copied
603: * @param whichNamespaces in the case of an element, controls
604: * which namespace nodes should be copied. Values are {@link #NO_NAMESPACES},
605: * {@link #LOCAL_NAMESPACES}, {@link #ALL_NAMESPACES}
606: * @param copyAnnotations indicates whether the type annotations
607: * of element and attribute nodes should be copied
608: * @param locationId If non-zero, identifies the location of the instruction
609: * that requested this copy. If zero, indicates that the location information
610: * for the original node is to be copied; in this case the Receiver must be
611: * a LocationCopier
612: * @throws net.sf.saxon.trans.XPathException
613: *
614: */
615:
616: public void copy(Receiver out, int whichNamespaces,
617: boolean copyAnnotations, int locationId)
618: throws XPathException {
619: out.namespace(nscode, 0);
620: }
621:
622: /**
623: * Output all namespace nodes associated with this element. Does nothing if
624: * the node is not an element.
625: *
626: * @param out The relevant outputter
627: * @param includeAncestors True if namespaces declared on ancestor
628: */
629:
630: public void sendNamespaceDeclarations(Receiver out,
631: boolean includeAncestors) throws XPathException {
632:
633: }
634:
635: /**
636: * Get all namespace undeclarations and undeclarations defined on this element.
637: *
638: * @param buffer If this is non-null, and the result array fits in this buffer, then the result
639: * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap.
640: * @return An array of integers representing the namespace declarations and undeclarations present on
641: * this element. For a node other than an element, return null. Otherwise, the returned array is a
642: * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The
643: * top half word of each namespace code represents the prefix, the bottom half represents the URI.
644: * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration.
645: * The XML namespace is never included in the list. If the supplied array is larger than required,
646: * then the first unused entry will be set to -1.
647: * <p/>
648: * <p>For a node other than an element, the method returns null.</p>
649: */
650:
651: public int[] getDeclaredNamespaces(int[] buffer) {
652: return null;
653: }
654:
655: /**
656: * Set the system identifier for this Source.
657: * <p/>
658: * <p>The system identifier is optional if the source does not
659: * get its data from a URL, but it may still be useful to provide one.
660: * The application can use a system identifier, for example, to resolve
661: * relative URIs and to include in error messages and warnings.</p>
662: *
663: * @param systemId The system identifier as a URL string.
664: */
665: public void setSystemId(String systemId) {
666:
667: }
668:
669: /**
670: * Get the typed value of the item
671: *
672: * @return the typed value of the item. In general this will be a sequence
673: * @throws net.sf.saxon.trans.XPathException
674: * where no typed value is available, e.g. for
675: * an element with complex content
676: */
677:
678: public SequenceIterator getTypedValue() throws XPathException {
679: return SingletonIterator.makeIterator(new StringValue(
680: getStringValueCS()));
681: }
682:
683: /**
684: * Get the typed value. The result of this method will always be consistent with the method
685: * {@link Item#getTypedValue()}. However, this method is often more convenient and may be
686: * more efficient, especially in the common case where the value is expected to be a singleton.
687: *
688: * @return the typed value. If requireSingleton is set to true, the result will always be an
689: * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic
690: * values.
691: * @since 8.5
692: */
693:
694: public Value atomize() throws XPathException {
695: return new StringValue(getStringValueCS());
696: }
697: }
698: }
|