KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > pull > VirtualTreeWalker


1 package net.sf.saxon.pull;
2
3 import net.sf.saxon.event.PipelineConfiguration;
4 import net.sf.saxon.expr.XPathContext;
5 import net.sf.saxon.instruct.DocumentInstr;
6 import net.sf.saxon.instruct.ElementCreator;
7 import net.sf.saxon.instruct.ParentNodeConstructor;
8 import net.sf.saxon.om.*;
9 import net.sf.saxon.trans.XPathException;
10 import net.sf.saxon.trans.DynamicError;
11 import net.sf.saxon.type.Type;
12 import net.sf.saxon.value.AtomicValue;
13 import net.sf.saxon.Configuration;
14
15 import javax.xml.transform.SourceLocator JavaDoc;
16 import javax.xml.transform.TransformerException JavaDoc;
17 import java.util.ArrayList JavaDoc;
18 import java.util.Stack JavaDoc;
19
20 /**
21  * A virtual tree walker provides a sequence of pull events describing the structure and content of a tree
22  * that is conceptually being constructed by expressions in a query or stylesheet; in fact the tree is
23  * not necessarily constructed in memory, and exists only as this stream of pull events.
24  * <p>
25  * The tree is physically constructed if operations are requested that depend on the identity of the nodes
26  * in the tree, or that navigate within the tree. Operations such as copying or atomizing the tree can be done
27  * directly, without building it in memory. (Note however that if such operations are done more than once, the
28  * underlying instructions may be evaluated repeatedly.)
29  */

