KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > tinytree > TinyTree


1 package net.sf.saxon.tinytree;
2 import net.sf.saxon.Configuration;
3 import net.sf.saxon.om.*;
4 import net.sf.saxon.style.StandardNames;
5 import net.sf.saxon.tree.LineNumberMap;
6 import net.sf.saxon.tree.SystemIdMap;
7 import net.sf.saxon.type.*;
8 import net.sf.saxon.value.UntypedAtomicValue;
9
10 import java.util.ArrayList JavaDoc;
11 import java.util.HashSet JavaDoc;
12 import java.util.Set JavaDoc;
13
14
15 /**
16  * A data structure to hold the contents of a tree. As the name implies, this implementation
17  * of the data model is optimized for size, and for speed of creation: it minimizes the number
18  * of Java objects used.
19  *
20  * <p>It can be used to represent a tree that is rooted at a document node, or one that is rooted
21  * at an element node.</p>
22  */

23
24 public final class TinyTree {
25
26     private static final int[] EMPTY_INT_ARRAY = new int[0];
27     private static final String JavaDoc[] EMPTY_STRING_ARRAY = new String JavaDoc[0];
28
29     private Configuration config;
30
31     // List of top-level document nodes.
32
private ArrayList JavaDoc documentList = new ArrayList JavaDoc(5);
33
34     // The document number (really a tree number: it can identify a non-document root node
35
protected int documentNumber;
36
37     // the contents of the document
38

39     protected char[] charBuffer;
40     protected int charBufferLength = 0;
41     protected FastStringBuffer commentBuffer = null; // created when needed
42

43     protected int numberOfNodes = 0; // excluding attributes and namespaces
44

45     // The following arrays contain one entry for each node other than attribute
46
// and namespace nodes, arranged in document order.
47

48     // nodeKind indicates the kind of node, e.g. element, text, or comment
49
public byte[] nodeKind;
50
51     // depth is the depth of the node in the hierarchy, i.e. the number of ancestors
52
protected short[] depth;
53
54     // next is the node number of the next sibling
55
// - unless it points backwards, in which case it is the node number of the parent
56
protected int[] next;
57
58     // alpha holds a value that depends on the node kind. For text nodes, it is the offset
59
// into the text buffer. For comments and processing instructions, it is the offset into
60
// the comment buffer. For elements, it is the index of the first attribute node, or -1
61
// if this element has no attributes.
62
protected int[] alpha;
63
64     // beta holds a value that depends on the node kind. For text nodes, it is the length
65
// of the text. For comments and processing instructions, it is the length of the text.
66
// For elements, it is the index of the first namespace node, or -1
67
// if this element has no namespaces.
68
protected int[] beta;
69
70     // nameCode holds the name of the node, as an identifier resolved using the name pool
71
protected int[] nameCode;
72
73     // the prior array indexes preceding-siblings; it is constructed only when required
74
protected int[] prior = null;
75
76     // the typeCode array holds type codes for element nodes; it is constructed only
77
// if at least one element has a type other than untyped (-1)
78
protected int[] typeCodeArray = null;
79
80     // the owner array gives fast access from a node to its parent; it is constructed
81
// only when required
82
// protected int[] parentIndex = null;
83

84     // the following arrays have one entry for each attribute.
85
protected int numberOfAttributes = 0;
86
87     // attParent is the index of the parent element node
88
protected int[] attParent;
89
90     // attCode is the nameCode representing the attribute name
91
protected int[] attCode;
92
93     // attValue is the string value of the attribute
94
protected CharSequence JavaDoc[] attValue;
95
96     // attTypeCode holds type annotations. The array is created only if any nodes have a type annotation
97
// or are marked as IDREF/IDREFS attributes. The bit 1<<30 represents the is-idref property, and 1<<29
98
// represents the is-id property
99
protected int[] attTypeCode;
100
101     // The following arrays have one entry for each namespace declaration
102
protected int numberOfNamespaces = 0;
103
104     // namespaceParent is the index of the element node owning the namespace declaration
105
protected int[] namespaceParent;
106
107     // namespaceCode is the namespace code used by the name pool: the top half is the prefix
108
// code, the bottom half the URI code
109
protected int[] namespaceCode;
110
111     // an array holding the offsets of all the level-0 (root) nodes, so that the root of a given
112
// node can be found efficiently
113
private int[] rootIndex = new int[5];
114     private int rootIndexUsed = 0;
115
116     private LineNumberMap lineNumberMap;
117     private SystemIdMap systemIdMap = null;
118
119     // a boolean that is set to true if the document declares a namespace other than the XML namespace
120
protected boolean usesNamespaces = false;
121
122     private Set JavaDoc nonIDs; // a set of type annotation codes appearing in this document that are known
123
// not to be subtypes of xs:ID
124

125     //private int IDtype;
126

127     public TinyTree() {
128         this(4000, 100, 20, 4000);
129     }
130
131     public TinyTree(int nodes, int attributes, int namespaces, int characters) {
132         //System.err.println("TinyTree.new() " + this);
133
nodeKind = new byte[nodes];
134         depth = new short[nodes];
135         next = new int[nodes];
136         alpha = new int[nodes];
137         beta = new int[nodes];
138         nameCode = new int[nodes];
139
140         numberOfAttributes = 0;
141         attParent = new int[attributes];
142         attCode = new int[attributes];
143         attValue = new String JavaDoc[attributes];
144
145         numberOfNamespaces = 0;
146         namespaceParent = new int[namespaces];
147         namespaceCode = new int[namespaces];
148
149         charBuffer = new char[characters];
150         charBufferLength = 0;
151     }
152
153     /**
154     * Set the Configuration that contains this document
155     */

156
157     public void setConfiguration(Configuration config) {
158         this.config = config;
159         addNamespace(0, NamespaceConstant.XML_NAMESPACE_CODE);
160     }
161
162     /**
163      * Get the configuration previously set using setConfiguration
164      */

165
166     public Configuration getConfiguration() {
167         return config;
168     }
169
170     /**
171     * Get the name pool used for the names in this document
172     */

173
174     public NamePool getNamePool() {
175         return config.getNamePool();
176     }
177
178     private void ensureNodeCapacity(short kind) {
179         if (nodeKind.length < numberOfNodes+1) {
180             //System.err.println("Number of nodes = " + numberOfNodes);
181
int k = (kind == Type.STOPPER ? numberOfNodes+1 : numberOfNodes*2);
182
183             byte[] nodeKind2 = new byte[k];
184             int[] next2 = new int[k];
185             short[] depth2 = new short[k];
186             int[] alpha2 = new int[k];
187             int[] beta2 = new int[k];
188             int[] nameCode2 = new int[k];
189
190             System.arraycopy(nodeKind, 0, nodeKind2, 0, numberOfNodes);
191             System.arraycopy(next, 0, next2, 0, numberOfNodes);
192             System.arraycopy(depth, 0, depth2, 0, numberOfNodes);
193             System.arraycopy(alpha, 0, alpha2, 0, numberOfNodes);
194             System.arraycopy(beta, 0, beta2, 0, numberOfNodes);
195             System.arraycopy(nameCode, 0, nameCode2, 0, numberOfNodes);
196
197             nodeKind = nodeKind2;
198             next = next2;
199             depth = depth2;
200             alpha = alpha2;
201             beta = beta2;
202             nameCode = nameCode2;
203
204             if (typeCodeArray != null) {
205                 int[] typeCodeArray2 = new int[k];
206                 System.arraycopy(typeCodeArray, 0, typeCodeArray2, 0, numberOfNodes);
207                 typeCodeArray = typeCodeArray2;
208             }
209         }
210     }
211
212     private void ensureAttributeCapacity() {
213         if (attParent.length < numberOfAttributes+1) {
214             int k = numberOfAttributes*2;
215             if (k==0) {
216                 k = 10;
217             }
218
219             int[] attParent2 = new int[k];
220             int[] attCode2 = new int[k];
221             String JavaDoc[] attValue2 = new String JavaDoc[k];
222
223             System.arraycopy(attParent, 0, attParent2, 0, numberOfAttributes);
224             System.arraycopy(attCode, 0, attCode2, 0, numberOfAttributes);
225             System.arraycopy(attValue, 0, attValue2, 0, numberOfAttributes);
226
227             attParent = attParent2;
228             attCode = attCode2;
229             attValue = attValue2;
230
231             if (attTypeCode != null) {
232                 int[] attTypeCode2 = new int[k];
233                 System.arraycopy(attTypeCode, 0, attTypeCode2, 0, numberOfAttributes);
234                 attTypeCode = attTypeCode2;
235             }
236         }
237     }
238
239     private void ensureNamespaceCapacity() {
240         if (namespaceParent.length < numberOfNamespaces+1) {
241             int k = numberOfNamespaces*2;
242
243             int[] namespaceParent2 = new int[k];
244             int[] namespaceCode2 = new int[k];
245
246             System.arraycopy(namespaceParent, 0, namespaceParent2, 0, numberOfNamespaces);
247             System.arraycopy(namespaceCode, 0, namespaceCode2, 0, numberOfNamespaces);
248
249             namespaceParent = namespaceParent2;
250             namespaceCode = namespaceCode2;
251         }
252     }
253
254     /**
255      * Add a document node to the tree. The data structure can contain any number of document (or element) nodes
256      * as top-level nodes. The document node is retained in the documentList list, and its offset in that list
257      * is held in the alpha array for the relevant node number.
258      */

259
260     void addDocumentNode(TinyDocumentImpl doc) {
261         documentList.add(doc);
262         addNode(Type.DOCUMENT, 0, documentList.size()-1, 0, -1);
263     }
264
265     /**
266      * Add a node to the tree
267      * @param kind The kind of the node. This must be a document, element, text, comment,
268      * or processing-instruction node (not an attribute or namespace)
269      * @param depth The depth in the tree
270      * @param alpha Pointer to attributes or text
271      * @param beta Pointer to namespaces or text
272      * @param nameCode The name of the node
273      * @return the node number of the node that was added
274      */

275     int addNode(short kind, int depth, int alpha, int beta, int nameCode) {
276         ensureNodeCapacity(kind);
277         this.nodeKind[numberOfNodes] = (byte)kind;
278         this.depth[numberOfNodes] = (short)depth;
279         this.alpha[numberOfNodes] = alpha;
280         this.beta[numberOfNodes] = beta;
281         this.nameCode[numberOfNodes] = nameCode;
282         this.next[numberOfNodes] = -1; // safety precaution
283

284         if (typeCodeArray != null) {
285             typeCodeArray[numberOfNodes] = StandardNames.XDT_UNTYPED;
286         }
287
288         if (numberOfNodes == 0) {
289             documentNumber = config.getDocumentNumberAllocator().allocateDocumentNumber();
290         }
291
292         if (depth == 0) {
293             if (rootIndexUsed == rootIndex.length) {
294                 int[] r2 = new int[rootIndexUsed * 2];
295                 System.arraycopy(rootIndex, 0, r2, 0, rootIndexUsed);
296                 rootIndex = r2;
297             }
298             rootIndex[rootIndexUsed++] = numberOfNodes;
299         }
300         return numberOfNodes++;
301     }
302
303     void appendChars(CharSequence JavaDoc chars) {
304         if (charBuffer.length < charBufferLength + chars.length()) {
305             char[] ch2 = new char[Math.max(charBuffer.length * 2, charBufferLength + chars.length() + 100)];
306             System.arraycopy(charBuffer, 0, ch2, 0, charBufferLength);
307             charBuffer = ch2;
308         }
309         if (chars instanceof CharSlice) {
310             ((CharSlice)chars).copyTo(charBuffer, charBufferLength);
311         } else if (chars instanceof FastStringBuffer) {
312             ((FastStringBuffer)chars).getChars(0, chars.length(), charBuffer, charBufferLength);
313         } else {
314             char[] newchars = chars.toString().toCharArray();
315             System.arraycopy(newchars, 0, charBuffer, charBufferLength, chars.length());
316             // TODO: this is inefficient. There is no absolute reason that the
317
// character data for the whole document needs to be in one array.
318
}
319         charBufferLength += chars.length();
320     }
321
322     /**
323     * Condense the tree: release unused memory. This is done after the full tree has been built.
324     * The method makes a pragmatic judgement as to whether it is worth reclaiming space; this is
325     * only done when the constructed tree is very small compared with the space allocated.
326     */

327
328     protected void condense() {
329         //System.err.println("TinyTree.condense() " + this + " roots " + rootIndexUsed + " nodes " + numberOfNodes + " capacity " + nodeKind.length);
330

331         // If there are already two trees in this forest, the chances are that more will be added. In this
332
// case we don't want to condense the arrays because we will only have to expand them again, which gets
333
// increasingly expensive as they grow larger.
334
if (rootIndexUsed > 1) {
335             return;
336         }
337         if (numberOfNodes * 3 < nodeKind.length ||
338                 (nodeKind.length - numberOfNodes > 20000)) {
339
340             //System.err.println("-- copying node arrays");
341
int k = numberOfNodes + 1;
342
343             byte[] nodeKind2 = new byte[k];
344             int[] next2 = new int[k];
345             short[] depth2 = new short[k];
346             int[] alpha2 = new int[k];
347             int[] beta2 = new int[k];
348             int[] nameCode2 = new int[k];
349
350             System.arraycopy(nodeKind, 0, nodeKind2, 0, numberOfNodes);
351             System.arraycopy(next, 0, next2, 0, numberOfNodes);
352             System.arraycopy(depth, 0, depth2, 0, numberOfNodes);
353             System.arraycopy(alpha, 0, alpha2, 0, numberOfNodes);
354             System.arraycopy(beta, 0, beta2, 0, numberOfNodes);
355             System.arraycopy(nameCode, 0, nameCode2, 0, numberOfNodes);
356             if (typeCodeArray != null) {
357                 int[] type2 = new int[k];
358                 System.arraycopy(typeCodeArray, 0, type2, 0, numberOfNodes);
359                 typeCodeArray = type2;
360             }
361
362             nodeKind = nodeKind2;
363             next = next2;
364             depth = depth2;
365             alpha = alpha2;
366             beta = beta2;
367             nameCode = nameCode2;
368         }
369
370         if ((numberOfAttributes * 3 < attParent.length) ||
371                 (attParent.length - numberOfAttributes > 1000)) {
372             int k = numberOfAttributes;
373
374             //System.err.println("-- copying attribute arrays");
375

376             if (k==0) {
377                 attParent = EMPTY_INT_ARRAY;
378                 attCode = EMPTY_INT_ARRAY;
379                 attValue = EMPTY_STRING_ARRAY;
380                 attTypeCode = null;
381             }
382
383             int[] attParent2 = new int[k];
384             int[] attCode2 = new int[k];
385             String JavaDoc[] attValue2 = new String JavaDoc[k];
386
387             System.arraycopy(attParent, 0, attParent2, 0, numberOfAttributes);
388             System.arraycopy(attCode, 0, attCode2, 0, numberOfAttributes);
389             System.arraycopy(attValue, 0, attValue2, 0, numberOfAttributes);
390
391             attParent = attParent2;
392             attCode = attCode2;
393             attValue = attValue2;
394
395             if (attTypeCode != null) {
396                 int[] attTypeCode2 = new int[k];
397                 System.arraycopy(attTypeCode, 0, attTypeCode2, 0, numberOfAttributes);
398                 attTypeCode = attTypeCode2;
399             }
400         }
401
402         if (numberOfNamespaces * 3 < namespaceParent.length) {
403             int k = numberOfNamespaces;
404             int[] namespaceParent2 = new int[k];
405             int[] namespaceCode2 = new int[k];
406
407             //System.err.println("-- copying namespace arrays");
408

409             System.arraycopy(namespaceParent, 0, namespaceParent2, 0, numberOfNamespaces);
410             System.arraycopy(namespaceCode, 0, namespaceCode2, 0, numberOfNamespaces);
411
412             namespaceParent = namespaceParent2;
413             namespaceCode = namespaceCode2;
414         }
415
416         if (charBufferLength * 3 < charBuffer.length ||
417                 charBuffer.length - charBufferLength > 10000) {
418             char[] c2 = new char[charBufferLength];
419             System.arraycopy(charBuffer, 0, c2, 0, charBufferLength);
420             charBuffer = c2;
421         }
422     }
423
424     /**
425     * Set the type annotation of an element node
426     */

427
428     void setElementAnnotation(int nodeNr, int typeCode) {
429         if (typeCode != StandardNames.XDT_UNTYPED) {
430             if (typeCodeArray == null) {
431                 typeCodeArray = new int[nodeKind.length];
432                 for (int i=0; i<nodeKind.length; i++) {
433                     typeCodeArray[i] = StandardNames.XDT_UNTYPED;
434                 }
435             }
436             typeCodeArray[nodeNr] = typeCode;
437         }
438     }
439
440     /**
441     * Get the type annotation of a node. Applies only to document, element, text,
442      * processing instruction, and comment nodes.
443      * @return -1 if the annotation is xdt:untyped or if the node is not an element.
444     */

445
446     public int getTypeAnnotation(int nodeNr) {
447         if (typeCodeArray == null) {
448             return StandardNames.XDT_UNTYPED;
449         }
450         return typeCodeArray[nodeNr];
451     }
452
453     /**
454      * Get the node kind of a given node, which must be a document, element,
455      * text, comment, or processing instruction node
456      * @param nodeNr the node number
457      * @return the node kind
458      */

459
460     public int getNodeKind(int nodeNr) {
461         return nodeKind[nodeNr];
462     }
463
464     /**
465      * Get the nameCode for a given node, which must be a document, element,
466      * text, comment, or processing instruction node
467      * @param nodeNr the node number
468      * @return the name code
469      */

470
471     public int getNameCode(int nodeNr) {
472         return nameCode[nodeNr];
473     }
474
475     /**
476     * On demand, make an index for quick access to preceding-sibling nodes
477     */

478
479     void ensurePriorIndex() {
480         if (prior==null) {
481             makePriorIndex();
482         }
483     }
484
485     private synchronized void makePriorIndex() {
486         prior = new int[numberOfNodes];
487         for (int i=0; i<numberOfNodes; i++) {
488             prior[i] = -1;
489         }
490         for (int i=0; i<numberOfNodes; i++) {
491             int nextNode = next[i];
492             if (nextNode > i) {
493                 prior[nextNode] = i;
494             }
495         }
496     }
497
498
499     void addAttribute(NodeInfo root, int parent, int nameCode, int typeCode, CharSequence JavaDoc attValue, int properties) {
500         ensureAttributeCapacity();
501         attParent[numberOfAttributes] = parent;
502         attCode[numberOfAttributes] = nameCode;
503         this.attValue[numberOfAttributes] = attValue;
504
505         if (typeCode == -1) {
506             // this shouldn't happen any more
507
typeCode = StandardNames.XDT_UNTYPED_ATOMIC;
508         }
509
510         if (typeCode != StandardNames.XDT_UNTYPED_ATOMIC) {
511             if (attTypeCode==null) {
512                 // this is the first typed attribute;
513
// create an array for the types, and set all previous attributes to untyped
514
attTypeCode = new int[attParent.length];
515                 for (int i=0; i<numberOfAttributes; i++) {
516                     attTypeCode[i] = StandardNames.XDT_UNTYPED_ATOMIC;
517                 }
518             }
519         }
520         if (attTypeCode != null) {
521             attTypeCode[numberOfAttributes] = typeCode;
522         }
523
524         if (alpha[parent] == -1) {
525             alpha[parent] = numberOfAttributes;
526         }
527
528         if (root instanceof TinyDocumentImpl && (isIDCode(typeCode) ||
529                 ((nameCode & NamePool.FP_MASK) == StandardNames.XML_ID))) {
530
531             // The attribute is marked as being an ID. But we don't trust it - it
532
// might come from a non-validating parser. Before adding it to the index, we
533
// check that it really is an ID.
534

535             String JavaDoc id = attValue.toString().trim();
536             if (XMLChar.isValidNCName(id)) {
537                 NodeInfo e = getNode(parent);
538                 ((TinyDocumentImpl)root).registerID(e, id);
539             } else if (attTypeCode != null) {
540                 attTypeCode[numberOfAttributes] = Type.UNTYPED_ATOMIC;
541             }
542         }
543
544         // Note: IDREF attributes are not indexed at this stage; that happens only if and when
545
// the idref() function is called.
546

547         // Note that an attTypes array will be created for all attributes if any ID or IDREF is reported.
548

549         numberOfAttributes++;
550     }
551
552     /**
553      * Index an element of type xs:ID
554      */

555
556     public void indexIDElement(NodeInfo root, int nodeNr) {
557         String JavaDoc id = TinyParentNodeImpl.getStringValue(this, nodeNr).toString().trim();
558         if (root instanceof DocumentInfo && XMLChar.isValidNCName(id)) {
559             NodeInfo e = getNode(nodeNr);
560             ((TinyDocumentImpl)root).registerID(e, id);
561         }
562     }
563
564     /**
565      * Test whether a type annotation code represents the type xs:ID or one of its subtypes
566      */

567
568     public boolean isIDCode(int typeCode) {
569         typeCode &= NamePool.FP_MASK;
570         if (typeCode == StandardNames.XS_ID) {
571             return true;
572         } else if (typeCode < 1024) {
573             // No other built-in type is an ID
574
return false;
575         } else {
576             if (nonIDs == null) {
577                 nonIDs = new HashSet JavaDoc(20);
578             }
579             Integer JavaDoc key = new Integer JavaDoc(typeCode);
580             if (nonIDs.contains(key)) {
581                 return false;
582             }
583             SchemaType type = getConfiguration().getSchemaType(typeCode);
584             if (type instanceof AtomicType) {
585                 if (Type.isSubType((AtomicType)type, Type.ID_TYPE)) {
586                     return true;
587                 } else {
588                     nonIDs.add(key);
589                     return false;
590                 }
591             } else {
592                 return false;
593             }
594         }
595     }
596
597     /**
598      * Add a namespace node to the current element
599      * @param parent the node number of the element
600      * @param nscode namespace code identifying the prefix and uri
601      */

602     void addNamespace(int parent, int nscode ) {
603
604         ensureNamespaceCapacity();
605         namespaceParent[numberOfNamespaces] = parent;
606         namespaceCode[numberOfNamespaces] = nscode;
607
608         if (beta[parent] == -1) {
609             beta[parent] = numberOfNamespaces;
610         }
611         numberOfNamespaces++;
612         if (nscode != NamespaceConstant.XML_NAMESPACE_CODE) {
613             usesNamespaces = true;
614         }
615     }
616
617     public TinyNodeImpl getNode(int nr) {
618
619         switch ((short)nodeKind[nr]) {
620             case Type.DOCUMENT:
621                 return (TinyDocumentImpl)documentList.get(alpha[nr]);
622             case Type.ELEMENT:
623                 return new TinyElementImpl(this, nr);
624             case Type.TEXT:
625                 return new TinyTextImpl(this, nr);
626             case Type.COMMENT:
627                 return new TinyCommentImpl(this, nr);
628             case Type.PROCESSING_INSTRUCTION:
629                 return new TinyProcInstImpl(this, nr);
630             case Type.PARENT_POINTER:
631                 throw new IllegalArgumentException JavaDoc("Attempting to treat a parent pointer as a node");
632         }
633
634         return null;
635     }
636
637     /**
638      * Get the typed value of a node whose type is known to be untypedAtomic.
639      * The node must be a document, element, text,
640      * comment, or processing-instruction node, and it must have no type annotation.
641      * This method gets the typed value
642      * of a numbered node without actually instantiating the NodeInfo object, as
643      * a performance optimization.
644      */

645
646     UntypedAtomicValue getUntypedAtomicValue(int nodeNr) {
647         switch (nodeKind[nodeNr]) {
648             case Type.ELEMENT:
649             case Type.DOCUMENT:
650                 int level = depth[nodeNr];
651                 int next = nodeNr+1;
652
653                 // we optimize two special cases: firstly, where the node has no children, and secondly,
654
// where it has a single text node as a child.
655

656                 if (depth[next] <= level) {
657                     return UntypedAtomicValue.ZERO_LENGTH_UNTYPED;
658                 } else if (nodeKind[next] == Type.TEXT && depth[next+1] <= level) {
659                     int length = beta[next];
660                     int start = alpha[next];
661                     return new UntypedAtomicValue(new CharSlice(charBuffer, start, length));
662                 }
663
664                 // Now handle the general case
665

666                 StringBuffer JavaDoc sb = null;
667                 while (next < numberOfNodes && depth[next] > level) {
668                     if (nodeKind[next]==Type.TEXT) {
669                         if (sb==null) {
670                             sb = new StringBuffer JavaDoc(1024);
671                         }
672                         int length = beta[next];
673                         int start = alpha[next];
674                         sb.append(charBuffer, start, length);
675                     }
676                     next++;
677                 }
678                 if (sb==null) {
679                     return UntypedAtomicValue.ZERO_LENGTH_UNTYPED;
680                 } else {
681                     //sb.trimToSize(); // TODO: reinstate this in JDK 1.5
682
char[] buff = new char[sb.length()];
683                     sb.getChars(0, sb.length(), buff, 0);
684                     return new UntypedAtomicValue(new CharSlice(buff));
685                 }
686
687             case Type.TEXT:
688                 int start = alpha[nodeNr];
689                 int len = beta[nodeNr];
690                 return new UntypedAtomicValue(
691                         new CharSlice(charBuffer, start, len));
692             case Type.COMMENT:
693             case Type.PROCESSING_INSTRUCTION:
694                 int start2 = alpha[nodeNr];
695                 int len2 = beta[nodeNr];
696                 if (len2==0) return UntypedAtomicValue.ZERO_LENGTH_UNTYPED;
697                 char[] dest = new char[len2];
698                 commentBuffer.getChars(start2, start2+len2, dest, 0);
699                 return new UntypedAtomicValue(new CharSlice(dest, 0, len2));
700             default:
701                 throw new IllegalStateException JavaDoc("Unknown node kind");
702         }
703     }
704
705     /**
706     * Make a (transient) attribute node from the array of attributes
707     */

708
709     TinyAttributeImpl getAttributeNode(int nr) {
710         return new TinyAttributeImpl(this, nr);
711     }
712
713     /**
714     * Get the type annotation of an attribute node.
715     * The bit {@link NodeInfo#IS_DTD_TYPE} (1<<30) will be set in the case of an attribute node if the type annotation
716     * is one of ID, IDREF, or IDREFS and this is derived from DTD rather than schema validation.
717     * @return Type.UNTYPED_ATOMIC if there is no annotation
718     */

719
720     int getAttributeAnnotation(int nr) {
721         if (attTypeCode == null) {
722             return StandardNames.XDT_UNTYPED_ATOMIC;
723         } else {
724             return attTypeCode[nr] & (NamePool.FP_MASK | NodeInfo.IS_DTD_TYPE);
725         }
726     }
727
728     /**
729      * Determine whether an attribute is an IDREF/IDREFS attribute. (The represents the
730      * is-IDREF property in the data model
731      */

732
733     boolean isIdref(int nr) {
734         if (attTypeCode == null) {
735             return false;
736         } else {
737             int tc = attTypeCode[nr];
738             if ((attTypeCode[nr] & (1<<30)) != 0) {
739                 return true;
740             } else if (tc == Type.UNTYPED_ATOMIC) {
741                 return false;
742             } else if (tc == StandardNames.XS_IDREF) {
743                 return true;
744             } else if (tc == StandardNames.XS_IDREFS) {
745                 return true;
746             } else if (tc < 1024) {
747                 return false;
748             } else {
749                 SchemaType type = getConfiguration().getSchemaType(tc);
750                 if (type instanceof AtomicType) {
751                     return Type.isSubType((AtomicType)type,
752                             (AtomicType)BuiltInSchemaFactory.getSchemaType(StandardNames.XS_IDREF));
753                 } else if (type instanceof ListType) {
754                     SimpleType itemType = ((ListType)type).getItemType();
755                     if (!(itemType instanceof AtomicType)) {
756                         return false;
757                     }
758                     return Type.isSubType((AtomicType)itemType,
759                             (AtomicType)BuiltInSchemaFactory.getSchemaType(StandardNames.XS_IDREF));
760                 }
761             }
762         }
763         return false;
764     }
765
766     /**
767     * Set the system id of an element in the document. This identifies the external entity containing
768      * the node - this is not necessarily the same as the base URI.
769      * @param seq the node number
770      * @param uri the system ID
771     */

772
773     void setSystemId(int seq, String JavaDoc uri) {
774         if (uri==null) {
775             uri = "";
776         }
777         if (systemIdMap==null) {
778             systemIdMap = new SystemIdMap();
779         }
780         systemIdMap.setSystemId(seq, uri);
781     }
782
783
784     /**
785     * Get the system id of an element in the document
786     */

787
788     String JavaDoc getSystemId(int seq) {
789         if (systemIdMap==null) {
790             return null;
791         }
792         return systemIdMap.getSystemId(seq);
793     }
794
795     /**
796      * Get the root node for a given node
797      */

798
799     int getRootNode(int nodeNr) {
800         for (int i=rootIndexUsed-1; i>=0; i--) {
801             if (rootIndex[i] <= nodeNr) {
802                 return rootIndex[i];
803             }
804         }
805         return 0;
806     }
807
808     /**
809     * Set line numbering on
810     */

811
812     public void setLineNumbering() {
813         lineNumberMap = new LineNumberMap();
814         lineNumberMap.setLineNumber(0, 0);
815     }
816
817     /**
818     * Set the line number for an element. Ignored if line numbering is off.
819     */

820
821     void setLineNumber(int sequence, int line) {
822         if (lineNumberMap != null) {
823             lineNumberMap.setLineNumber(sequence, line);
824         }
825     }
826
827     /**
828     * Get the line number for an element. Return -1 if line numbering is off.
829     */

830
831     int getLineNumber(int sequence) {
832         if (lineNumberMap != null) {
833             return lineNumberMap.getLineNumber(sequence);
834         }
835         return -1;
836     }
837
838     /**
839      * Get the document number (actually, the tree number)
840      */

841
842     public int getDocumentNumber() {
843         return documentNumber;
844     }
845
846     /**
847      * Determine whether a given node is nilled
848      */

849
850     public boolean isNilled(int nodeNr) {
851         if (nodeKind[nodeNr] != Type.ELEMENT) {
852             return false;
853         }
854         if (typeCodeArray == null || typeCodeArray[nodeNr] == -1 || typeCodeArray[nodeNr] == StandardNames.XDT_UNTYPED) {
855             return false;
856         }
857         int index = alpha[nodeNr];
858         if (index > 0) {
859             while (attParent[index] == nodeNr && index < numberOfAttributes) {
860                 if (attCode[index] == StandardNames.XSI_NIL) {
861                     String JavaDoc val = attValue[index].toString().trim();
862                     if (val.equals("1") || val.equals("true")) {
863                         return true;
864                     }
865                 }
866                 index++;
867             }
868         }
869         return false;
870     }
871
872     /**
873     * Produce diagnostic print of main tree arrays
874     */

875
876     public void diagnosticDump() {
877         System.err.println(" node type depth next alpha beta name");
878         for (int i=0; i<numberOfNodes; i++) {
879             System.err.println(n8(i) + n8(nodeKind[i]) + n8(depth[i]) + n8(next[i]) +
880                                      n8(alpha[i]) + n8(beta[i]) + n8(nameCode[i]));
881         }
882         System.err.println(" attr parent name value");
883         for (int i=0; i<numberOfAttributes; i++) {
884             System.err.println(n8(i) + n8(attParent[i]) + n8(attCode[i]) + " " + attValue[i]);
885         }
886         System.err.println(" ns parent prefix uri");
887         for (int i=0; i<numberOfNamespaces; i++) {
888             System.err.println(n8(i) + n8(namespaceParent[i]) + n8(namespaceCode[i]>>16) + n8(namespaceCode[i]&0xffff));
889         }
890     }
891
892     /**
893     * Output a number as a string of 8 characters
894     */

895
896     private String JavaDoc n8(int val) {
897         String JavaDoc s = " " + val;
898         return s.substring(s.length()-8);
899     }
900
901     public void showSize() {
902         System.err.println("Tree size: " + numberOfNodes + " nodes, " + charBufferLength + " characters, " +
903                                 numberOfAttributes + " attributes");
904     }
905
906     /**
907      * Get the number of nodes in the tree, excluding attributes and namespace nodes
908      * @return the number of nodes.
909      */

910
911     public int getNumberOfNodes() {
912         return numberOfNodes;
913     }
914
915     public int getNumberOfAttributes() {
916         return numberOfAttributes;
917     }
918
919     public int getNumberOfNamespaces() {
920         return numberOfNamespaces;
921     }
922
923     public byte[] getNodeKindArray() {
924         return nodeKind;
925     }
926
927     public short[] getNodeDepthArray() {
928         return depth;
929     }
930
931     public int[] getNameCodeArray() {
932         return nameCode;
933     }
934
935     public int[] getTypeCodeArray() {
936         return typeCodeArray;
937     }
938
939     public int[] getNextPointerArray() {
940         return next;
941     }
942
943     public int[] getAlphaArray() {
944         return alpha;
945     }
946
947     public int[] getBetaArray() {
948         return beta;
949     }
950
951     public CharSequence JavaDoc getCharacterBuffer() {
952         return new CharSlice(charBuffer, 0, charBufferLength);
953     }
954
955     public CharSequence JavaDoc getCommentBuffer() {
956         return commentBuffer;
957     }
958
959     public int[] getAttributeNameCodeArray() {
960         return attCode;
961     }
962
963     public int[] getAttributeTypeCodeArray() {
964         return attTypeCode;
965     }
966
967     public int[] getAttributeParentArray() {
968         return attParent;
969     }
970
971     public CharSequence JavaDoc[] getAttributeValueArray() {
972         return attValue;
973     }
974
975     public int[] getNamespaceCodeArray() {
976         return namespaceCode;
977     }
978
979     public int[] getNamespaceParentArray() {
980         return namespaceParent;
981     }
982
983
984 }
985
986 //
987
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
988
// you may not use this file except in compliance with the License. You may obtain a copy of the
989
// License at http://www.mozilla.org/MPL/
990
//
991
// Software distributed under the License is distributed on an "AS IS" basis,
992
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
993
// See the License for the specific language governing rights and limitations under the License.
994
//
995
// The Original Code is: all this file
996
//
997
// The Initial Developer of the Original Code is Michael H. Kay.
998
//
999
// Contributor(s):
1000
//
1001
Popular Tags