0001: package net.sf.saxon;
0002:
0003: import net.sf.saxon.event.Builder;
0004: import net.sf.saxon.instruct.TerminationException;
0005: import net.sf.saxon.om.Validation;
0006: import net.sf.saxon.trace.TraceListener;
0007: import net.sf.saxon.trans.DynamicError;
0008: import net.sf.saxon.trans.XPathException;
0009: import net.sf.saxon.value.UntypedAtomicValue;
0010: import org.xml.sax.InputSource;
0011: import org.xml.sax.XMLReader;
0012:
0013: import javax.xml.transform.*;
0014: import javax.xml.transform.sax.SAXSource;
0015: import javax.xml.transform.stream.StreamResult;
0016: import javax.xml.transform.stream.StreamSource;
0017: import java.io.File;
0018: import java.net.URI;
0019: import java.net.URISyntaxException;
0020: import java.util.ArrayList;
0021: import java.util.Date;
0022: import java.util.List;
0023:
0024: /**
0025: * This <B>Transform</B> class is the entry point to the Saxon XSLT Processor. This
0026: * class is provided to control the processor from the command line.<p>
0027: * <p/>
0028: * The XSLT syntax supported conforms to the W3C XSLT 1.0 and XPath 1.0 recommendation.
0029: * Only the transformation language is implemented (not the formatting objects).
0030: * Saxon extensions are documented in the file extensions.html
0031: *
0032: * @author Michael H. Kay
0033: */
0034:
0035: public class Transform {
0036:
0037: protected TransformerFactoryImpl factory = new TransformerFactoryImpl();
0038: protected Configuration config;
0039: protected boolean useURLs = false;
0040: protected boolean showTime = false;
0041: protected int repeat = 1;
0042: String sourceParserName = null;
0043:
0044: /**
0045: * Main program, can be used directly from the command line.
0046: * <p>The format is:</P>
0047: * <p>java net.sf.saxon.Transform [options] <I>source-file</I> <I>style-file</I> ><I>output-file</I></P>
0048: * <p>followed by any number of parameters in the form {keyword=value}... which can be
0049: * referenced from within the stylesheet.</p>
0050: * <p>This program applies the XSL style sheet in style-file to the source XML document in source-file.</p>
0051: *
0052: * @param args List of arguments supplied on operating system command line
0053: * @throws java.lang.Exception Indicates that a compile-time or
0054: * run-time error occurred
0055: */
0056:
0057: public static void main(String args[]) throws java.lang.Exception {
0058: // the real work is delegated to another routine so that it can be used in a subclass
0059: (new Transform()).doMain(args, "java net.sf.saxon.Transform");
0060: }
0061:
0062: /**
0063: * Set the configuration in the TransformerFactory. This is designed to be
0064: * overridden in a subclass
0065: */
0066:
0067: protected void setFactoryConfiguration() {
0068: Configuration config = new Configuration();
0069: factory.setConfiguration(config);
0070: // In basic XSLT, all nodes are untyped by definition
0071: config.setAllNodesUntyped(true);
0072: }
0073:
0074: /**
0075: * Support method for main program. This support method can also be invoked from subclasses
0076: * that support the same command line interface
0077: *
0078: * @param args the command-line arguments
0079: * @param name name of the class, to be used in error messages
0080: */
0081:
0082: protected void doMain(String args[], String name) {
0083:
0084: String sourceFileName = null;
0085: String styleFileName = null;
0086: File outputFile = null;
0087: ArrayList parameterList = new ArrayList(20);
0088: String outputFileName = null;
0089: String initialMode = null;
0090: String initialTemplate = null;
0091: boolean useAssociatedStylesheet = false;
0092: boolean wholeDirectory = false;
0093: boolean precompiled = false;
0094: boolean dtdValidation = false;
0095: String styleParserName = null;
0096:
0097: setFactoryConfiguration();
0098: config = factory.getConfiguration();
0099: boolean schemaAware = config.isSchemaAware(Configuration.XSLT);
0100:
0101: // Check the command-line arguments.
0102:
0103: try {
0104: int i = 0;
0105: while (true) {
0106: if (i >= args.length) {
0107: badUsage(name, "No source file name");
0108: }
0109:
0110: if (args[i].charAt(0) == '-') {
0111:
0112: if (args[i].equals("-a")) {
0113: useAssociatedStylesheet = true;
0114: i++;
0115: } else if (args[i].equals("-c")) {
0116: precompiled = true;
0117: i++;
0118: } else if (args[i].equals("-cr")) {
0119: i++;
0120: if (args.length < i + 2) {
0121: badUsage(name, "No resolver after -cr");
0122: }
0123: String crclass = args[i++];
0124: Object resolver = config.getInstance(crclass,
0125: null);
0126: factory.setAttribute(
0127: FeatureKeys.COLLECTION_URI_RESOLVER,
0128: resolver);
0129: } else if (args[i].equals("-ds")) {
0130: factory.setAttribute(FeatureKeys.TREE_MODEL,
0131: new Integer(Builder.STANDARD_TREE));
0132: i++;
0133: } else if (args[i].equals("-dt")) {
0134: factory.setAttribute(FeatureKeys.TREE_MODEL,
0135: new Integer(Builder.TINY_TREE));
0136: i++;
0137: } else if (args[i].equals("-im")) {
0138: i++;
0139: if (args.length < i + 2) {
0140: badUsage(name, "No initial mode after -im");
0141: }
0142: initialMode = args[i++];
0143: } else if (args[i].equals("-it")) {
0144: i++;
0145: if (args.length < i + 2) {
0146: badUsage(name,
0147: "No initial template after -it");
0148: }
0149: initialTemplate = args[i++];
0150: } else if (args[i].equals("-l")) {
0151: factory.setAttribute(
0152: FeatureKeys.LINE_NUMBERING, Boolean
0153: .valueOf(true));
0154: i++;
0155: } else if (args[i].equals("-novw")) {
0156: factory.setAttribute(
0157: FeatureKeys.VERSION_WARNING, Boolean
0158: .valueOf(false));
0159: i++;
0160: } else if (args[i].equals("-snone")) {
0161: factory.setAttribute(
0162: FeatureKeys.STRIP_WHITESPACE, "none");
0163: i++;
0164: } else if (args[i].equals("-sall")) {
0165: factory.setAttribute(
0166: FeatureKeys.STRIP_WHITESPACE, "all");
0167: i++;
0168: } else if (args[i].equals("-signorable")) {
0169: factory.setAttribute(
0170: FeatureKeys.STRIP_WHITESPACE,
0171: "ignorable");
0172: i++;
0173: } else if (args[i].equals("-u")) {
0174: useURLs = true;
0175: i++;
0176: } else if (args[i].equals("-v")) {
0177: factory.setAttribute(
0178: FeatureKeys.DTD_VALIDATION, Boolean
0179: .valueOf(true));
0180: dtdValidation = true;
0181: i++;
0182: } else if (args[i].equals("-vw")) {
0183: if (schemaAware) {
0184: factory.setAttribute(
0185: FeatureKeys.VALIDATION_WARNINGS,
0186: Boolean.valueOf(true));
0187: } else {
0188: quit(
0189: "The -vw option requires a schema-aware processor",
0190: 2);
0191: }
0192: i++;
0193: } else if (args[i].equals("-val")) {
0194: if (schemaAware) {
0195: factory.setAttribute(
0196: FeatureKeys.SCHEMA_VALIDATION,
0197: new Integer(Validation.STRICT));
0198: } else {
0199: quit(
0200: "The -val option requires a schema-aware processor",
0201: 2);
0202: }
0203: i++;
0204: } else if (args[i].equals("-vlax")) {
0205: if (schemaAware) {
0206: factory.setAttribute(
0207: FeatureKeys.SCHEMA_VALIDATION,
0208: new Integer(Validation.LAX));
0209: } else {
0210: quit(
0211: "The -vlax option requires a schema-aware processor",
0212: 2);
0213: }
0214: i++;
0215: } else if (args[i].equals("-t")) {
0216: System.err.println(config.getProductTitle());
0217: System.err.println("Java version "
0218: + System.getProperty("java.version"));
0219: factory.setAttribute(FeatureKeys.TIMING,
0220: Boolean.valueOf(true));
0221:
0222: //Loader.setTracing(true);
0223: showTime = true;
0224: i++;
0225: } else if (args[i].equals("-1.1")) { // XML 1.1
0226: i++;
0227: factory.setAttribute(FeatureKeys.XML_VERSION,
0228: "1.1");
0229: } else if (args[i].equals("-3")) { // undocumented option: do it thrice
0230: i++;
0231: repeat = 3;
0232: } else if (args[i].equals("-9")) { // undocumented option: do it nine times
0233: i++;
0234: repeat = 9;
0235: } else if (args[i].equals("-o")) {
0236: i++;
0237: if (args.length < i + 2) {
0238: badUsage(name, "No output file name");
0239: }
0240: outputFileName = args[i++];
0241: } else if (args[i].equals("-p")) {
0242: i++;
0243: setPOption(config);
0244: useURLs = true;
0245: } else if (args[i].equals("-x")) {
0246: i++;
0247: if (args.length < i + 2) {
0248: badUsage(name, "No source parser class");
0249: }
0250: sourceParserName = args[i++];
0251: factory.setAttribute(
0252: FeatureKeys.SOURCE_PARSER_CLASS,
0253: sourceParserName);
0254: } else if (args[i].equals("-y")) {
0255: i++;
0256: if (args.length < i + 2) {
0257: badUsage(name, "No style parser class");
0258: }
0259: styleParserName = args[i++];
0260: factory.setAttribute(
0261: FeatureKeys.STYLE_PARSER_CLASS,
0262: styleParserName);
0263: } else if (args[i].equals("-r")) {
0264: i++;
0265: if (args.length < i + 2) {
0266: badUsage(name, "No URIResolver class");
0267: }
0268: String r = args[i++];
0269: factory.setURIResolver(config
0270: .makeURIResolver(r));
0271: } else if (args[i].equals("-T")) {
0272: i++;
0273: TraceListener traceListener = new net.sf.saxon.trace.XSLTTraceListener();
0274: factory.setAttribute(
0275: FeatureKeys.TRACE_LISTENER,
0276: traceListener);
0277: factory.setAttribute(
0278: FeatureKeys.LINE_NUMBERING,
0279: Boolean.TRUE);
0280: } else if (args[i].equals("-TP")) {
0281: i++;
0282: TraceListener traceListener = new net.sf.saxon.trace.TimedTraceListener();
0283: factory.setAttribute(
0284: FeatureKeys.TRACE_LISTENER,
0285: traceListener);
0286: factory.setAttribute(
0287: FeatureKeys.LINE_NUMBERING,
0288: Boolean.TRUE);
0289: } else if (args[i].equals("-TJ")) {
0290: i++;
0291: factory.setAttribute(
0292: FeatureKeys.TRACE_EXTERNAL_FUNCTIONS,
0293: Boolean.TRUE);
0294: } else if (args[i].equals("-TL")) {
0295: i++;
0296: if (args.length < i + 2) {
0297: badUsage(name, "No TraceListener class");
0298: }
0299: TraceListener traceListener = config
0300: .makeTraceListener(args[i++]);
0301: factory.setAttribute(
0302: FeatureKeys.TRACE_LISTENER,
0303: traceListener);
0304: factory.setAttribute(
0305: FeatureKeys.LINE_NUMBERING,
0306: Boolean.TRUE);
0307: } else if (args[i].equals("-w0")) {
0308: i++;
0309: factory
0310: .setAttribute(
0311: FeatureKeys.RECOVERY_POLICY,
0312: new Integer(
0313: Configuration.RECOVER_SILENTLY));
0314: } else if (args[i].equals("-w1")) {
0315: i++;
0316: factory
0317: .setAttribute(
0318: FeatureKeys.RECOVERY_POLICY,
0319: new Integer(
0320: Configuration.RECOVER_WITH_WARNINGS));
0321: } else if (args[i].equals("-w2")) {
0322: i++;
0323: factory.setAttribute(
0324: FeatureKeys.RECOVERY_POLICY,
0325: new Integer(
0326: Configuration.DO_NOT_RECOVER));
0327: } else if (args[i].equals("-m")) {
0328: i++;
0329: if (args.length < i + 2) {
0330: badUsage(name, "No message Emitter class");
0331: }
0332: factory.setAttribute(
0333: FeatureKeys.MESSAGE_EMITTER_CLASS,
0334: args[i++]);
0335: } else if (args[i].equals("-noext")) {
0336: i++;
0337: factory.setAttribute(
0338: FeatureKeys.ALLOW_EXTERNAL_FUNCTIONS,
0339: Boolean.valueOf(false));
0340: } else if (args[i].equals("-?")) {
0341: badUsage(name, "");
0342: } else if (args[i].equals("-")) {
0343: break;
0344: // this means take the source from standard input
0345: } else {
0346: badUsage(name, "Unknown option " + args[i]);
0347: }
0348: } else {
0349: break;
0350: }
0351: }
0352:
0353: if (initialTemplate != null && useAssociatedStylesheet) {
0354: badUsage(name,
0355: "-it and -a options cannot be used together");
0356: }
0357:
0358: if (initialTemplate == null) {
0359: if (args.length < i + 1) {
0360: badUsage(name, "No source file name");
0361: }
0362: sourceFileName = args[i++];
0363: }
0364:
0365: if (!useAssociatedStylesheet) {
0366: if (args.length < i + 1) {
0367: badUsage(name, "No stylesheet file name");
0368: }
0369: styleFileName = args[i++];
0370: }
0371:
0372: for (int p = i; p < args.length; p++) {
0373: String arg = args[p];
0374: int eq = arg.indexOf("=");
0375: if (eq < 1 || eq >= arg.length() - 1) {
0376: badUsage(name,
0377: "Bad param=value pair on command line: "
0378: + arg);
0379: }
0380: parameterList.add(arg);
0381: }
0382:
0383: config.displayLicenseMessage();
0384:
0385: List sources = null;
0386: if (initialTemplate == null) {
0387: boolean useSAXSource = sourceParserName != null
0388: || dtdValidation;
0389: Object loaded = loadDocuments(sourceFileName, useURLs,
0390: config, useSAXSource);
0391: if (loaded instanceof List) {
0392: wholeDirectory = true;
0393: sources = (List) loaded;
0394: } else {
0395: wholeDirectory = false;
0396: sources = new ArrayList(1);
0397: sources.add(loaded);
0398: }
0399: sources = preprocess(sources);
0400: if (wholeDirectory) {
0401: if (outputFileName == null) {
0402: quit(
0403: "To process a directory, -o must be specified",
0404: 2);
0405: } else if (outputFileName.equals(sourceFileName)) {
0406: quit(
0407: "Output directory must be different from input",
0408: 2);
0409: } else {
0410: outputFile = new File(outputFileName);
0411: if (!outputFile.isDirectory()) {
0412: quit(
0413: "Input is a directory, but output is not",
0414: 2);
0415: }
0416: }
0417: }
0418: }
0419:
0420: if (outputFileName != null && !wholeDirectory) {
0421: outputFile = new File(outputFileName);
0422: if (outputFile.isDirectory()) {
0423: quit("Output is a directory, but input is not", 2);
0424: }
0425: }
0426:
0427: if (useAssociatedStylesheet) {
0428: if (wholeDirectory) {
0429: processDirectoryAssoc(sources, outputFile,
0430: parameterList, initialMode);
0431: } else {
0432: processFileAssoc((Source) sources.get(0), null,
0433: outputFile, parameterList, initialMode);
0434: }
0435: } else {
0436:
0437: long startTime = (new Date()).getTime();
0438:
0439: PreparedStylesheet sheet = null;
0440:
0441: if (precompiled) {
0442: try {
0443: sheet = PreparedStylesheet
0444: .loadCompiledStylesheet(config,
0445: styleFileName);
0446: if (showTime) {
0447: long endTime = (new Date()).getTime();
0448: System.err
0449: .println("Stylesheet loading time: "
0450: + (endTime - startTime)
0451: + " milliseconds");
0452: startTime = (new Date()).getTime();
0453: }
0454: } catch (Exception err) {
0455: err.printStackTrace();
0456: }
0457: } else {
0458: Source styleSource;
0459: XMLReader styleParser = null;
0460: if (useURLs || styleFileName.startsWith("http:")
0461: || styleFileName.startsWith("file:")) {
0462: styleSource = config.getURIResolver().resolve(
0463: styleFileName, null);
0464: if (styleSource == null) {
0465: styleSource = config.getSystemURIResolver()
0466: .resolve(styleFileName, null);
0467: }
0468: } else if (styleFileName.equals("-")) {
0469: // take input from stdin
0470: if (styleParserName == null) {
0471: styleSource = new StreamSource(System.in);
0472: } else {
0473: styleParser = config.getStyleParser();
0474: styleSource = new SAXSource(styleParser,
0475: new InputSource(System.in));
0476: }
0477: } else {
0478: File sheetFile = new File(styleFileName);
0479: if (!sheetFile.exists()) {
0480: quit("Stylesheet file " + sheetFile
0481: + " does not exist", 2);
0482: }
0483: if (styleParserName == null) {
0484: styleSource = new StreamSource(sheetFile
0485: .toURI().toString());
0486: } else {
0487: InputSource eis = new InputSource(sheetFile
0488: .toURI().toString());
0489: styleParser = config.getStyleParser();
0490: styleSource = new SAXSource(styleParser,
0491: eis);
0492: }
0493: }
0494:
0495: if (styleSource == null) {
0496: quit(
0497: "URIResolver for stylesheet file must return a Source",
0498: 2);
0499: }
0500:
0501: sheet = (PreparedStylesheet) factory
0502: .newTemplates(styleSource);
0503: if (styleParser != null) {
0504: config.reuseStyleParser(styleParser);
0505: // pointless, because the Configuration won't be used again; but we want to set a good example
0506: }
0507: if (showTime) {
0508: long endTime = (new Date()).getTime();
0509: System.err
0510: .println("Stylesheet compilation time: "
0511: + (endTime - startTime)
0512: + " milliseconds");
0513: }
0514: }
0515:
0516: if (initialTemplate != null) {
0517: execute(initialTemplate, sheet, outputFile,
0518: parameterList, initialMode);
0519: } else if (wholeDirectory) {
0520: processDirectory(sources, sheet, outputFile,
0521: parameterList, initialMode);
0522: } else {
0523: processFile((Source) sources.get(0), sheet,
0524: outputFile, parameterList, initialMode);
0525: }
0526: }
0527: } catch (TerminationException err) {
0528: quit(err.getMessage(), 1);
0529: } catch (TransformerConfigurationException err) {
0530: //err.printStackTrace();
0531: quit(err.getMessage(), 2);
0532: } catch (TransformerException err) {
0533: //err.printStackTrace();
0534: quit("Transformation failed: " + err.getMessage(), 2);
0535: } catch (TransformerFactoryConfigurationError err) {
0536: //err.printStackTrace();
0537: quit("Transformation failed: " + err.getMessage(), 2);
0538: } catch (Exception err2) {
0539: err2.printStackTrace();
0540: quit("Fatal error during transformation: "
0541: + err2.getMessage(), 2);
0542: }
0543:
0544: //System.exit(0);
0545: }
0546:
0547: /**
0548: * Preprocess the list of sources. This method exists so that it can be
0549: * overridden in a subclass
0550: */
0551:
0552: public List preprocess(List sources) throws XPathException {
0553: return sources;
0554: }
0555:
0556: /**
0557: * Get the configuration.
0558: */
0559:
0560: protected Configuration getConfiguration() {
0561: return config;
0562: }
0563:
0564: /**
0565: * Exit with a message
0566: *
0567: * @param message The message to be output
0568: * @param code The result code to be returned to the operating
0569: * system shell
0570: */
0571:
0572: protected static void quit(String message, int code) {
0573: System.err.println(message);
0574: System.exit(code);
0575: }
0576:
0577: /**
0578: * Load a document, or all the documents in a directory, given a filename or URL
0579: *
0580: * @return if sourceFileName represents a single source document, return a Source object representing
0581: * that document. If sourceFileName represents a directory, return a List containing multiple Source
0582: * objects, one for each file in the directory.
0583: */
0584:
0585: public static Object loadDocuments(String sourceFileName,
0586: boolean useURLs, Configuration config, boolean useSAXSource)
0587: throws TransformerException {
0588:
0589: Source sourceInput;
0590: XMLReader parser = null;
0591: if (useURLs || sourceFileName.startsWith("http:")
0592: || sourceFileName.startsWith("file:")) {
0593: sourceInput = config.getURIResolver().resolve(
0594: sourceFileName, null);
0595: if (sourceInput == null) {
0596: sourceInput = config.getSystemURIResolver().resolve(
0597: sourceFileName, null);
0598: }
0599: return sourceInput;
0600: } else if (sourceFileName.equals("-")) {
0601: // take input from stdin
0602: if (useSAXSource) {
0603: parser = config.getSourceParser();
0604: sourceInput = new SAXSource(parser, new InputSource(
0605: System.in));
0606: } else {
0607: sourceInput = new StreamSource(System.in);
0608: }
0609: return sourceInput;
0610: } else {
0611: File sourceFile = new File(sourceFileName);
0612: if (!sourceFile.exists()) {
0613: quit("Source file " + sourceFile + " does not exist", 2);
0614: }
0615: if (sourceFile.isDirectory()) {
0616: parser = config.getSourceParser();
0617: List result = new ArrayList(20);
0618: String[] files = sourceFile.list();
0619: for (int f = 0; f < files.length; f++) {
0620: File file = new File(sourceFile, files[f]);
0621: if (!file.isDirectory()) {
0622: if (useSAXSource) {
0623: InputSource eis = new InputSource(file
0624: .toURI().toString());
0625: sourceInput = new SAXSource(parser, eis);
0626: // it's safe to use the same parser for each document, as they
0627: // will be processed one at a time.
0628: } else {
0629: sourceInput = new StreamSource(file.toURI()
0630: .toString());
0631: }
0632: result.add(sourceInput);
0633: }
0634: }
0635: return result;
0636: } else {
0637: if (useSAXSource) {
0638: InputSource eis = new InputSource(sourceFile
0639: .toURI().toString());
0640: sourceInput = new SAXSource(config
0641: .getSourceParser(), eis);
0642: } else {
0643: sourceInput = new StreamSource(sourceFile.toURI()
0644: .toString());
0645: }
0646: return sourceInput;
0647: }
0648: }
0649: }
0650:
0651: /**
0652: * Process each file in the source directory using its own associated stylesheet
0653: *
0654: * @param sources The sources in the directory to be processed
0655: * @param outputDir The directory in which output files are to be
0656: * created
0657: * @param parameterList List of parameters to be supplied to each
0658: * transformation
0659: * @param initialMode Initial mode for executing each
0660: * transformation
0661: * @throws Exception when any error occurs during a transformation
0662: */
0663:
0664: public void processDirectoryAssoc(List sources, File outputDir,
0665: ArrayList parameterList, String initialMode)
0666: throws Exception {
0667:
0668: int failures = 0;
0669: for (int f = 0; f < sources.size(); f++) {
0670: Source source = (Source) sources.get(f);
0671: String localName = getLocalFileName(source);
0672: try {
0673: processFileAssoc(source, localName, outputDir,
0674: parameterList, initialMode);
0675: } catch (XPathException err) {
0676: failures++;
0677: System.err.println("While processing " + localName
0678: + ": " + err.getMessage() + '\n');
0679: }
0680: }
0681: if (failures > 0) {
0682: throw new DynamicError(failures + " transformation"
0683: + (failures == 1 ? "" : "s") + " failed");
0684: }
0685: }
0686:
0687: /**
0688: * Make an output file in the output directory, with filename extension derived from the
0689: * media-type produced by the stylesheet
0690: *
0691: * @param directory The directory in which the file is to be created
0692: * @param localName The local name of the file within the
0693: * directory, excluding the file type suffix
0694: * @param sheet The Templates object identifying the stylesheet -
0695: * used to determine the output method, and hence the suffix to be
0696: * used for the filename
0697: * @return The newly created file
0698: */
0699:
0700: private File makeOutputFile(File directory, String localName,
0701: Templates sheet) {
0702: String mediaType = sheet.getOutputProperties().getProperty(
0703: OutputKeys.MEDIA_TYPE);
0704: String suffix = ".xml";
0705: if ("text/html".equals(mediaType)) {
0706: suffix = ".html";
0707: } else if ("text/plain".equals(mediaType)) {
0708: suffix = ".txt";
0709: }
0710: String prefix = localName;
0711: if (localName.endsWith(".xml") || localName.endsWith(".XML")) {
0712: prefix = localName.substring(0, localName.length() - 4);
0713: }
0714: return new File(directory, prefix + suffix);
0715: }
0716:
0717: /**
0718: * Process a single source file using its associated stylesheet(s)
0719: *
0720: * @param sourceInput Identifies the source file to be transformed
0721: * @param localName The local name of the file within the
0722: * directory, excluding the file type suffix
0723: * @param outputFile The output file to contain the results of the
0724: * transformation
0725: * @param parameterList List of parameters to be supplied to the
0726: * transformation
0727: * @param initialMode Initial mode for executing the transformation
0728: * @throws XPathException If the transformation fails
0729: */
0730:
0731: public void processFileAssoc(Source sourceInput, String localName,
0732: File outputFile, ArrayList parameterList, String initialMode)
0733: throws TransformerException {
0734: if (showTime) {
0735: System.err.println("Processing "
0736: + sourceInput.getSystemId()
0737: + " using associated stylesheet");
0738: }
0739: long startTime = (new Date()).getTime();
0740:
0741: Source style = factory.getAssociatedStylesheet(sourceInput,
0742: null, null, null);
0743: Templates sheet = factory.newTemplates(style);
0744: if (showTime) {
0745: System.err.println("Prepared associated stylesheet "
0746: + style.getSystemId());
0747: }
0748:
0749: Transformer instance = sheet.newTransformer();
0750: setParams(instance, parameterList);
0751: if (initialMode != null) {
0752: ((Controller) instance).setInitialMode(initialMode);
0753: }
0754:
0755: File outFile = outputFile;
0756:
0757: if (outFile != null && outFile.isDirectory()) {
0758: outFile = makeOutputFile(outFile, localName, sheet);
0759: }
0760:
0761: StreamResult result = (outFile == null ? new StreamResult(
0762: System.out) : new StreamResult(outFile.toURI()
0763: .toString()));
0764:
0765: try {
0766: instance.transform(sourceInput, result);
0767: } catch (TerminationException err) {
0768: throw err;
0769: } catch (XPathException err) {
0770: // The error message will already have been displayed; don't do it twice
0771: throw new DynamicError("Run-time errors were reported");
0772: }
0773:
0774: if (showTime) {
0775: long endTime = (new Date()).getTime();
0776: System.err.println("Execution time: "
0777: + (endTime - startTime) + " milliseconds");
0778: }
0779: }
0780:
0781: /**
0782: * Process each file in the source directory using the same supplied stylesheet
0783: *
0784: * @param sources The sources in the directory to be processed
0785: * @param sheet The Templates object identifying the stylesheet
0786: * @param outputDir The directory in which output files are to be
0787: * created
0788: * @param parameterList List of parameters to be supplied to each
0789: * transformation
0790: * @param initialMode Initial mode for executing each
0791: * transformation
0792: * @throws XPathException when any error occurs during a
0793: * transformation
0794: */
0795:
0796: public void processDirectory(List sources, Templates sheet,
0797: File outputDir, ArrayList parameterList, String initialMode)
0798: throws TransformerException {
0799: int failures = 0;
0800: for (int f = 0; f < sources.size(); f++) {
0801: Source source = (Source) sources.get(f);
0802: String localName = getLocalFileName(source);
0803: try {
0804: File outputFile = makeOutputFile(outputDir, localName,
0805: sheet);
0806: processFile(source, sheet, outputFile, parameterList,
0807: initialMode);
0808: } catch (XPathException err) {
0809: failures++;
0810: System.err.println("While processing " + localName
0811: + ": " + err.getMessage() + '\n');
0812: }
0813: }
0814: if (failures > 0) {
0815: throw new DynamicError(failures + " transformation"
0816: + (failures == 1 ? "" : "s") + " failed");
0817: }
0818: }
0819:
0820: private static String getLocalFileName(Source source) {
0821: try {
0822: String path = new URI(source.getSystemId()).getPath();
0823: while (true) {
0824: int sep = path.indexOf('/');
0825: if (sep < 0) {
0826: return path;
0827: } else {
0828: path = path.substring(sep + 1);
0829: }
0830: }
0831: } catch (URISyntaxException err) {
0832: throw new IllegalArgumentException(err.getMessage());
0833: }
0834: }
0835:
0836: /**
0837: * Process a single file using a supplied stylesheet
0838: *
0839: * @param source The source XML document to be transformed
0840: * @param sheet The Templates object identifying the stylesheet
0841: * @param outputFile The output file to contain the results of the
0842: * transformation
0843: * @param parameterList List of parameters to be supplied to the
0844: * transformation
0845: * @param initialMode Initial mode for executing the transformation
0846: * @throws net.sf.saxon.trans.XPathException
0847: * If the transformation fails
0848: */
0849:
0850: public void processFile(Source source, Templates sheet,
0851: File outputFile, ArrayList parameterList, String initialMode)
0852: throws TransformerException {
0853:
0854: for (int r = 0; r < repeat; r++) { // repeat is for internal testing/timing
0855: if (showTime) {
0856: System.err
0857: .println("Processing " + source.getSystemId());
0858: }
0859: long startTime = (new Date()).getTime();
0860: Transformer instance = sheet.newTransformer();
0861: setParams(instance, parameterList);
0862: if (initialMode != null) {
0863: ((Controller) instance).setInitialMode(initialMode);
0864: }
0865: // if (outputFile==null) {
0866: // ((Controller)instance).setBaseOutputURI(new File(System.getProperty("user.dir")).toURI().toString());
0867: // }
0868: Result result = (outputFile == null ? new StreamResult(
0869: System.out) : new StreamResult(outputFile.toURI()
0870: .toString()));
0871:
0872: try {
0873: instance.transform(source, result);
0874: } catch (TerminationException err) {
0875: throw err;
0876: } catch (XPathException err) {
0877: // The message will already have been displayed; don't do it twice
0878: throw new DynamicError("Run-time errors were reported");
0879: }
0880:
0881: if (showTime) {
0882: long endTime = (new Date()).getTime();
0883: System.err.println("Execution time: "
0884: + (endTime - startTime) + " milliseconds");
0885: System.err.println("Memory used: "
0886: + (Runtime.getRuntime().totalMemory() - Runtime
0887: .getRuntime().freeMemory()));
0888: config.getNamePool().statistics();
0889: if (repeat > 1) {
0890: System.err
0891: .println("-------------------------------");
0892: Runtime.getRuntime().gc();
0893: }
0894: }
0895: }
0896: }
0897:
0898: /**
0899: * Invoke a supplied stylesheet with no source document
0900: *
0901: * @param initialTemplate The entry point to the stylesheet
0902: * @param sheet The Templates object identifying the stylesheet
0903: * @param outputFile The output file to contain the results of the
0904: * transformation
0905: * @param parameterList List of parameters to be supplied to the
0906: * transformation
0907: * @param initialMode Initial mode for executing the transformation
0908: * @throws net.sf.saxon.trans.XPathException
0909: * If the transformation fails
0910: */
0911:
0912: public void execute(String initialTemplate, Templates sheet,
0913: File outputFile, ArrayList parameterList, String initialMode)
0914: throws TransformerException {
0915:
0916: for (int r = 0; r < repeat; r++) { // repeat is for internal testing/timing
0917: if (showTime) {
0918: System.err.println("Calling template "
0919: + initialTemplate);
0920: }
0921: long startTime = (new Date()).getTime();
0922: Transformer instance = sheet.newTransformer();
0923: setParams(instance, parameterList);
0924: if (initialMode != null) {
0925: ((Controller) instance).setInitialMode(initialMode);
0926: }
0927: ((Controller) instance).setInitialTemplate(initialTemplate);
0928: Result result = (outputFile == null ? new StreamResult(
0929: System.out) : new StreamResult(outputFile.toURI()
0930: .toString()));
0931:
0932: try {
0933: instance.transform(null, result);
0934: } catch (TerminationException err) {
0935: throw err;
0936: } catch (XPathException err) {
0937: // The message will already have been displayed; don't do it twice
0938: throw new DynamicError("Run-time errors were reported");
0939: }
0940:
0941: if (showTime) {
0942: long endTime = (new Date()).getTime();
0943: System.err.println("Execution time: "
0944: + (endTime - startTime) + " milliseconds");
0945: }
0946: }
0947: }
0948:
0949: /**
0950: * Supply the requested parameters to the transformer
0951: *
0952: * @param t The transformer to be used for the transformation
0953: * @param parameterList List of parameters to be supplied to the
0954: * transformation
0955: */
0956: private void setParams(Transformer t, ArrayList parameterList)
0957: throws TransformerException {
0958: for (int i = 0; i < parameterList.size(); i++) {
0959: String arg = (String) parameterList.get(i);
0960: int eq = arg.indexOf("=");
0961: String argname = arg.substring(0, eq);
0962: if (argname.startsWith("!")) {
0963: // parameters starting with "!" are taken as output properties
0964: t.setOutputProperty(argname.substring(1), arg
0965: .substring(eq + 1));
0966: } else if (argname.startsWith("+")) {
0967: // parameters starting with "+" are taken as input documents
0968: Object sources = loadDocuments(arg.substring(eq + 1),
0969: useURLs, config, true);
0970: t.setParameter(argname.substring(1), sources);
0971: } else {
0972: t.setParameter(argname, new UntypedAtomicValue(arg
0973: .substring(eq + 1)));
0974: }
0975: }
0976: }
0977:
0978: public void setPOption(Configuration config) {
0979: factory.setAttribute(
0980: FeatureKeys.RECOGNIZE_URI_QUERY_PARAMETERS, Boolean
0981: .valueOf(true));
0982: }
0983:
0984: /**
0985: * Report incorrect usage of the command line, with a list of the options and arguments that are available
0986: *
0987: * @param name The name of the command being executed (allows subclassing)
0988: * @param message The error message
0989: */
0990: protected void badUsage(String name, String message) {
0991: if (!"".equals(message)) {
0992: System.err.println(message);
0993: }
0994: if (!showTime) {
0995: System.err.println(config.getProductTitle());
0996: }
0997: System.err.println("Usage: " + name
0998: + " [options] source-doc style-doc {param=value}...");
0999: System.err.println("Options: ");
1000: System.err
1001: .println(" -a Use xml-stylesheet PI, not style-doc argument");
1002: System.err
1003: .println(" -c Indicates that style-doc is a compiled stylesheet");
1004: System.err
1005: .println(" -cr classname Use specified collection URI resolver class");
1006: System.err
1007: .println(" -ds Use standard tree data structure");
1008: System.err
1009: .println(" -dt Use tinytree data structure (default)");
1010: System.err
1011: .println(" -im modename Start transformation in specified mode");
1012: System.err
1013: .println(" -it template Start transformation by calling named template");
1014: System.err
1015: .println(" -l Retain line numbers in source document tree");
1016: System.err
1017: .println(" -o filename Send output to named file or directory");
1018: System.err
1019: .println(" -m classname Use specified Emitter class for xsl:message output");
1020: System.err
1021: .println(" -novw Suppress warning when running with an XSLT 1.0 stylesheet");
1022: System.err
1023: .println(" -r classname Use specified URIResolver class");
1024: System.err
1025: .println(" -p Recognize Saxon file extensions and query parameters");
1026: System.err
1027: .println(" -sall Strip all whitespace text nodes");
1028: System.err
1029: .println(" -signorable Strip ignorable whitespace text nodes (default)");
1030: System.err
1031: .println(" -snone Strip no whitespace text nodes");
1032: System.err
1033: .println(" -t Display version and timing information");
1034: System.err
1035: .println(" -T Set standard TraceListener");
1036: System.err
1037: .println(" -TJ Trace calls to external Java functions");
1038: System.err
1039: .println(" -TL classname Set a specific TraceListener");
1040: System.err
1041: .println(" -u Names are URLs not filenames");
1042: System.err
1043: .println(" -v Validate source documents using DTD");
1044: if (config.isSchemaAware(Configuration.XSLT)) {
1045: System.err
1046: .println(" -val Validate source documents using schema");
1047: System.err
1048: .println(" -vlax Lax validation of source documents using schema");
1049: System.err
1050: .println(" -vw Treat validation errors on result document as warnings");
1051: }
1052: System.err
1053: .println(" -w0 Recover silently from recoverable errors");
1054: System.err
1055: .println(" -w1 Report recoverable errors and continue (default)");
1056: System.err
1057: .println(" -w2 Treat recoverable errors as fatal");
1058: System.err
1059: .println(" -x classname Use specified SAX parser for source file");
1060: System.err
1061: .println(" -y classname Use specified SAX parser for stylesheet");
1062: System.err.println(" -1.1 Allow XML 1.1 documents");
1063: System.err.println(" -? Display this message ");
1064: System.err
1065: .println(" param=value Set stylesheet string parameter");
1066: System.err
1067: .println(" +param=file Set stylesheet document parameter");
1068: System.err
1069: .println(" !option=value Set serialization option");
1070: if ("".equals(message)) {
1071: System.exit(0);
1072: } else {
1073: System.exit(2);
1074: }
1075: }
1076:
1077: }
1078:
1079: //
1080: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
1081: // you may not use this file except in compliance with the License. You may obtain a copy of the
1082: // License at http://www.mozilla.org/MPL/
1083: //
1084: // Software distributed under the License is distributed on an "AS IS" basis,
1085: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
1086: // See the License for the specific language governing rights and limitations under the License.
1087: //
1088: // The Original Code is: all this file.
1089: //
1090: // The Initial Developer of the Original Code is Michael H. Kay.
1091: //
1092: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
1093: //
1094: // Contributor(s): changes to allow source and/or stylesheet from stdin contributed by
1095: // Gunther Schadow [gunther@aurora.regenstrief.org]
1096: //
|