001: package net.sf.saxon;
002:
003: //import net.sf.saxon.dom.NodeOverNodeInfo;
004: import net.sf.saxon.event.CommentStripper;
005: import net.sf.saxon.event.PipelineConfiguration;
006: import net.sf.saxon.event.Sender;
007: import net.sf.saxon.event.StartTagBuffer;
008: import net.sf.saxon.instruct.Executable;
009: import net.sf.saxon.om.NamePool;
010: import net.sf.saxon.om.Validation;
011: import net.sf.saxon.style.*;
012: import net.sf.saxon.trans.StaticError;
013: import net.sf.saxon.trans.XPathException;
014: import net.sf.saxon.tree.DocumentImpl;
015: import net.sf.saxon.tree.TreeBuilder;
016: import org.xml.sax.XMLReader;
017:
018: import javax.xml.transform.*;
019: import java.io.FileInputStream;
020: import java.io.IOException;
021: import java.io.ObjectInputStream;
022: import java.io.Serializable;
023: import java.math.BigDecimal;
024: import java.util.Properties;
025:
026: /**
027: * This <B>PreparedStylesheet</B> class represents a Stylesheet that has been
028: * prepared for execution (or "compiled").
029: */
030:
031: public class PreparedStylesheet implements Templates, Serializable {
032:
033: private Executable executable;
034: private transient Configuration config;
035: private NamePool targetNamePool; // the namepool used when the stylesheet was compiled,
036: // saved here so it can be used again when the stylesheet is run
037: private transient StyleNodeFactory nodeFactory;
038: private int errorCount = 0;
039:
040: /**
041: * Constructor: deliberately protected
042: *
043: * @param config The Configuration set up by the TransformerFactory
044: */
045:
046: protected PreparedStylesheet(Configuration config) {
047: this .config = config;
048: }
049:
050: /**
051: * Make a Transformer from this Templates object.
052: *
053: * @return the new Transformer (always a Controller)
054: * @see net.sf.saxon.Controller
055: */
056:
057: public Transformer newTransformer() {
058: Controller c = new Controller(config, executable);
059: c.setPreparedStylesheet(this );
060: return c;
061: }
062:
063: public void setConfiguration(Configuration config) {
064: this .config = config;
065: }
066:
067: public Configuration getConfiguration() {
068: return config;
069: }
070:
071: /**
072: * Set the name pool
073: */
074:
075: public void setTargetNamePool(NamePool pool) {
076: targetNamePool = pool;
077: }
078:
079: /**
080: * Get the name pool in use. This is the namepool used for names that need to be accessible
081: * at runtime, notably the names used in XPath expressions in the stylesheet.
082: *
083: * @return the name pool in use
084: */
085:
086: public NamePool getTargetNamePool() {
087: if (targetNamePool == null) {
088: return config.getNamePool();
089: } else {
090: return targetNamePool;
091: }
092: }
093:
094: /**
095: * Get the StyleNodeFactory in use. The StyleNodeFactory determines which subclass of StyleElement
096: * to use for each element node in the stylesheet tree.
097: *
098: * @return the StyleNodeFactory
099: */
100:
101: public StyleNodeFactory getStyleNodeFactory() {
102: return nodeFactory;
103: }
104:
105: /**
106: * Prepare a stylesheet from a Source document
107: *
108: * @param styleSource the source document containing the stylesheet
109: * @exception TransformerConfigurationException if compilation of the
110: * stylesheet fails for any reason
111: */
112:
113: protected void prepare(Source styleSource)
114: throws TransformerConfigurationException {
115: nodeFactory = new StyleNodeFactory(config);
116: DocumentImpl doc;
117: try {
118: doc = loadStylesheetModule(styleSource, config, config
119: .getNamePool(), nodeFactory);
120: setStylesheetDocument(doc, nodeFactory);
121: } catch (XPathException e) {
122: config.reportFatalError(e);
123: if (errorCount == 0) {
124: errorCount++;
125: }
126: }
127:
128: if (errorCount > 0) {
129: throw new TransformerConfigurationException(
130: "Failed to compile stylesheet. "
131: + errorCount
132: + (errorCount == 1 ? " error " : " errors ")
133: + "detected.");
134: }
135: }
136:
137: /**
138: * Build the tree representation of a stylesheet module
139: *
140: * @param styleSource the source of the module
141: * @param config the Configuration of the transformation factory
142: * @param localNamePool the namepool used during compilation
143: * @param nodeFactory the StyleNodeFactory used for creating
144: * element nodes in the tree
145: * @exception XPathException if XML parsing or tree
146: * construction fails
147: * @return the root Document node of the tree containing the stylesheet
148: * module
149: */
150: public static DocumentImpl loadStylesheetModule(Source styleSource,
151: Configuration config, NamePool localNamePool,
152: StyleNodeFactory nodeFactory) throws XPathException {
153:
154: TreeBuilder styleBuilder = new TreeBuilder();
155: PipelineConfiguration pipe = config.makePipelineConfiguration();
156: styleBuilder.setPipelineConfiguration(pipe);
157: styleBuilder.setSystemId(styleSource.getSystemId());
158: styleBuilder.setNodeFactory(nodeFactory);
159: styleBuilder.setLineNumbering(true);
160:
161: StartTagBuffer startTagBuffer = new StartTagBuffer();
162:
163: UseWhenFilter useWhenFilter = new UseWhenFilter(startTagBuffer);
164: useWhenFilter.setUnderlyingReceiver(styleBuilder);
165:
166: startTagBuffer.setUnderlyingReceiver(useWhenFilter);
167:
168: StylesheetStripper styleStripper = new StylesheetStripper();
169: styleStripper.setStylesheetRules(localNamePool);
170: styleStripper.setUnderlyingReceiver(startTagBuffer);
171:
172: CommentStripper commentStripper = new CommentStripper();
173: commentStripper.setUnderlyingReceiver(styleStripper);
174:
175: // build the stylesheet document
176:
177: DocumentImpl doc;
178:
179: Sender sender = new Sender(pipe);
180: AugmentedSource aug = AugmentedSource
181: .makeAugmentedSource(styleSource);
182: aug.setSchemaValidationMode(Validation.STRIP);
183: if (aug.getXMLReader() == null) {
184: XMLReader styleParser = config.getStyleParser();
185: aug.setXMLReader(styleParser);
186: sender.send(aug, commentStripper);
187: config.reuseStyleParser(styleParser);
188: } else {
189: sender.send(aug, commentStripper);
190: }
191: doc = (DocumentImpl) styleBuilder.getCurrentRoot();
192:
193: return doc;
194:
195: }
196:
197: /**
198: * Load a PreparedStylesheet from a compiled stylesheet stored in a file.
199: * @param config The Configuration. <b>This method changes the NamePool used by this configuration
200: * to be the NamePool that was stored with the compiled stylesheet. The method must therefore not
201: * be used in a multi-threaded environment where the Configuration (and NamePool) are shared between
202: * multiple concurrent transformations.</b>
203: * @param fileName The name of the file containing the compiled stylesheet (which is just the Java serialization
204: * of a PreparedStylesheet object).
205: * @return the PreparedStylesheet, which can be used in JAXP interfaces as the Templates object
206: */
207:
208: public static PreparedStylesheet loadCompiledStylesheet(
209: Configuration config, String fileName) throws IOException,
210: ClassNotFoundException {
211: ObjectInputStream ois = new ObjectInputStream(
212: new FileInputStream(fileName));
213: return loadCompiledStylesheet(config, ois);
214: }
215:
216: /**
217: * Load a PreparedStylesheet from a compiled stylesheet stored in a file.
218: * @param config The Configuration. <b>This method changes the NamePool used by this configuration
219: * to be the NamePool that was stored with the compiled stylesheet. The method must therefore not
220: * be used in a multi-threaded environment where the Configuration (and NamePool) are shared between
221: * multiple concurrent transformations.</b>
222: * @param ois The ObjectInputStream containing the compiled stylesheet (which is just the Java serialization
223: * of a PreparedStylesheet object).
224: * @return the PreparedStylesheet, which can be used in JAXP interfaces as the Templates object
225: */
226:
227: public static PreparedStylesheet loadCompiledStylesheet(
228: Configuration config, ObjectInputStream ois)
229: throws IOException, ClassNotFoundException {
230: PreparedStylesheet sheet = (PreparedStylesheet) ois
231: .readObject();
232: ois.close();
233: NamePool compiledNamePool = sheet.getTargetNamePool();
234: sheet.setConfiguration(config);
235: sheet.getExecutable().setConfiguration(config);
236: config.setNamePool(compiledNamePool);
237: NamePool.setDefaultNamePool(compiledNamePool);
238: return sheet;
239: }
240:
241: /**
242: * Create a PreparedStylesheet from a supplied DocumentInfo
243: * Note: the document must have been built using the StyleNodeFactory
244: *
245: * @param doc the document containing the stylesheet module
246: * @param snFactory the StyleNodeFactory used to build the tree
247: * @exception XPathException if the document supplied
248: * is not a stylesheet
249: */
250:
251: protected void setStylesheetDocument(DocumentImpl doc,
252: StyleNodeFactory snFactory) throws XPathException {
253:
254: DocumentImpl styleDoc = doc;
255: nodeFactory = snFactory;
256:
257: // If top-level node is a literal result element, stitch it into a skeleton stylesheet
258:
259: StyleElement topnode = (StyleElement) styleDoc
260: .getDocumentElement();
261: if (topnode instanceof LiteralResultElement) {
262: styleDoc = ((LiteralResultElement) topnode).makeStylesheet(
263: this , snFactory);
264: }
265:
266: if (!(styleDoc.getDocumentElement() instanceof XSLStylesheet)) {
267: throw new StaticError(
268: "Outermost element of stylesheet is not xsl:stylesheet or xsl:transform or literal result element");
269: }
270:
271: XSLStylesheet top = (XSLStylesheet) styleDoc
272: .getDocumentElement();
273: if (config.isVersionWarning()
274: && top.getVersion().equals(BigDecimal.valueOf(1))) {
275: try {
276: config
277: .getErrorListener()
278: .warning(
279: new TransformerException(
280: "Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor"));
281: } catch (TransformerException e) {
282: throw StaticError.makeStaticError(e);
283: }
284: }
285:
286: // Preprocess the stylesheet, performing validation and preparing template definitions
287:
288: top.setPreparedStylesheet(this );
289: try {
290: top.preprocess();
291: } catch (XPathException e) {
292: Throwable e2 = e.getException();
293: if (e2 instanceof XPathException) {
294: config.reportFatalError((XPathException) e2);
295: }
296: throw e;
297: }
298:
299: // Compile the stylesheet, retaining the resulting executable
300:
301: executable = top.compileStylesheet();
302: }
303:
304: /**
305: * Get the associated executable
306: *
307: * @return the Executable for this stylesheet
308: */
309:
310: public Executable getExecutable() {
311: return executable;
312: }
313:
314: /**
315: * Get the properties for xsl:output. JAXP method. The object returned will
316: * be a clone of the internal values, and thus it can be mutated
317: * without mutating the Templates object, and then handed in to
318: * the process method.
319: * <p>In Saxon, the properties object is a new, empty, Properties object that is
320: * backed by the live properties to supply default values for missing properties.
321: * This means that the property values must be read using the getProperty() method.
322: * Calling the get() method on the underlying Hashtable will return null.</p>
323: * <p>In Saxon 8.x, this method gets the output properties for the unnamed output
324: * format in the stylesheet.</p>
325: *
326: * @see javax.xml.transform.Transformer#setOutputProperties
327: * @return A Properties object reflecting the output properties defined
328: * for the default (unnamed) output format in the stylesheet. It may
329: * be mutated and supplied to the setOutputProperties() method of the
330: * Transformer, without affecting other transformations that use the
331: * same stylesheet.
332: */
333:
334: public Properties getOutputProperties() {
335: Properties details = executable.getDefaultOutputProperties();
336: return new Properties(details);
337: }
338:
339: /**
340: * Report a compile time error. This calls the errorListener to output details
341: * of the error, and increments an error count.
342: *
343: * @param err the exception containing details of the error
344: * @exception TransformerException if the ErrorListener decides that the
345: * error should be reported
346: */
347:
348: public void reportError(TransformerException err)
349: throws TransformerException {
350: errorCount++;
351: config.getErrorListener().fatalError(err);
352: }
353:
354: /**
355: * Get the number of errors reported so far
356: *
357: * @return the number of errors reported
358: */
359:
360: public int getErrorCount() {
361: return errorCount;
362: }
363:
364: /**
365: * Report a compile time warning. This calls the errorListener to output details
366: * of the warning.
367: *
368: * @param err an exception holding details of the warning condition to be
369: * reported
370: */
371:
372: public void reportWarning(TransformerException err) {
373: try {
374: config.getErrorListener().warning(err);
375: } catch (TransformerException err2) {
376: }
377: }
378:
379: }
380:
381: //
382: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
383: // you may not use this file except in compliance with the License. You may obtain a copy of the
384: // License at http://www.mozilla.org/MPL/
385: //
386: // Software distributed under the License is distributed on an "AS IS" basis,
387: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
388: // See the License for the specific language governing rights and limitations under the License.
389: //
390: // The Original Code is: all this file.
391: //
392: // The Initial Developer of the Original Code is Michael H. Kay.
393: //
394: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
395: //
396: // Contributor(s): none.
397: //
|