KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > tree > TreeBuilder


1 package com.icl.saxon.tree;
2 import com.icl.saxon.om.*;
3 import com.icl.saxon.expr.*;
4 import com.icl.saxon.PreviewManager;
5 import com.icl.saxon.ExtendedInputSource;
6 import com.icl.saxon.Context;
7 import com.icl.saxon.Controller;
8
9 import org.xml.sax.*;
10 import org.xml.sax.helpers.*;
11 import javax.xml.transform.TransformerException JavaDoc;
12
13 import java.util.*;
14 import java.io.*;
15 import java.net.URL JavaDoc;
16
17 /**
18   * The Builder class is responsible for taking a stream of SAX events and constructing
19   * a Document tree.
20   * @author Michael H. Kay (mhkay@iclway.co.uk)
21   */

22   
23 public class TreeBuilder extends Builder
24
25 {
26     private static AttributeCollection emptyAttributeCollection =
27                     new AttributeCollection((NamePool)null);
28
29     private ParentNodeImpl currentNode;
30
31     private NodeFactory nodeFactory;
32     private int[] size = new int[100]; // stack of number of children for each open node
33
private int depth = 0;
34     private Vector arrays = new Vector(); // reusable arrays for creating nodes
35
private boolean previousText;
36     private StringBuffer JavaDoc charBuffer;
37
38     private int nextNodeNumber = 1;
39
40     /**
41     * create a Builder and initialise variables
42     */

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

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

60     /**
61     * Callback interface for SAX: not for application use
62     */

63
64     public void startDocument () throws TransformerException JavaDoc
65     {
66         // System.err.println("Builder: " + this + " Start document");
67
failed = false;
68         started = true;
69         
70         DocumentImpl doc;
71         if (currentDocument==null) {
72             // normal case
73
doc = new DocumentImpl();
74             currentDocument = doc;
75         } else {
76             // document node supplied by user
77
if (!(currentDocument instanceof DocumentImpl)) {
78                 throw new TransformerException JavaDoc("Root node supplied is of wrong type");
79             }
80             doc = (DocumentImpl)currentDocument;
81             if (doc.getFirstChild()!=null) {
82                 throw new TransformerException JavaDoc("Supplied document is not empty");
83             }
84             
85         }
86         if (locator==null || locator.getSystemId()==null) {
87             locator = this;
88         }
89         doc.setSystemId(locator.getSystemId());
90         doc.setNamePool(namePool);
91         doc.setNodeFactory(nodeFactory);
92         currentNode = doc;
93         depth = 0;
94         size[depth] = 0;
95         doc.sequence = 0;
96         charBuffer = new StringBuffer JavaDoc(estimatedLength);
97         doc.setCharacterBuffer(charBuffer);
98         if (lineNumbering) {
99             doc.setLineNumbering();
100         }
101
102         //startTime = (new Date()).getTime();
103
}
104
105     /**
106     * Callback interface for SAX: not for application use
107     */

108
109     public void endDocument () throws TransformerException JavaDoc
110     {
111         if (currentNode==null) return; // can be called twice on an error path
112
currentNode.compact(size[depth]);
113         currentNode = null;
114
115         // we're not going to use this Builder again so give the garbage collector
116
// something to play with
117
arrays = null;
118
119         //long endTime = (new Date()).getTime();
120
//System.err.println("Build time: " + (endTime-startTime) + " milliseconds");
121

122     }
123
124     /**
125     * Callback interface for SAX: not for application use
126     */

127     
128     public void setDocumentLocator (Locator locator)
129     {
130         this.locator = locator;
131     }
132
133     /**
134     * Callback interface for SAX: not for application use
135     */

136
137     public void startElement (
138         int nameCode, Attributes attributes, int[] namespaces, int namespacesUsed) throws TransformerException JavaDoc
139     {
140         // System.err.println("Start element (" + uri + ", " + localname + ", " + rawname + ")");
141

142         // Convert SAX2 Attributes object into an AttributeCollection
143
// the difference is historic, both classes perform the same function
144
// and could be combined.
145

146         AttributeCollection atts;
147         int numAtts = attributes.getLength();
148         if (numAtts==0) {
149             atts = emptyAttributeCollection;
150         } else {
151             atts = new AttributeCollection(namePool, attributes);
152         }
153                 // System.err.println("TreeBuilder.locator = " + locator);
154
// System.err.println("TreeBuilder.baseURI = " + baseURI);
155
ElementImpl elem = nodeFactory.makeElementNode( currentNode,
156                                                         nameCode,
157                                                         atts,
158                                                         namespaces,
159                                                         namespacesUsed,
160                                                         locator,
161                                                         nextNodeNumber++);
162                                                         
163         // the initial aray used for pointing to children will be discarded when the exact number
164
// of children in known. Therefore, it can be reused. So we allocate an initial array from
165
// a pool of reusable arrays. A nesting depth of >20 is so rare that we don't bother.
166

167         while (depth >= arrays.size()) {
168             arrays.addElement(new NodeImpl[20]);
169         }
170         elem.useChildrenArray((NodeImpl[])arrays.elementAt(depth));
171
172         currentNode.addChild(elem, size[depth]++);
173         if (depth >= size.length - 1) {
174             int[] newsize = new int[size.length * 2];
175             System.arraycopy(size, 0, newsize, 0, size.length);
176             size = newsize;
177         }
178         size[++depth] = 0;
179             
180         namespacesUsed = 0;
181         
182         if (currentNode instanceof DocumentInfo) {
183             ((DocumentImpl)currentNode).setDocumentElement(elem);
184         }
185
186
187         currentNode = elem;
188     }
189
190     /**
191     * Callback interface for SAX: not for application use
192     */

193
194     public void endElement (int nameCode) throws TransformerException JavaDoc
195     {
196         // System.err.println("End element " + namePool.getDisplayName(nameCode));
197
currentNode.compact(size[depth]);
198
199         // if a preview handler is registered, call it now
200
if (previewManager != null) {
201             
202             if (previewManager.isPreviewElement(currentNode.getFingerprint())) {
203                 //Controller c = previewManager.getController();
204
Context context = controller.makeContext(currentNode);
205                 controller.applyTemplates(
206                     context,
207                     new SingletonNodeSet(currentNode),
208                     controller.getRuleManager().getMode(previewManager.getPreviewMode()),
209                     null);
210                 currentNode.dropChildren();
211             }
212         }
213         
214         depth--;
215         currentNode = (ParentNodeImpl)currentNode.getParentNode();
216     }
217
218     /**
219     * Callback interface for SAX: not for application use
220     */

221
222     public void characters (char ch[], int start, int length) throws TransformerException JavaDoc
223     {
224         // System.err.println("Characters: " + new String(ch, start, length));
225
if (length>0) {
226             int bufferStart = charBuffer.length();
227             //charBuffer.append(ch, start, length);
228

229             // we rely on adjacent chunks of text having already been merged
230
//TextImpl n = new TextImpl(currentNode, bufferStart, length);
231
TextImpl n = new TextImpl(currentNode, new String JavaDoc(ch, start, length));
232             currentNode.addChild(n, size[depth]++);
233             previousText = true;
234            
235         }
236     }
237     
238     /**
239     * Callback interface for SAX: not for application use<BR>
240     * Note: because SAX1 does not deliver comment nodes, we get these in the form of a processing
241     * instruction with a null name. This requires a specially-adapted SAX driver.
242     */

243
244     public void processingInstruction (String JavaDoc name, String JavaDoc remainder)
245     {
246         if (!discardComments) {
247             int nameCode = namePool.allocate("", "", name);
248             ProcInstImpl pi = new ProcInstImpl(nameCode, remainder);
249             currentNode.addChild(pi, size[depth]++);
250             if (locator!=null) {
251                 pi.setLocation(locator.getSystemId(), locator.getLineNumber());
252             }
253         }
254     }
255
256     /**
257     * Callback interface for SAX (part of LexicalHandler interface): not for application use
258     */

259  
260     public void comment (char ch[], int start, int length) throws TransformerException JavaDoc
261     {
262         if (!discardComments) {
263             CommentImpl comment = new CommentImpl(new String JavaDoc(ch, start, length));
264             currentNode.addChild(comment, size[depth]++);
265         }
266     }
267
268
269     /**
270     * graftElement() allows an element node to be transferred from one tree to another.
271     * This is a dangerous internal interface which is used only to contruct a stylesheet
272     * tree from a stylesheet using the "literal result element as stylesheet" syntax.
273     * The supplied element is grafted onto the current element as its only child.
274     */

275
276     public void graftElement(ElementImpl element) throws TransformerException JavaDoc {
277         currentNode.addChild(element, size[depth]++);
278     }
279
280     /**
281     * Set an unparsed entity URI for the document
282     */

283
284     public void setUnparsedEntity(String JavaDoc name, String JavaDoc uri) {
285         ((DocumentImpl)currentDocument).setUnparsedEntity(name, uri);
286     }
287
288
289     //////////////////////////////////////////////////////////////////////////////
290
// Inner class DefaultNodeFactory. This creates the nodes in the tree.
291
// It can be overridden, e.g. when building the stylesheet tree
292
//////////////////////////////////////////////////////////////////////////////
293

294     private class DefaultNodeFactory implements NodeFactory {
295
296         public ElementImpl makeElementNode(
297                 NodeInfo parent,
298                 int nameCode,
299                 AttributeCollection attlist,
300                 int[] namespaces,
301                 int namespacesUsed,
302                 Locator locator,
303                 int sequenceNumber)
304                     
305         {
306             if (attlist.getLength()==0 && namespacesUsed==0) {
307                 
308                 // for economy, use a simple ElementImpl node
309

310                 ElementImpl e = new ElementImpl();
311                 String JavaDoc baseURI = null;
312                 int lineNumber = -1;
313
314                 if (locator!=null) {
315                     baseURI = locator.getSystemId();
316                     lineNumber = locator.getLineNumber();
317                 }
318
319                 e.initialise(nameCode, attlist, parent, baseURI, lineNumber, sequenceNumber);
320
321                 return e;
322
323             } else {
324                 ElementWithAttributes e = new ElementWithAttributes();
325                 String JavaDoc baseURI = null;
326                 int lineNumber = -1;
327
328                 if (locator!=null) {
329                     baseURI = locator.getSystemId();
330                     lineNumber = locator.getLineNumber();
331                 }
332             
333                 e.setNamespaceDeclarations(namespaces, namespacesUsed);
334
335                 e.initialise(nameCode, attlist, parent, baseURI, lineNumber, sequenceNumber);
336
337                 return e;
338             }
339         }
340     }
341
342
343 } // end of outer class TreeBuilder
344

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