KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > tree > TreeBuilder


1 package net.sf.saxon.tree;
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.AttributeCollectionImpl;
6 import net.sf.saxon.om.DocumentInfo;
7 import net.sf.saxon.om.NodeInfo;
8 import net.sf.saxon.trans.DynamicError;
9 import net.sf.saxon.trans.XPathException;
10
11 import java.util.ArrayList JavaDoc;
12
13
14 /**
15   * The Builder class is responsible for taking a stream of SAX events and constructing
16   * a Document tree.
17   * @author Michael H. Kay
18   */

19
20 public class TreeBuilder extends Builder
21
22 {
23     private static AttributeCollectionImpl emptyAttributeCollection =
24                     new AttributeCollectionImpl(null);
25
26     private ParentNodeImpl currentNode;
27
28     private NodeFactory nodeFactory;
29     private int[] size = new int[100]; // stack of number of children for each open node
30
private int depth = 0;
31     private ArrayList JavaDoc arrays = new ArrayList JavaDoc(20); // reusable arrays for creating nodes
32
private int pendingElement;
33     private int pendingLocationId;
34     private AttributeCollectionImpl attributes;
35     private int[] namespaces;
36     private int namespacesUsed;
37
38     private int nextNodeNumber = 1;
39     private static final int[] EMPTY_ARRAY_OF_INT = new int[0];
40
41     /**
42     * create a Builder and initialise variables
43     */

44
45     public TreeBuilder() {
46         nodeFactory = new DefaultNodeFactory();
47         // System.err.println("new TreeBuilder " + this);
48
}
49
50     /**
51     * Set the Node Factory to use. If none is specified, the Builder uses its own.
52     */

53
54     public void setNodeFactory(NodeFactory factory) {
55         nodeFactory = factory;
56     }
57
58   ////////////////////////////////////////////////////////////////////////////////////////
59
// Implement the org.xml.sax.ContentHandler interface.
60
////////////////////////////////////////////////////////////////////////////////////////
61

62     /**
63     * Callback interface for SAX: not for application use
64     */

65
66     public void open () throws XPathException
67     {
68         // System.err.println("TreeBuilder: " + this + " Start document depth=" + depth);
69
//failed = false;
70
started = true;
71
72         DocumentImpl doc;
73         if (currentRoot==null) {
74             // normal case
75
doc = new DocumentImpl();
76             currentRoot = doc;
77         } else {
78             // document node supplied by user
79
if (!(currentRoot instanceof DocumentImpl)) {
80                 throw new DynamicError("Document node supplied is of wrong kind (" +
81                         currentRoot.getClass().getName() + ')');
82             }
83             doc = (DocumentImpl)currentRoot;
84             if (doc.getFirstChild()!=null) {
85                 throw new DynamicError("Supplied document is not empty");
86             }
87
88         }
89
90         doc.setSystemId(getSystemId());
91         doc.setConfiguration(config);
92         currentNode = doc;
93         depth = 0;
94         size[depth] = 0;
95         doc.sequence = 0;
96         //charBuffer = new StringBuffer(4096);
97
//doc.setCharacterBuffer(charBuffer);
98
if (lineNumbering) {
99             doc.setLineNumbering();
100         }
101
102         super.open();
103     }
104
105     /**
106     * Callback interface for SAX: not for application use
107     */

108
109     public void close () throws XPathException
110     {
111         // System.err.println("TreeBuilder: " + this + " End document");
112
if (currentNode==null) return; // can be called twice on an error path
113
currentNode.compact(size[depth]);
114         currentNode = null;
115
116         // we're not going to use this Builder again so give the garbage collector
117
// something to play with
118
arrays = null;
119
120         super.close();
121         nodeFactory = null;
122
123     }
124
125     /**
126     * Notify the start of an element
127     */

128
129     public void startElement (int nameCode, int typeCode, int locationId, int properties) throws XPathException {
130         // System.err.println("TreeBuilder: " + this + " Start element depth=" + depth);
131

132         pendingElement = nameCode;
133         pendingLocationId = locationId;
134         namespaces = null;
135         namespacesUsed = 0;
136         attributes = null;
137     }
138
139     public void namespace (int namespaceCode, int properties) {
140         if (namespaces==null) {
141             namespaces = new int[5];
142         }
143         if (namespacesUsed == namespaces.length) {
144             int[] ns2 = new int[namespaces.length * 2];
145             System.arraycopy(namespaces, 0, ns2, 0, namespacesUsed);
146             namespaces = ns2;
147         }
148         namespaces[namespacesUsed++] = namespaceCode;
149     }
150
151     public void attribute(int nameCode, int typeCode, CharSequence JavaDoc value, int locationId, int properties)
152     throws XPathException {
153
154 // if ((properties & ReceiverOptions.DISABLE_ESCAPING) != 0) {
155
// throw new DynamicError("Cannot disable output escaping when writing a tree");
156
// }
157
properties &= ~ReceiverOptions.DISABLE_ESCAPING;
158
159         if (attributes==null) {
160             attributes = new AttributeCollectionImpl(namePool);
161         }
162 // String attType = "CDATA";
163
// if (typeCode == Type.ID || (properties & ReceiverOptions.DTD_ID_ATTRIBUTE) != 0) {
164
// attType = "ID";
165
// }
166
attributes.addAttribute(nameCode, typeCode, value.toString(), locationId, properties);
167     }
168
169     public void startContent() throws XPathException {
170         // System.err.println("TreeBuilder: " + this + " startContent()");
171
if (attributes == null) {
172             attributes = emptyAttributeCollection;
173         } else {
174             attributes.compact();
175         }
176
177         if (namespaces == null) {
178             namespaces = EMPTY_ARRAY_OF_INT;
179         }
180
181         ElementImpl elem = nodeFactory.makeElementNode( currentNode,
182                                                         pendingElement,
183                                                         attributes,
184                                                         namespaces,
185                                                         namespacesUsed,
186                                                         pipe.getLocationProvider(),
187                                                         pendingLocationId,
188                                                         nextNodeNumber++);
189
190         namespaces = null;
191         namespacesUsed = 0;
192         attributes = null;
193
194         // the initial array used for pointing to children will be discarded when the exact number
195
// of children in known. Therefore, it can be reused. So we allocate an initial array from
196
// a pool of reusable arrays. A nesting depth of >20 is so rare that we don't bother.
197

198         while (depth >= arrays.size()) {
199             arrays.add(new NodeImpl[20]);
200         }
201         elem.useChildrenArray((NodeImpl[])arrays.get(depth));
202
203         currentNode.addChild(elem, size[depth]++);
204         if (depth >= size.length - 1) {
205             int[] newsize = new int[size.length * 2];
206             System.arraycopy(size, 0, newsize, 0, size.length);
207             size = newsize;
208         }
209         size[++depth] = 0;
210         namespacesUsed = 0;
211
212         if (currentNode instanceof DocumentInfo) {
213             ((DocumentImpl)currentNode).setDocumentElement(elem);
214         }
215
216         currentNode = elem;
217     }
218
219     /**
220     * Notify the end of an element
221     */

222
223     public void endElement () throws XPathException
224     {
225         // System.err.println("End element depth=" + depth);
226
currentNode.compact(size[depth]);
227         depth--;
228         currentNode = (ParentNodeImpl)currentNode.getParent();
229     }
230
231     /**
232     * Notify a text node. Adjacent text nodes must have already been merged
233     */

234
235     public void characters (CharSequence JavaDoc chars, int locationId, int properties) throws XPathException
236     {
237         // System.err.println("Characters: " + chars.toString() + " depth=" + depth);
238
if (chars.length()>0) {
239
240 // if ((properties & ReceiverOptions.DISABLE_ESCAPING) != 0) {
241
// throw new DynamicError("Cannot disable output escaping when writing a tree");
242
// }
243

244             // we rely on adjacent chunks of text having already been merged
245
//TextImpl n = new TextImpl(currentNode, bufferStart, length);
246
TextImpl n = new TextImpl(currentNode, chars.toString());
247             currentNode.addChild(n, size[depth]++);
248         }
249     }
250
251     /**
252     * Notify a processing instruction
253     */

254
255     public void processingInstruction (String JavaDoc name, CharSequence JavaDoc remainder, int locationId, int properties)
256     {
257         int nameCode = namePool.allocate("", "", name);
258         ProcInstImpl pi = new ProcInstImpl(nameCode, remainder.toString());
259         currentNode.addChild(pi, size[depth]++);
260         LocationProvider locator = pipe.getLocationProvider();
261         if (locator!=null) {
262             pi.setLocation(locator.getSystemId(locationId),
263                            locator.getLineNumber(locationId));
264         }
265     }
266
267     /**
268     * Notify a comment
269     */

270
271     public void comment (CharSequence JavaDoc chars, int locationId, int properties) throws XPathException {
272         CommentImpl comment = new CommentImpl(chars.toString());
273         currentNode.addChild(comment, size[depth]++);
274     }
275
276
277     /**
278     * graftElement() allows an element node to be transferred from one tree to another.
279     * This is a dangerous internal interface which is used only to contruct a stylesheet
280     * tree from a stylesheet using the "literal result element as stylesheet" syntax.
281     * The supplied element is grafted onto the current element as its only child.
282     */

283
284     public void graftElement(ElementImpl element) throws XPathException {
285         currentNode.addChild(element, size[depth]++);
286     }
287
288     /**
289     * Set an unparsed entity URI for the document
290     */

291
292     public void setUnparsedEntity(String JavaDoc name, String JavaDoc uri, String JavaDoc publicId) {
293         ((DocumentImpl)currentRoot).setUnparsedEntity(name, uri, publicId);
294     }
295
296
297     //////////////////////////////////////////////////////////////////////////////
298
// Inner class DefaultNodeFactory. This creates the nodes in the tree.
299
// It can be overridden, e.g. when building the stylesheet tree
300
//////////////////////////////////////////////////////////////////////////////
301

302     private static class DefaultNodeFactory implements NodeFactory {
303
304         public ElementImpl makeElementNode(
305                 NodeInfo parent,
306                 int nameCode,
307                 AttributeCollectionImpl attlist,
308                 int[] namespaces,
309                 int namespacesUsed,
310                 LocationProvider locator,
311                 int locationId,
312                 int sequenceNumber)
313
314         {
315             ElementImpl e;
316             if (attlist.getLength()==0 && namespacesUsed==0) {
317                 // for economy, use a simple ElementImpl node
318
e = new ElementImpl();
319             } else {
320                 e = new ElementWithAttributes();
321                 if (namespacesUsed > 0) {
322                     ((ElementWithAttributes)e).setNamespaceDeclarations(namespaces, namespacesUsed);
323                 }
324             }
325             String JavaDoc baseURI = null;
326             int lineNumber = -1;
327
328             if (locator!=null) {
329                 baseURI = locator.getSystemId(locationId);
330                 lineNumber = locator.getLineNumber(locationId);
331             }
332
333             e.initialise(nameCode, attlist, parent, baseURI, lineNumber, sequenceNumber);
334             return e;
335         }
336     }
337
338 }
339
340 //
341
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
342
// you may not use this file except in compliance with the License. You may obtain a copy of the
343
// License at http://www.mozilla.org/MPL/
344
//
345
// Software distributed under the License is distributed on an "AS IS" basis,
346
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
347
// See the License for the specific language governing rights and limitations under the License.
348
//
349
// The Original Code is: all this file.
350
//
351
// The Initial Developer of the Original Code is Michael H. Kay.
352
//
353
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
354
//
355
// Contributor(s): none.
356
//
357
Popular Tags