30
31 public class VirtualTreeWalker implements PullProvider, NamespaceDeclarations {
32
33     private PipelineConfiguration pipe;
34     private int currentEvent = START_OF_INPUT;
35     private int nameCode;
36     private int nextNameCode;
37     private ParentNodeConstructor instruction;
38     private XPathContext context;
39     private Stack JavaDoc constructorStack = new Stack JavaDoc();
40     private Stack JavaDoc iteratorStack = new Stack JavaDoc();
41     private PullProvider subordinateTreeWalker = null;
42                 // The subordinateTreeWalker is used if the tree construction expression pulls in references
43
// to document or element nodes in an existing source document. When this happens, tree walking
44
// events generated by walking the source document are copied into to the stream of events
45
// generated by this class.
46
private boolean alreadyRead = false;
47     private boolean allowAttributes = false;
48
49     private int stripDepth = -1;
50                 // If this is >0, it indicates that instructions on the constructor stack with depth < stripDepth
51
// specify validation=preserve, while those at greater depth effectively specify validation=strip
52
// (It doesn't matter if they actually say validation=preserve, the stripping takes priority)
53

54     private AttributeCollectionImpl attributes;
55     private boolean foundAttributes;
56     private int[] activeNamespaces;
57     private ArrayList JavaDoc additionalNamespaces = new ArrayList JavaDoc(10); // array of namespace nodes
58

59     /**
60      * Create a VirtualTreeWalker to navigate the tree constructed by evaluating a given instruction
61      * in a given dyamic context
62      * @param instruction the instruction (this will always be an instruction that creates element or
63      * document nodes)
64      * @param context the dynamic evaluation context
65      */

66
67     public VirtualTreeWalker(ParentNodeConstructor instruction, XPathContext context) {
68         this.instruction = instruction;
69         this.context = context;
70     }
71
72     /**
73      * Set configuration information. This must only be called before any events
74      * have been read.
75      */

76
77     public void setPipelineConfiguration(PipelineConfiguration pipe) {
78         this.pipe = pipe;
79     }
80
81     /**
82      * Get configuration information.
83      */

84
85     public PipelineConfiguration getPipelineConfiguration() {
86         return pipe;
87     }
88
89     /**
90      * Get the namepool
91      */

92
93     public NamePool getNamePool() {
94         return pipe.getConfiguration().getNamePool();
95     }
96
97     /**
98      * Get the next event
99      *
100      * @return an integer code indicating the type of event. The code
101      * {@link #END_OF_INPUT} is returned at the end of the sequence.
102      */

103
104     public int next() throws XPathException {
105
106         try {
107
108             // First see if we are currently walking some other tree that has been logically
109
// copied into this tree.
110

111             if (subordinateTreeWalker != null) {
112                 currentEvent = subordinateTreeWalker.next();
113                 if (currentEvent == END_OF_INPUT) {
114                     subordinateTreeWalker = null;
115                     return next();
116                 }
117                 return currentEvent;
118             }
119
120             // On the first call, produce a START_ELEMENT or START_DOCUMENT event depending on the instruction
121

122             if (currentEvent == START_OF_INPUT) {
123                 constructorStack.push(instruction);
124                 if (stripDepth < 0 && instruction.getValidationAction() == Validation.STRIP) {
125                      stripDepth = constructorStack.size();
126                 }
127                 SequenceIterator content = instruction.getContentExpression().iterate(context);
128                 iteratorStack.push(content);
129                 if (instruction instanceof DocumentInstr) {
130                     currentEvent = START_DOCUMENT;
131                     nameCode = -1;
132                 } else {
133                     currentEvent = START_ELEMENT;
134                     nameCode = ((ElementCreator)instruction).getNameCode(context);
135                     allowAttributes = true;
136                     // look ahead to generate all the attributes and namespaces of the element
137
processAttributesAndNamespaces((ElementCreator)instruction, content);
138                     // remember that we've read one event too many
139
allowAttributes = false;
140                     alreadyRead = true;
141                 }
142                 return currentEvent;
143             }
144
145             if (iteratorStack.isEmpty()) {
146                 // if we're at the top level, see if we've just started, or are about to finish
147
if (currentEvent == START_DOCUMENT || currentEvent == START_ELEMENT) {
148                     // we've just started: start processing the content of the instruction
149
SequenceIterator iter = instruction.getContentExpression().iterate(context);
150                     constructorStack.push(instruction);
151                     if (stripDepth < 0 && instruction.getValidationAction() == Validation.STRIP) {
152                         stripDepth = constructorStack.size();
153                     }
154                     iteratorStack.push(iter);
155                 } else if (currentEvent == END_DOCUMENT || currentEvent == END_ELEMENT) {
156                     // we're about to finish
157
currentEvent = END_OF_INPUT;
158                     return currentEvent;
159                 } else {
160                     // we're going to finish soon, but must first generate the last END_DOCUMENT or END_ELEMENT event
161
currentEvent =
162                             ((instruction instanceof DocumentInstr) ? END_DOCUMENT : END_ELEMENT);
163                     return currentEvent;
164                 }
165             }
166
167             // Read the next item from the current content iterator
168

169             SequenceIterator iterator = ((SequenceIterator)iteratorStack.peek());
170             if (alreadyRead) {
171                 Item item = iterator.current();
172                 alreadyRead = false;
173                 nameCode = nextNameCode;
174                 return processItem(iterator, item);
175             } else {
176                 return processItem(iterator, iterator.next());
177             }
178         } catch (XPathException e) {
179             // report any dynamic errors unless already reported
180
if (!e.hasBeenReported()) {
181                 try {
182                     context.getController().getErrorListener().fatalError(e);
183                 } catch (TransformerException JavaDoc e2) {
184                     //
185
}
186             }
187             throw e;
188         }
189     }
190
191     private FastStringBuffer textNodeBuffer = new FastStringBuffer(100);
192
193     /**
194      * Process an item in the content of an element or document node
195      * @param iterator the iterator over the contents of the element or document
196      * @param item the current item to be processed, or null if the end of the content
197      * iterator has been reached
198      * @return the next event code
199      * @throws XPathException if a dynamic error occurs
200      */

201
202     private int processItem(SequenceIterator iterator, Item item) throws XPathException {
203         if (item == null) {
204             // we've reached the end of the children
205
if (stripDepth == constructorStack.size()) {
206                 stripDepth = -1;
207             }
208             ParentNodeConstructor inst = (ParentNodeConstructor)constructorStack.pop();
209             if (inst instanceof DocumentInstr) {
210                 iteratorStack.pop();
211                 if (iteratorStack.isEmpty()) {
212                     currentEvent = END_DOCUMENT;
213                     nameCode = -1;
214                     return currentEvent;
215                 }
216                 // skip the END_DOCUMENT event for a nested document node
217
return next();
218             } else {
219                 currentEvent = END_ELEMENT;
220                 nameCode = -1;
221                 iteratorStack.pop();
222                 return currentEvent;
223             }
224
225
226         } else if (item instanceof UnconstructedParent) {
227             // this represents a nested element or document node constructor
228
UnconstructedParent parent = (UnconstructedParent)item;
229             ParentNodeConstructor inst = parent.getInstruction();
230
231             constructorStack.push(inst);
232             if (stripDepth < 0 && inst.getValidationAction() == Validation.STRIP) {
233                  stripDepth = constructorStack.size();
234             }
235             SequenceIterator content = inst.getContentExpression().iterate(parent.getXPathContext());
236             if (inst instanceof DocumentInstr) {
237                 iteratorStack.push(content);
238                 // skip the START_DOCUMENT event
239
return next();
240             } else {
241                 currentEvent = START_ELEMENT;
242                 nameCode = ((UnconstructedElement)item).getNameCode();
243                 processAttributesAndNamespaces((ElementCreator)inst, content);
244                 alreadyRead = true;
245                 iteratorStack.push(content);
246                 return currentEvent;
247             }
248
249         } else if (item instanceof AtomicValue) {
250             textNodeBuffer.setLength(0);
251             textNodeBuffer.append(item.getStringValueCS());
252             while (true) {
253                 Item next = iterator.next();
254                 if (next instanceof AtomicValue) {
255                     textNodeBuffer.append(' ');
256                     textNodeBuffer.append(next.getStringValueCS());
257                     continue;
258                 } else {
259                     currentEvent = TEXT;
260                     nameCode = -1;
261                     alreadyRead = true;
262                     return currentEvent;
263                 }
264             }
265
266         } else {
267             nameCode = ((NodeInfo)item).getNameCode();
268             switch (((NodeInfo)item).getNodeKind()) {
269                 case Type.TEXT:
270                     currentEvent = TEXT;
271                     textNodeBuffer.setLength(0);
272                     textNodeBuffer.append(item.getStringValueCS());
273                         // TODO: avoid this unnecessary copy.
274
return currentEvent;
275
276                 case Type.COMMENT:
277                     currentEvent = COMMENT;
278                     return currentEvent;
279
280                 case Type.PROCESSING_INSTRUCTION:
281                     currentEvent = PROCESSING_INSTRUCTION;
282                     return currentEvent;
283
284                 case Type.ATTRIBUTE:
285                     if (!allowAttributes) {
286                         DynamicError de;
287                         if (constructorStack.peek() instanceof DocumentInstr) {
288                             de = new DynamicError(
289                                     "Attributes cannot be attached to a document node");
290                             if (context.getController().getExecutable().getHostLanguage() == Configuration.XQUERY) {
291                                 de.setErrorCode("XQTY0004");
292                             } else {
293                                 de.setErrorCode("XTDE0420");
294                             }
295                         } else {
296                             de = new DynamicError(
297                                     "Attributes in the content of an element must come before the child nodes");
298                             if (context.getController().getExecutable().getHostLanguage() == Configuration.XQUERY) {
299                                 de.setErrorCode("XQDY0024");
300                             } else {
301                                 de.setErrorCode("XTDE0410");
302                             }
303                         }
304                         de.setXPathContext(context);
305                         de.setLocator(getSourceLocator());
306                         throw de;
307                     }
308                     currentEvent = ATTRIBUTE;
309                     return currentEvent;
310
311                 case Type.NAMESPACE:
312                     if (!allowAttributes) {
313                         DynamicError de = new DynamicError(
314                                 "Namespace nodes in the content of an element must come before the child nodes");
315                         de.setErrorCode("XTDE0410");
316                         de.setXPathContext(context);
317                         de.setLocator(getSourceLocator());
318                         throw de;
319                     }
320                     currentEvent = NAMESPACE;
321                     return currentEvent;
322
323                 case Type.ELEMENT:
324                     subordinateTreeWalker = TreeWalker.makeTreeWalker((NodeInfo)item);
325                     subordinateTreeWalker.setPipelineConfiguration(pipe);
326                     currentEvent = subordinateTreeWalker.next();
327                     nameCode = subordinateTreeWalker.getNameCode();
328                     return currentEvent;
329
330                 case Type.DOCUMENT:
331                     subordinateTreeWalker = TreeWalker.makeTreeWalker((NodeInfo)item);
332                     subordinateTreeWalker.setPipelineConfiguration(pipe);
333                     subordinateTreeWalker = new DocumentEventIgnorer(subordinateTreeWalker);
334                     subordinateTreeWalker.setPipelineConfiguration(pipe);
335                     currentEvent = subordinateTreeWalker.next();
336                     nameCode = -1;
337                     return currentEvent;
338
339                 default:
340                     throw new IllegalStateException JavaDoc();
341
342             }
343         }
344     }
345
346     /**
347      * Following a START_ELEMENT event, evaluate the contents of the element to obtain all attributes and namespaces.
348      * This process stops when the first event other than an attribute or namespace is read. We then remember the
349      * extra event, which will be the next event returned in the normal sequence. Note that the relative order
350      * of attributes and namespaces is undefined.
351      * @param inst The instruction that creates the element node
352      * @param content Iterator over the expression that generates the attributes, namespaces, and content of the
353      * element
354      * @throws XPathException if any dynamic error occurs
355      */

356     private void processAttributesAndNamespaces(ElementCreator inst, SequenceIterator content) throws XPathException {
357         foundAttributes = false;
358         additionalNamespaces.clear();
359         activeNamespaces = inst.getActiveNamespaces();
360         if (activeNamespaces == null) {
361             activeNamespaces = EMPTY_INT_ARRAY;
362         }
363         boolean preserve = (stripDepth<0);
364         while (true) {
365             Item next = content.next();
366             if (next == null) {
367                 break;
368             } else if (next instanceof NodeInfo) {
369                 NodeInfo node = (NodeInfo)next;
370                 int kind = node.getNodeKind();
371                 if (kind == Type.ATTRIBUTE) {
372                     if (!foundAttributes) {
373                         if (attributes == null) {
374                             attributes = new AttributeCollectionImpl(context.getController().getNamePool());
375                         }
376                         attributes.clear();
377                         foundAttributes = true;
378                     }
379                     int index = attributes.getIndexByFingerprint(node.getFingerprint());
380                     if (index >= 0) {
381                         // Attribute already exists. In XQuery this is an error. In XSLT, the last attribute wins
382
if (context.getController().getExecutable().getHostLanguage() == Configuration.XSLT) {
383                             attributes.setAttribute(index,
384                                     node.getNameCode(),
385                                     preserve ? node.getTypeAnnotation() : -1,
386                                     node.getStringValue(), 0, 0);
387                         } else {
388                             DynamicError de = new DynamicError(
389                                 "The attributes of an element must have distinct names");
390                             de.setErrorCode("XQDY0025");
391                             de.setXPathContext(context);
392                             de.setLocator(getSourceLocator());
393                             throw de;
394                         }
395                     } else {
396                         attributes.addAttribute(
397                             node.getNameCode(),
398                             preserve ? node.getTypeAnnotation() : -1,
399                             node.getStringValue(),
400                             0, 0);
401                     }
402                 } else if (kind == Type.NAMESPACE) {
403                     additionalNamespaces.add(node);
404                 } else {
405                     nextNameCode = ((NodeInfo)next).getNameCode();
406                     break;
407                 }
408             } else {
409                 break;
410             }
411         }
412     }
413
414     /**
415      * Get the event most recently returned by next(), or by other calls that change
416      * the position, for example getStringValue() and skipToMatchingEnd(). This
417      * method does not change the position of the PullProvider.
418      *
419      * @return the current event
420      */

421
422     public int current() {
423         return currentEvent;
424     }
425
426     /**
427      * Get the attributes associated with the current element. This method must
428      * be called only after a START_ELEMENT event has been notified. The contents
429      * of the returned AttributeCollection are guaranteed to remain unchanged
430      * until the next START_ELEMENT event, but may be modified thereafter. The object
431      * should not be modified by the client.
432      * <p/>
433      * <p>Attributes may be read before or after reading the namespaces of an element,
434      * but must not be read after the first child node has been read, or after calling
435      * one of the methods skipToEnd(), getStringValue(), or getTypedValue().</p>
436      *
437      * @return an AttributeCollection representing the attributes of the element
438      * that has just been notified.
439      */

440
441     public AttributeCollection getAttributes() throws XPathException {
442         if (subordinateTreeWalker != null) {
443             return subordinateTreeWalker.getAttributes();
444         } else {
445             if (foundAttributes) {
446                 return attributes;
447             } else {
448                 return AttributeCollectionImpl.EMPTY_ATTRIBUTE_COLLECTION;
449             }
450         }
451     }
452
453     /**
454      * Get the namespace declarations associated with the current element. This method must
455      * be called only after a START_ELEMENT event has been notified. In the case of a top-level
456      * START_ELEMENT event (that is, an element that either has no parent node, or whose parent
457      * is not included in the sequence being read), the NamespaceDeclarations object returned
458      * will contain a namespace declaration for each namespace that is in-scope for this element
459      * node. In the case of a non-top-level element, the NamespaceDeclarations will contain
460      * a set of namespace declarations and undeclarations, representing the differences between
461      * this element and its parent.
462      * <p/>
463      * <p>It is permissible for this method to return namespace declarations that are redundant.</p>
464      * <p/>
465      * <p>The NamespaceDeclarations object is guaranteed to remain unchanged until the next START_ELEMENT
466      * event, but may then be overwritten. The object should not be modified by the client.</p>
467      * <p/>
468      * <p>Namespaces may be read before or after reading the attributes of an element,
469      * but must not be read after the first child node has been read, or after calling
470      * one of the methods skipToEnd(), getStringValue(), or getTypedValue().</p>*
471      */

472
473     public NamespaceDeclarations getNamespaceDeclarations() throws XPathException {
474         if (subordinateTreeWalker != null) {
475             return subordinateTreeWalker.getNamespaceDeclarations();
476         } else {
477             return this;
478         }
479     }
480
481     /**
482      * Skip the current subtree. This method may be called only immediately after
483      * a START_DOCUMENT or START_ELEMENT event. This call returns the matching
484      * END_DOCUMENT or END_ELEMENT event; the next call on next() will return
485      * the event following the END_DOCUMENT or END_ELEMENT.
486      * @throws IllegalStateException if the method is called at any time other than
487      * immediately after a START_DOCUMENT or START_ELEMENT event.
488      */

489
490     public int skipToMatchingEnd() throws XPathException {
491         if (currentEvent != START_DOCUMENT && currentEvent != START_ELEMENT) {
492             throw new IllegalStateException JavaDoc();
493         }
494         if (subordinateTreeWalker != null) {
495             return subordinateTreeWalker.skipToMatchingEnd();
496         } else {
497             SequenceIterator content = (SequenceIterator)iteratorStack.peek();
498             if (alreadyRead) {
499                 alreadyRead = false;
500             }
501             while (true) {
502                 Item next = content.next();
503                 if (next == null) {
504                     break;
505                 }
506             }
507             return (currentEvent == START_DOCUMENT ? END_DOCUMENT : END_ELEMENT);
508         }
509     }
510
511     /**
512      * Close the event reader. This indicates that no further events are required.
513      * It is not necessary to close an event reader after {@link #END_OF_INPUT} has
514      * been reported, but it is recommended to close it if reading terminates
515      * prematurely. Once an event reader has been closed, the effect of further
516      * calls on next() is undefined.
517      */

518
519     public void close() {
520         if (subordinateTreeWalker != null) {
521             subordinateTreeWalker.close();
522         } else {
523             // do nothing
524
}
525     }
526
527     /**
528      * Set the initial nameCode (the nameCode of the node at the root of the tree being walked)
529      */

530
531     public void setNameCode(int nameCode) {
532         this.nameCode = nameCode;
533     }
534
535     /**
536      * Get the nameCode identifying the name of the current node. This method
537      * can be used after the {@link #START_ELEMENT}, {@link #END_ELEMENT}, {@link #PROCESSING_INSTRUCTION},
538      * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. With some PullProvider implementations,
539      * <b>but not this one</b>, it can also be used after {@link #END_ELEMENT}.
540      * If called at other times, the result is undefined and may result in an IllegalStateException.
541      * If called when the current node is an unnamed namespace node (a node representing the default namespace)
542      * the returned value is -1.
543      *
544      * @return the nameCode. The nameCode can be used to obtain the prefix, local name,
545      * and namespace URI from the name pool.
546      */

547
548     public int getNameCode() {
549         if (subordinateTreeWalker != null) {
550             return subordinateTreeWalker.getNameCode();
551         }
552         return nameCode;
553     }
554
555     /**
556      * Get the fingerprint of the name of the element. This is similar to the nameCode, except that
557      * it does not contain any information about the prefix: so two elements with the same fingerprint
558      * have the same name, excluding prefix. This method
559      * can be used after the {@link #START_ELEMENT}, {@link #END_ELEMENT}, {@link #PROCESSING_INSTRUCTION},
560      * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events.
561      * If called at other times, the result is undefined and may result in an IllegalStateException.
562      * If called when the current node is an unnamed namespace node (a node representing the default namespace)
563      * the returned value is -1.
564      *
565      * @return the fingerprint. The fingerprint can be used to obtain the local name
566      * and namespace URI from the name pool.
567      */

568
569     public int getFingerprint() {
570         int nc = getNameCode();
571         if (nc == -1) {
572             return -1;
573         } else {
574             return nc & NamePool.FP_MASK;
575         }
576     }
577
578     /**
579      * Get the string value of the current element, text node, processing-instruction,
580      * or top-level attribute or namespace node, or atomic value.
581      * <p/>
582      * <p>In other situations the result is undefined and may result in an IllegalStateException.</p>
583      * <p/>
584      * <p>If the most recent event was a {@link #START_ELEMENT}, this method causes the content
585      * of the element to be read. The current event on completion of this method will be the
586      * corresponding {@link #END_ELEMENT}. The next call of next() will return the event following
587      * the END_ELEMENT event.</p>
588      *
589      * @return the String Value of the node in question, defined according to the rules in the
590      * XPath data model.
591      */

592
593     public CharSequence JavaDoc getStringValue() throws XPathException {
594         if (subordinateTreeWalker != null) {
595             return subordinateTreeWalker.getStringValue();
596         } else if (currentEvent == TEXT) {
597             return textNodeBuffer;
598         } else if (currentEvent != START_ELEMENT && currentEvent != START_DOCUMENT) {
599             SequenceIterator content = (SequenceIterator)iteratorStack.peek();
600             if (content.current() == null) {
601                 return "";
602             }
603             return content.current().getStringValue();
604         } else {
605             FastStringBuffer sb = new FastStringBuffer(100);
606             SequenceIterator content = (SequenceIterator)iteratorStack.peek();
607             if (alreadyRead) {
608                 if (content.current() == null) {
609                     return "";
610                 }
611                 processText(content.current(), sb);
612                 alreadyRead = false;
613             }
614             while (true) {
615                 Item next = content.next();
616                 if (next == null) {
617                     break;
618                 }
619                 processText(next, sb);
620             }
621             return sb;
622         }
623     }
624
625     /**
626      * Add the string value of a child item to a string buffer that is used to accumulate the
627      * string value of a document or element node
628      * @param item the child item
629      * @param sb the string buffer where the content is accumulated
630      */

631
632     private void processText(Item item, FastStringBuffer sb) {
633         if (item instanceof UnconstructedParent) {
634             sb.append(item.getStringValueCS());
635         } else if (item instanceof AtomicValue) {
636             sb.append(item.getStringValueCS());
637         } else {
638             NodeInfo node = (NodeInfo)item;
639             switch (node.getNodeKind()) {
640                 case Type.DOCUMENT:
641                 case Type.ELEMENT:
642                 case Type.TEXT:
643                     sb.append(node.getStringValueCS());
644                 default:
645                     // do nothing
646
}
647         }
648     }
649
650     /**
651      * Get an atomic value. This call may be used only when the last event reported was
652      * ATOMIC_VALUE. This indicates that the PullProvider is reading a sequence that contains
653      * a free-standing atomic value; it is never used when reading the content of a node.
654      */

655
656     public AtomicValue getAtomicValue() {
657         throw new IllegalStateException JavaDoc();
658     }
659
660     /**
661      * Get the type annotation of the current attribute or element node, or atomic value.
662      * The result of this method is undefined unless the most recent event was START_ELEMENT,
663      * ATTRIBUTE, or ATOMIC_VALUE.
664      *
665      * @return the type annotation. This code is the fingerprint of a type name, which may be
666      * resolved to a {@link net.sf.saxon.type.SchemaType} by access to the Configuration.
667      */

668
669     public int getTypeAnnotation() {
670         if (subordinateTreeWalker != null && stripDepth < 0) {
671             return subordinateTreeWalker.getTypeAnnotation();
672         } else {
673             return -1;
674         }
675     }
676
677     /**
678      * Get the location of the current event.
679      * For an event stream representing a real document, the location information
680      * should identify the location in the lexical XML source. For a constructed document, it should
681      * identify the location in the query or stylesheet that caused the node to be created.
682      * A value of null can be returned if no location information is available.
683      */

684
685     public SourceLocator JavaDoc getSourceLocator() {
686         return instruction;
687     }
688
689     /**
690      * Get the number of declarations (and undeclarations) in this list.
691      */

692
693     public int getLength() {
694         return activeNamespaces.length + additionalNamespaces.size();
695     }
696
697     /**
698      * Get the prefix of the n'th declaration (or undeclaration) in the list,
699      * counting from zero.
700      *
701      * @param index the index identifying which declaration is required.
702      * @return the namespace prefix. For a declaration or undeclaration of the
703      * default namespace, this is the zero-length string.
704      * @throws IndexOutOfBoundsException if the index is out of range.
705      */

706
707     public String JavaDoc getPrefix(int index) {
708         if (index < activeNamespaces.length) {
709             return getNamePool().getPrefixFromNamespaceCode(activeNamespaces[index]);
710         } else {
711             return ((NodeInfo)additionalNamespaces.get(index - activeNamespaces.length)).getLocalPart();
712         }
713     }
714
715     /**
716      * Get the namespace URI of the n'th declaration (or undeclaration) in the list,
717      * counting from zero.
718      *
719      * @param index the index identifying which declaration is required.
720      * @return the namespace URI. For a namespace undeclaration, this is the
721      * zero-length string.
722      * @throws IndexOutOfBoundsException if the index is out of range.
723      */

724
725     public String JavaDoc getURI(int index) {
726         if (index < activeNamespaces.length) {
727             return getNamePool().getURIFromNamespaceCode(activeNamespaces[index]);
728         } else {
729             return ((NodeInfo)additionalNamespaces.get(index - activeNamespaces.length)).getStringValue();
730         }
731     }
732
733     /**
734      * Get the n'th declaration in the list in the form of a namespace code. Namespace
735      * codes can be translated into a prefix and URI by means of methods in the
736      * NamePool
737      *
738      * @param index the index identifying which declaration is required.
739      * @return the namespace code. This is an integer whose upper half indicates
740      * the prefix (0 represents the default namespace), and whose lower half indicates
741      * the URI (0 represents an undeclaration).
742      * @throws IndexOutOfBoundsException if the index is out of range.
743      * @see net.sf.saxon.om.NamePool#getPrefixFromNamespaceCode(int)
744      * @see net.sf.saxon.om.NamePool#getURIFromNamespaceCode(int)
745      */

746
747     public int getNamespaceCode(int index) {
748         if (index < activeNamespaces.length) {
749             return activeNamespaces[index];
750         } else {
751             return getNamePool().allocateNamespaceCode(getPrefix(index), getURI(index));
752         }
753     }
754
755     /**
756      * Get all the namespace codes, as an array.
757      *
758      * @param buffer a sacrificial array that the method is free to use to contain the result.
759      * May be null.
760      * @return an integer array containing namespace codes. The array may be filled completely
761      * with namespace codes, or it may be incompletely filled, in which case a -1 integer acts
762      * as a terminator.
763      */

764
765     // TODO: not coded for efficiency!
766

767     public int[] getNamespaceCodes(int[] buffer) {
768         if (buffer.length < getLength()) {
769             buffer = new int[getLength()];
770         } else {
771             buffer[getLength()] = -1;
772         }
773         for (int i=0; i<getLength(); i++) {
774             buffer[i] = getNamespaceCode(i);
775         }
776         return buffer;
777     }
778
779     private static final int[] EMPTY_INT_ARRAY = new int[0];
780 }
781
782 //
783
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
784
// you may not use this file except in compliance with the License. You may obtain a copy of the
785
// License at http://www.mozilla.org/MPL/
786
//
787
// Software distributed under the License is distributed on an "AS IS" basis,
788
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
789
// See the License for the specific language governing rights and limitations under the License.
790
//
791
// The Original Code is: all this file.
792
//
793
// The Initial Developer of the Original Code is Michael H. Kay.
794
//
795
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
796
//
797
// Contributor(s): none.
798
//
799

800
Popular Tags