001: package net.sf.saxon.event;
002:
003: import net.sf.saxon.Configuration;
004: import net.sf.saxon.Controller;
005: import net.sf.saxon.om.DocumentInfo;
006: import net.sf.saxon.om.NamePool;
007: import net.sf.saxon.om.NodeInfo;
008: import net.sf.saxon.om.StrippedDocument;
009: import net.sf.saxon.tinytree.TinyBuilder;
010: import net.sf.saxon.tinytree.TinyDocumentImpl;
011: import net.sf.saxon.trans.DynamicError;
012: import net.sf.saxon.trans.XPathException;
013: import net.sf.saxon.tree.TreeBuilder;
014:
015: import javax.xml.transform.Source;
016: import javax.xml.transform.dom.DOMSource;
017: import java.util.Date;
018:
019: /**
020: * The abstract Builder class is responsible for taking a stream of SAX events
021: * and constructing a Document tree. There is one concrete subclass for each
022: * tree implementation.
023: * @author Michael H. Kay
024: */
025:
026: public abstract class Builder implements Receiver {
027: public static final int STANDARD_TREE = 0;
028: public static final int TINY_TREE = 1;
029:
030: protected PipelineConfiguration pipe;
031: protected Configuration config;
032: protected NamePool namePool;
033: protected String systemId;
034: protected NodeInfo currentRoot;
035: protected boolean lineNumbering = false;
036:
037: protected boolean started = false;
038: protected boolean timing = false;
039:
040: private long startTime;
041:
042: /**
043: * create a Builder and initialise variables
044: */
045:
046: public Builder() {
047: }
048:
049: public void setPipelineConfiguration(PipelineConfiguration pipe) {
050: this .pipe = pipe;
051: this .config = pipe.getConfiguration();
052: this .namePool = config.getNamePool();
053: this .lineNumbering = (lineNumbering || config.isLineNumbering());
054: }
055:
056: public PipelineConfiguration getPipelineConfiguration() {
057: return pipe;
058: }
059:
060: public Configuration getConfiguration() {
061: return config;
062: }
063:
064: public void setSystemId(String systemId) {
065: this .systemId = systemId;
066: }
067:
068: public String getSystemId() {
069: return systemId;
070: }
071:
072: public void setLineNumbering(boolean is) {
073: lineNumbering = is;
074: }
075:
076: /////////////////////////////////////////////////////////////////////////
077: // Methods setting and getting options for building the tree
078: /////////////////////////////////////////////////////////////////////////
079:
080: /**
081: * Set the root (document) node to use. This method is used to support
082: * the JAXP facility to attach transformation output to a supplied Document
083: * node. It must be called before startDocument(), and the type of document
084: * node must be compatible with the type of Builder used.
085: */
086:
087: // public void setRootNode(DocumentInfo doc) {
088: // currentRoot = doc;
089: // }
090:
091: /**
092: * Set timing option on or off
093: */
094:
095: public void setTiming(boolean on) {
096: timing = on;
097: }
098:
099: /**
100: * Get timing option
101: */
102:
103: public boolean isTiming() {
104: return timing;
105: }
106:
107: public void open() throws XPathException {
108: if (timing) {
109: System.err.println("Building tree for " + getSystemId()
110: + " using " + getClass());
111: startTime = (new Date()).getTime();
112: }
113: }
114:
115: public void close() throws XPathException {
116: if (timing) {
117: long endTime = (new Date()).getTime();
118: System.err.println("Tree built in " + (endTime - startTime)
119: + " milliseconds");
120: if (currentRoot instanceof TinyDocumentImpl) {
121: ((TinyDocumentImpl) currentRoot).showSize();
122: }
123: startTime = endTime;
124: }
125: }
126:
127: /**
128: * Start of a document node.
129: * This event is ignored: we simply add the contained elements to the current document
130: */
131:
132: public void startDocument(int properties) throws XPathException {
133: }
134:
135: /**
136: * Notify the end of a document node
137: */
138:
139: public void endDocument() throws XPathException {
140: }
141:
142: /**
143: * Get the current root node. This will normally be a document node, but if the root of the tree
144: * is an element node, it can be an element.
145: * @return the root of the tree that is currently being built, or that has been most recently built
146: * using this builder
147: */
148:
149: public NodeInfo getCurrentRoot() {
150: return currentRoot;
151: }
152:
153: /**
154: * Static method to build a document from any kind of Source object. If the source
155: * is already in the form of a tree, it is wrapped as required.
156: * @param source Any javax.xml.transform.Source object
157: * @param stripper A stripper object, if whitespace text nodes are to be stripped;
158: * otherwise null.
159: * @param config The Configuration object
160: * @return the NodeInfo of the start node in the resulting document object.
161: */
162:
163: public static NodeInfo build(Source source, Stripper stripper,
164: Configuration config) throws XPathException {
165: return build(source, stripper, config
166: .makePipelineConfiguration());
167: }
168:
169: /**
170: * Static method to build a document from any kind of Source object. If the source
171: * is already in the form of a tree, it is wrapped as required.
172: * @param source Any javax.xml.transform.Source object
173: * @param stripper A stripper object, if whitespace text nodes are to be stripped;
174: * otherwise null.
175: * @param pipe The PipelineConfiguration object
176: * @return the NodeInfo of the start node in the resulting document object.
177: */
178:
179: public static NodeInfo build(Source source, Stripper stripper,
180: PipelineConfiguration pipe) throws XPathException {
181: Configuration config = pipe.getConfiguration();
182: if (source == null) {
183: throw new NullPointerException(
184: "Source supplied to builder cannot be null");
185: }
186:
187: NodeInfo start;
188: if (source instanceof DOMSource || source instanceof NodeInfo) {
189: start = Controller.unravel(source, config);
190: if (stripper != null) {
191: DocumentInfo docInfo = start.getDocumentRoot();
192: StrippedDocument strippedDoc = new StrippedDocument(
193: docInfo, stripper);
194: start = strippedDoc.wrap(start);
195: }
196:
197: } else {
198: // we have a SAXSource or StreamSource
199: Builder b;
200: if (config.getTreeModel() == Builder.TINY_TREE) {
201: b = new TinyBuilder();
202: } else {
203: b = new TreeBuilder();
204: }
205: b.setPipelineConfiguration(pipe);
206: b.setLineNumbering(config.isLineNumbering());
207: Receiver receiver = b;
208: if (stripper != null) {
209: stripper.setUnderlyingReceiver(b);
210: receiver = stripper;
211: }
212: try {
213: new Sender(pipe).send(source, receiver);
214: } catch (XPathException err) {
215: throw DynamicError.makeDynamicError(err);
216: }
217: start = b.getCurrentRoot();
218: }
219: return start;
220: }
221:
222: }
223:
224: //
225: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
226: // you may not use this file except in compliance with the License. You may obtain a copy of the
227: // License at http://www.mozilla.org/MPL/
228: //
229: // Software distributed under the License is distributed on an "AS IS" basis,
230: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
231: // See the License for the specific language governing rights and limitations under the License.
232: //
233: // The Original Code is: all this file.
234: //
235: // The Initial Developer of the Original Code is Michael H. Kay.
236: //
237: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
238: //
239: // Contributor(s): none.
240: //
|