KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.tinytree;
2 import net.sf.saxon.event.Builder;
3 import net.sf.saxon.event.LocationProvider;
4 import net.sf.saxon.event.ReceiverOptions;
5 import net.sf.saxon.om.FastStringBuffer;
6 import net.sf.saxon.style.StandardNames;
7 import net.sf.saxon.trans.XPathException;
8 import net.sf.saxon.type.Type;
9
10
11 /**
12   * The TinyBuilder class is responsible for taking a stream of SAX events and constructing
13   * a Document tree, using the "TinyTree" implementation.
14   *
15   * @author Michael H. Kay
16   */

17
18 public class TinyBuilder extends Builder {
19
20     public static final int PARENT_POINTER_INTERVAL = 10;
21             // a lower value allocates more parent pointers which takes more space but reduces
22
// the length of parent searches
23

24     private TinyTree tree;
25
26     private int currentDepth = 0;
27     private int nodeNr = 0; // this is the local sequence within this document
28
private boolean ended = false;
29     private int[] sizeParameters; // estimate of number of nodes, attributes, namespaces, characters
30

31     public void setSizeParameters(int[] params) {
32         sizeParameters = params;
33     }
34
35     public int[] getSizeParameters() {
36         int[] params = {tree.numberOfNodes, tree.numberOfAttributes, tree.numberOfNamespaces, tree.charBufferLength};
37         return params;
38     }
39
40     private int[] prevAtDepth = new int[100];
41             // this array is scaffolding used while constructing the tree, it is
42
// not present in the final tree. For each level of the tree, it records the
43
// node number of the most recent node at that level.
44

45     private int[] siblingsAtDepth = new int[100];
46             // more scaffolding. For each level of the tree, this array records the
47
// number of siblings processed at that level. When this exceeds a threshold value,
48
// a dummy node is inserted into the arrays to contain a parent pointer: this it to
49
// prevent excessively long searches for a parent node, which is normally found by
50
// scanning the siblings.
51

52     private boolean isIDElement = false;
53
54     public TinyTree getTree() {
55         return tree;
56     }
57
58     /**
59      * Open the event stream
60      */

61
62     public void open() throws XPathException {
63         if (started) {
64             // this happens when using an IdentityTransformer
65
return;
66         }
67         if (tree == null) {
68             if (sizeParameters==null) {
69                 tree = new TinyTree();
70             } else {
71                 tree = new TinyTree(sizeParameters[0],
72                                         sizeParameters[1], sizeParameters[2], sizeParameters[3]);
73             }
74             tree.setConfiguration(config);
75             currentDepth = 0;
76             if (lineNumbering) {
77                 tree.setLineNumbering();
78             }
79         }
80         super.open();
81     }
82
83     /**
84     * Write a document node to the tree
85     */

86
87     public void startDocument (int properties) throws XPathException {
88 // if (currentDepth == 0 && tree.numberOfNodes != 0) {
89
// System.err.println("**** FOREST DOCUMENT ****");
90
// }
91
if ((started && !ended) || currentDepth > 0) {
92             // this happens when using an IdentityTransformer, or when copying a document node to form
93
// the content of an element
94
return;
95         }
96         started = true;
97
98         //if (currentRoot==null) {
99
// normal case
100
currentRoot = new TinyDocumentImpl(tree);
101             TinyDocumentImpl doc = (TinyDocumentImpl)currentRoot;
102             doc.setSystemId(getSystemId());
103             doc.setConfiguration(config);
104             //tree.document = doc;
105
// } else {
106
// // document node supplied by user
107
// if (!(currentRoot instanceof TinyDocumentImpl)) {
108
// throw new DynamicError("Document node supplied is of wrong kind (" +
109
// currentRoot.getClass().getName() + ')');
110
// }
111
// if (currentRoot.hasChildNodes()) {
112
// throw new DynamicError("Supplied document is not empty");
113
// }
114
// //currentRoot.setConfiguration(config);
115
// }
116

117         currentDepth = 0;
118         tree.addDocumentNode((TinyDocumentImpl)currentRoot);
119         prevAtDepth[0] = 0;
120         prevAtDepth[1] = -1;
121         siblingsAtDepth[0] = 0;
122         siblingsAtDepth[1] = 0;
123         tree.next[0] = -1;
124
125         currentDepth++;
126
127         super.startDocument(0);
128
129     }
130
131     /**
132     * Callback interface for SAX: not for application use
133     */

134
135     public void endDocument () throws XPathException {
136              // System.err.println("TinyBuilder: " + this + " End document");
137

138         if (currentDepth > 1) return;
139             // happens when copying a document node as the child of an element
140

141         if (ended) return; // happens when using an IdentityTransformer
142
ended = true;
143
144         prevAtDepth[currentDepth] = -1;
145
146
147
148         //super.close();
149
}
150
151     public void close() throws XPathException {
152         tree.addNode(Type.STOPPER, 0, 0, 0, 0);
153         tree.condense();
154         super.close();
155     }
156
157     /**
158     * Notify the start tag of an element
159     */

160
161     public void startElement (int nameCode, int typeCode, int locationId, int properties) throws XPathException
162     {
163 // if (currentDepth == 0 && tree.numberOfNodes != 0) {
164
// System.err.println("**** FOREST ELEMENT ****");
165
// }
166

167         // if the number of siblings exceeds a certain threshold, add a parent pointer, in the form
168
// of a pseudo-node
169
if (siblingsAtDepth[currentDepth] > PARENT_POINTER_INTERVAL) {
170             nodeNr = tree.addNode(Type.PARENT_POINTER, currentDepth, prevAtDepth[currentDepth-1], 0, 0);
171             int prev = prevAtDepth[currentDepth];
172             if (prev > 0) {
173                 tree.next[prev] = nodeNr;
174             }
175             tree.next[nodeNr] = prevAtDepth[currentDepth-1];
176             prevAtDepth[currentDepth] = nodeNr;
177             siblingsAtDepth[currentDepth] = 0;
178         }
179
180         // now add the element node itself
181
nodeNr = tree.addNode(Type.ELEMENT, currentDepth, -1, -1, nameCode);
182
183         isIDElement = false;
184         if (typeCode != StandardNames.XDT_UNTYPED && typeCode != -1) {
185             tree.setElementAnnotation(nodeNr, typeCode);
186             if (tree.isIDCode(typeCode)) {
187                 isIDElement = true;
188             }
189         }
190
191         if (currentDepth == 0) {
192             prevAtDepth[0] = nodeNr;
193             prevAtDepth[1] = -1;
194             //tree.next[0] = -1;
195
currentRoot = tree.getNode(nodeNr);
196         } else {
197             int prev = prevAtDepth[currentDepth];
198             if (prev > 0) {
199                 tree.next[prev] = nodeNr;
200             }
201             tree.next[nodeNr] = prevAtDepth[currentDepth - 1]; // *O* owner pointer in last sibling
202
prevAtDepth[currentDepth] = nodeNr;
203             siblingsAtDepth[currentDepth]++;
204         }
205         currentDepth++;
206
207         if (currentDepth == prevAtDepth.length) {
208             int[] p2 = new int[currentDepth*2];
209             System.arraycopy(prevAtDepth, 0, p2, 0, currentDepth);
210             prevAtDepth = p2;
211             p2 = new int[currentDepth*2];
212             System.arraycopy(siblingsAtDepth, 0, p2, 0, currentDepth);
213             siblingsAtDepth = p2;
214         }
215         prevAtDepth[currentDepth] = -1;
216         siblingsAtDepth[currentDepth] = 0;
217
218         LocationProvider locator = pipe.getLocationProvider();
219         if (locator != null) {
220             tree.setSystemId(nodeNr, locator.getSystemId(locationId));
221             if (lineNumbering) {
222                 tree.setLineNumber(nodeNr, locator.getLineNumber(locationId));
223             }
224         }
225     }
226
227     public void namespace(int namespaceCode, int properties) throws XPathException {
228         tree.addNamespace( nodeNr, namespaceCode );
229     }
230
231     public void attribute(int nameCode, int typeCode, CharSequence JavaDoc value, int locationId, int properties)
232     throws XPathException {
233         // System.err.println("attribute " + nameCode + "=" + value);
234

235         properties &= ~ReceiverOptions.DISABLE_ESCAPING;
236         tree.addAttribute(currentRoot, nodeNr, nameCode, typeCode, value, properties);
237     }
238
239     public void startContent() {
240         nodeNr++;
241     }
242
243     /**
244     * Callback interface for SAX: not for application use
245     */

246
247     public void endElement () throws XPathException {
248         prevAtDepth[currentDepth] = -1;
249         siblingsAtDepth[currentDepth] = 0;
250         currentDepth--;
251         if (isIDElement) {
252             tree.indexIDElement(currentRoot, prevAtDepth[currentDepth]);
253             isIDElement = false;
254         }
255     }
256
257     /**
258     * Callback interface for SAX: not for application use
259     */

260
261     public void characters (CharSequence JavaDoc chars, int locationId, int properties) throws XPathException
262     {
263         if (chars.length()>0) {
264             //properties &= ~ReceiverOptions.DISABLE_ESCAPING;
265
int bufferStart = tree.charBufferLength;
266             tree.appendChars(chars);
267             int n=tree.numberOfNodes-1;
268             if (tree.nodeKind[n] == Type.TEXT && tree.depth[n] == currentDepth) {
269                 // merge this text node with the previous text node
270
tree.beta[n] += chars.length();
271             } else {
272                 nodeNr = tree.addNode(Type.TEXT, currentDepth, bufferStart, chars.length(), -1);
273
274                 int prev = prevAtDepth[currentDepth];
275                 if (prev > 0) {
276                     tree.next[prev] = nodeNr;
277                 }
278                 tree.next[nodeNr] = prevAtDepth[currentDepth - 1]; // *O* owner pointer in last sibling
279
prevAtDepth[currentDepth] = nodeNr;
280                 siblingsAtDepth[currentDepth]++;
281             }
282         }
283     }
284
285     /**
286     * Callback interface for SAX: not for application use<BR>
287     */

288
289     public void processingInstruction (String JavaDoc piname, CharSequence JavaDoc remainder, int locationId, int properties) throws XPathException
290     {
291         if (tree.commentBuffer==null) {
292             tree.commentBuffer = new FastStringBuffer(200);
293         }
294         int s = tree.commentBuffer.length();
295         tree.commentBuffer.append(remainder.toString());
296         int nameCode = namePool.allocate("", "", piname);
297
298         nodeNr = tree.addNode(Type.PROCESSING_INSTRUCTION, currentDepth, s, remainder.length(),
299                      nameCode);
300
301         int prev = prevAtDepth[currentDepth];
302         if (prev > 0) {
303             tree.next[prev] = nodeNr;
304         }
305         tree.next[nodeNr] = prevAtDepth[currentDepth - 1]; // *O* owner pointer in last sibling
306
prevAtDepth[currentDepth] = nodeNr;
307         siblingsAtDepth[currentDepth]++;
308
309         LocationProvider locator = pipe.getLocationProvider();
310         if (locator != null) {
311             tree.setSystemId(nodeNr, locator.getSystemId(locationId));
312             if (lineNumbering) {
313                 tree.setLineNumber(nodeNr, locator.getLineNumber(locationId));
314             }
315         }
316     }
317
318     /**
319     * Callback interface for SAX: not for application use
320     */

321
322     public void comment (CharSequence JavaDoc chars, int locationId, int properties) throws XPathException {
323         if (tree.commentBuffer==null) {
324             tree.commentBuffer = new FastStringBuffer(200);
325         }
326         int s = tree.commentBuffer.length();
327         tree.commentBuffer.append(chars.toString());
328         nodeNr = tree.addNode(Type.COMMENT, currentDepth, s, chars.length(), -1);
329
330         int prev = prevAtDepth[currentDepth];
331         if (prev > 0) {
332             tree.next[prev] = nodeNr;
333         }
334         tree.next[nodeNr] = prevAtDepth[currentDepth - 1]; // *O* owner pointer in last sibling
335
prevAtDepth[currentDepth] = nodeNr;
336         siblingsAtDepth[currentDepth]++;
337
338     }
339
340     /**
341     * Set an unparsed entity in the document
342     */

343
344     public void setUnparsedEntity(String JavaDoc name, String JavaDoc uri, String JavaDoc publicId) {
345         ((TinyDocumentImpl)currentRoot).setUnparsedEntity(name, uri, publicId);
346     }
347
348 }
349
350 //
351
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
352
// you may not use this file except in compliance with the License. You may obtain a copy of the
353
// License at http://www.mozilla.org/MPL/
354
//
355
// Software distributed under the License is distributed on an "AS IS" basis,
356
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
357
// See the License for the specific language governing rights and limitations under the License.
358
//
359
// The Original Code is: all this file.
360
//
361
// The Initial Developer of the Original Code is Michael H. Kay.
362
//
363
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
364
//
365
// Contributor(s): none.
366
//
367
Popular Tags