PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/saxonB/net/sf/saxon/Transform.java

https://bitbucket.org/nrg/pipeline
Java | 1253 lines | 963 code | 85 blank | 205 comment | 365 complexity | 992700a87ec9272b3c03994bdffcf792 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. package net.sf.saxon;
  2. import net.sf.saxon.event.Builder;
  3. import net.sf.saxon.event.Receiver;
  4. import net.sf.saxon.event.SaxonOutputKeys;
  5. import net.sf.saxon.instruct.TerminationException;
  6. import net.sf.saxon.om.Validation;
  7. import net.sf.saxon.trace.ExpressionPresenter;
  8. import net.sf.saxon.trace.TraceListener;
  9. import net.sf.saxon.trans.XPathException;
  10. import net.sf.saxon.value.UntypedAtomicValue;
  11. import org.xml.sax.InputSource;
  12. import org.xml.sax.XMLReader;
  13. import javax.xml.transform.*;
  14. import javax.xml.transform.sax.SAXSource;
  15. import javax.xml.transform.stream.StreamResult;
  16. import javax.xml.transform.stream.StreamSource;
  17. import java.io.File;
  18. import java.io.FileOutputStream;
  19. import java.io.OutputStream;
  20. import java.io.PrintStream;
  21. import java.net.URI;
  22. import java.net.URISyntaxException;
  23. import java.util.ArrayList;
  24. import java.util.Date;
  25. import java.util.List;
  26. import java.util.Properties;
  27. /**
  28. * This <B>Transform</B> class is the entry point to the Saxon XSLT Processor. This
  29. * class is provided to control the processor from the command line.<p>
  30. * <p/>
  31. * The XSLT syntax supported conforms to the W3C XSLT 1.0 and XPath 1.0 recommendation.
  32. * Only the transformation language is implemented (not the formatting objects).
  33. * Saxon extensions are documented in the file extensions.html
  34. *
  35. * @author Michael H. Kay
  36. */
  37. public class Transform {
  38. protected TransformerFactoryImpl factory;
  39. protected Configuration config;
  40. protected boolean useURLs = false;
  41. protected boolean showTime = false;
  42. protected int repeat = 1;
  43. String sourceParserName = null;
  44. /**
  45. * Main program, can be used directly from the command line.
  46. * <p>The format is:</P>
  47. * <p>java net.sf.saxon.Transform [options] <I>source-file</I> <I>style-file</I> &gt;<I>output-file</I></P>
  48. * <p>followed by any number of parameters in the form {keyword=value}... which can be
  49. * referenced from within the stylesheet.</p>
  50. * <p>This program applies the XSL style sheet in style-file to the source XML document in source-file.</p>
  51. *
  52. * @param args List of arguments supplied on operating system command line
  53. * @throws java.lang.Exception Indicates that a compile-time or
  54. * run-time error occurred
  55. */
  56. public static void main(String args[])
  57. throws java.lang.Exception {
  58. // the real work is delegated to another routine so that it can be used in a subclass
  59. (new Transform()).doTransform(args, "java net.sf.saxon.Transform");
  60. }
  61. /**
  62. * Set the configuration in the TransformerFactory. This is designed to be
  63. * overridden in a subclass
  64. * @param schemaAware True if the transformation is to be schema-aware
  65. * @param className Name of the schema-aware Configuration class to be loaded. Designed for use by .NET;
  66. * can normally be null.
  67. */
  68. public void setFactoryConfiguration(boolean schemaAware, String className) throws RuntimeException {
  69. if (schemaAware) {
  70. config = Configuration.makeSchemaAwareConfiguration(null, className);
  71. } else {
  72. config = new Configuration();
  73. // In basic XSLT, all nodes are untyped when calling from the command line
  74. config.setAllNodesUntyped(true);
  75. }
  76. factory = new TransformerFactoryImpl(config);
  77. }
  78. /**
  79. * Support method for main program. This support method can also be invoked from subclasses
  80. * that support the same command line interface
  81. *
  82. * @param args the command-line arguments
  83. * @param command the form of the command as written by the user, to be used in error messages
  84. */
  85. public void doTransform(String args[], String command) {
  86. String sourceFileName = null;
  87. String styleFileName = null;
  88. File outputFile = null;
  89. ArrayList parameterList = new ArrayList(20);
  90. String outputFileName = null;
  91. String initialMode = null;
  92. String initialTemplate = null;
  93. boolean useAssociatedStylesheet = false;
  94. boolean wholeDirectory = false;
  95. boolean precompiled = false;
  96. boolean dtdValidation = false;
  97. String styleParserName = null;
  98. boolean explain = false;
  99. String explainOutputFileName = null;
  100. String additionalSchemas = null;
  101. PrintStream traceDestination = System.err;
  102. boolean closeTraceDestination = false;
  103. boolean schemaAware = false;
  104. for (int i=0; i<args.length; i++) {
  105. if (args[i].equals("-sa") ||
  106. args[i].startsWith("-sa:") ||
  107. args[i].startsWith("-val:") ||
  108. args[i].equals("-val") ||
  109. args[i].equals("-vlax") ||
  110. args[i].startsWith("-xsd:") ||
  111. args[i].startsWith("-xsdversion:") ||
  112. args[i].equals("-p")) {
  113. schemaAware = true;
  114. break;
  115. }
  116. }
  117. try {
  118. setFactoryConfiguration(schemaAware, null);
  119. } catch (Exception err) {
  120. err.printStackTrace();
  121. quit(err.getMessage(), 2);
  122. }
  123. config = factory.getConfiguration();
  124. config.setVersionWarning(true); // unless suppressed by command line options
  125. schemaAware = config.isSchemaAware(Configuration.XSLT);
  126. // Check the command-line arguments.
  127. try {
  128. int i = 0;
  129. while (true) {
  130. if (i >= args.length) {
  131. break;
  132. }
  133. if (args[i].charAt(0) == '-') {
  134. String option;
  135. String value = null;
  136. int colon = args[i].indexOf(':');
  137. if (colon > 0 && colon < args[i].length() - 1) {
  138. option = args[i].substring(1, colon);
  139. value = args[i].substring(colon+1);
  140. } else {
  141. option = args[i].substring(1);
  142. }
  143. if (option.equals("a")) {
  144. useAssociatedStylesheet = true;
  145. i++;
  146. } else if (option.equals("c")) {
  147. precompiled = true;
  148. if (value != null) {
  149. styleFileName = value;
  150. }
  151. i++;
  152. } else if (option.equals("cr")) {
  153. i++;
  154. if (value == null) {
  155. if (args.length < i + 2) {
  156. badUsage(command, "No resolver after -cr");
  157. }
  158. value = args[i++];
  159. }
  160. Object resolver = config.getInstance(value, null);
  161. factory.setAttribute(FeatureKeys.COLLECTION_URI_RESOLVER, resolver);
  162. } else if (option.equals("ds")) {
  163. factory.setAttribute(FeatureKeys.TREE_MODEL,
  164. new Integer(Builder.LINKED_TREE));
  165. i++;
  166. } else if (option.equals("dt")) {
  167. factory.setAttribute(FeatureKeys.TREE_MODEL,
  168. new Integer(Builder.TINY_TREE));
  169. i++;
  170. } else if (option.equals("dtd")) {
  171. if (!("on".equals(value) || "off".equals(value))) {
  172. badUsage(command, "-dtd option must be -dtd:on or -dtd:off");
  173. }
  174. factory.setAttribute(FeatureKeys.DTD_VALIDATION,
  175. Boolean.valueOf("on".equals(value)));
  176. i++;
  177. } else if (option.equals("expand")) {
  178. if (!("on".equals(value) || "off".equals(value))) {
  179. badUsage(command, "-expand option must be 'on' or 'off'");
  180. }
  181. factory.setAttribute(FeatureKeys.EXPAND_ATTRIBUTE_DEFAULTS,
  182. Boolean.valueOf("on".equals(value)));
  183. i++;
  184. } else if (option.equals("explain")) {
  185. explain = true;
  186. explainOutputFileName = value; // may be omitted/null
  187. factory.setAttribute(FeatureKeys.TRACE_OPTIMIZER_DECISIONS, Boolean.TRUE);
  188. i++;
  189. } else if (option.equals("ext")) {
  190. if (!("on".equals(value) || "off".equals(value))) {
  191. badUsage(command, "-ext option must be -ext:on or -ext:off");
  192. }
  193. factory.setAttribute(FeatureKeys.ALLOW_EXTERNAL_FUNCTIONS,
  194. Boolean.valueOf("on".equals(value)));
  195. i++;
  196. } else if (option.equals("im")) {
  197. i++;
  198. if (value == null) {
  199. if (args.length < i + 2) {
  200. badUsage(command, "No initial mode after -im");
  201. }
  202. value = args[i++];
  203. }
  204. initialMode = value;
  205. } else if (option.equals("it")) {
  206. i++;
  207. if (value == null) {
  208. if (args.length < i + 2) {
  209. badUsage(command, "No initial template after -it");
  210. }
  211. value = args[i++];
  212. }
  213. initialTemplate = value;
  214. } else if (option.equals("l")) {
  215. if (!(value==null || "on".equals(value) || "off".equals(value))) {
  216. badUsage(command, "-l option must be -l:on or -l:off");
  217. }
  218. factory.setAttribute(FeatureKeys.LINE_NUMBERING,
  219. Boolean.valueOf(!"off".equals(value)));
  220. i++;
  221. } else if (option.equals("m")) {
  222. i++;
  223. if (value == null) {
  224. if (args.length < i + 2) {
  225. badUsage(command, "No message receiver class after -m");
  226. }
  227. value = args[i++];
  228. }
  229. factory.setAttribute(FeatureKeys.MESSAGE_EMITTER_CLASS, value);
  230. } else if (option.equals("noext")) {
  231. i++;
  232. factory.setAttribute(FeatureKeys.ALLOW_EXTERNAL_FUNCTIONS,
  233. Boolean.valueOf(false));
  234. } else if (option.equals("novw")) {
  235. factory.setAttribute(FeatureKeys.VERSION_WARNING,
  236. Boolean.valueOf(false));
  237. i++;
  238. } else if (option.equals("o")) {
  239. i++;
  240. if (value == null) {
  241. if (args.length < i + 2) {
  242. badUsage(command, "No output file name after -o");
  243. }
  244. value = args[i++];
  245. }
  246. outputFileName = value;
  247. } else if (option.equals("or")) {
  248. i++;
  249. if (value == null) {
  250. if (args.length < i + 2) {
  251. badUsage(command, "No output resolver class after -or");
  252. }
  253. value = args[i++];
  254. }
  255. String orclass = value;
  256. Object resolver = config.getInstance(orclass, null);
  257. factory.setAttribute(FeatureKeys.OUTPUT_URI_RESOLVER, resolver);
  258. } else if (option.equals("outval")) {
  259. if (schemaAware) {
  260. if (!(value==null || "recover".equals(value) || "fatal".equals(value))) {
  261. badUsage(command, "-outval option must be 'recover' or 'fatal'");
  262. }
  263. factory.setAttribute(FeatureKeys.VALIDATION_WARNINGS,
  264. Boolean.valueOf("recover".equals(value)));
  265. } else {
  266. quit("The -outval option requires a schema-aware processor", 2);
  267. }
  268. i++;
  269. } else if (option.equals("p")) {
  270. i++;
  271. if (!(value==null || "on".equals(value) || "off".equals(value))) {
  272. badUsage(command, "-p option must be -p:on or -p:off");
  273. }
  274. if (!"off".equals(value)) {
  275. //setPOption(config);
  276. config.setParameterizedURIResolver();
  277. useURLs = true;
  278. }
  279. } else if (option.equals("r")) {
  280. i++;
  281. if (value == null) {
  282. if (args.length < i + 2) {
  283. badUsage(command, "No URIesolver class after -r");
  284. }
  285. value = args[i++];
  286. }
  287. factory.setURIResolver(config.makeURIResolver(value));
  288. } else if (option.equals("repeat")) {
  289. i++;
  290. if (value == null) {
  291. badUsage(command, "No number after -repeat");
  292. } else {
  293. try {
  294. repeat = Integer.parseInt(value);
  295. } catch (NumberFormatException err) {
  296. badUsage(command, "Bad number after -repeat");
  297. }
  298. }
  299. } else if (option.equals("s")) {
  300. i++;
  301. if (value == null) {
  302. if (args.length < i + 2) {
  303. badUsage(command, "No source file name after -s");
  304. }
  305. value = args[i++];
  306. }
  307. sourceFileName = value;
  308. } else if (option.equals("sa")) {
  309. // already handled
  310. i++;
  311. } else if (option.equals("snone")) {
  312. factory.setAttribute(FeatureKeys.STRIP_WHITESPACE, "none");
  313. i++;
  314. } else if (option.equals("sall")) {
  315. factory.setAttribute(FeatureKeys.STRIP_WHITESPACE, "all");
  316. i++;
  317. } else if (option.equals("signorable")) {
  318. factory.setAttribute(FeatureKeys.STRIP_WHITESPACE, "ignorable");
  319. i++;
  320. } else if (option.equals("strip")) {
  321. if ("none".equals(value) || "all".equals(value) || "ignorable".equals(value)) {
  322. factory.setAttribute(FeatureKeys.STRIP_WHITESPACE, value);
  323. i++;
  324. } else {
  325. badUsage(command, "-strip must be none, all, or ignorable");
  326. }
  327. } else if (option.equals("t")) {
  328. if (!showTime) {
  329. // don't do it twice if the option appears twice
  330. System.err.println(config.getProductTitle());
  331. System.err.println(Configuration.getPlatform().getPlatformVersion());
  332. factory.setAttribute(FeatureKeys.TIMING, Boolean.valueOf(true));
  333. showTime = true;
  334. }
  335. i++;
  336. } else if (option.equals("T")) {
  337. i++;
  338. TraceListener traceListener;
  339. if (value == null) {
  340. traceListener = new net.sf.saxon.trace.XSLTTraceListener();
  341. } else {
  342. traceListener = config.makeTraceListener(value);
  343. }
  344. factory.setAttribute(FeatureKeys.TRACE_LISTENER, traceListener);
  345. factory.setAttribute(FeatureKeys.LINE_NUMBERING, Boolean.TRUE);
  346. } else if (option.equals("TJ")) {
  347. i++;
  348. factory.setAttribute(FeatureKeys.TRACE_EXTERNAL_FUNCTIONS,
  349. Boolean.TRUE);
  350. } else if (option.equals("TL")) {
  351. i++;
  352. if (args.length < i + 2) {
  353. badUsage(command, "No TraceListener class");
  354. }
  355. TraceListener traceListener = config.makeTraceListener(args[i++]);
  356. factory.setAttribute(FeatureKeys.TRACE_LISTENER,
  357. traceListener);
  358. factory.setAttribute(FeatureKeys.LINE_NUMBERING,
  359. Boolean.TRUE);
  360. } else if (option.equals("TP")) {
  361. i++;
  362. TraceListener traceListener = new net.sf.saxon.trace.TimedTraceListener();
  363. factory.setAttribute(FeatureKeys.TRACE_LISTENER,
  364. traceListener);
  365. factory.setAttribute(FeatureKeys.LINE_NUMBERING,
  366. Boolean.TRUE);
  367. } else if (option.equals("traceout")) {
  368. i++;
  369. if (value.equals("#err")) {
  370. // no action, this is the default
  371. } else if (value.equals("#out")) {
  372. traceDestination = System.out;
  373. } else if (value.equals("#null")) {
  374. traceDestination = null;
  375. } else {
  376. traceDestination = new PrintStream(new FileOutputStream(new File(value)));
  377. closeTraceDestination = true;
  378. }
  379. } else if (option.equals("tree")) {
  380. if ("linked".equals(value)) {
  381. factory.setAttribute(FeatureKeys.TREE_MODEL,
  382. new Integer(Builder.LINKED_TREE));
  383. } else if ("tiny".equals(value)) {
  384. factory.setAttribute(FeatureKeys.TREE_MODEL,
  385. new Integer(Builder.TINY_TREE));
  386. } else {
  387. badUsage(command, "-tree option must be 'linked' or 'tiny'");
  388. }
  389. i++;
  390. } else if (option.equals("u")) {
  391. useURLs = true;
  392. i++;
  393. } else if (option.equals("v")) {
  394. factory.setAttribute(FeatureKeys.DTD_VALIDATION,
  395. Boolean.valueOf(true));
  396. dtdValidation = true;
  397. i++;
  398. } else if (option.equals("val")) {
  399. if (!schemaAware) {
  400. badUsage(command, "The -val option requires a schema-aware processor");
  401. } else if (value==null || "strict".equals(value)) {
  402. factory.setAttribute(FeatureKeys.SCHEMA_VALIDATION,
  403. new Integer(Validation.STRICT));
  404. } else if ("lax".equals(value)) {
  405. factory.setAttribute(FeatureKeys.SCHEMA_VALIDATION,
  406. new Integer(Validation.LAX));
  407. } else {
  408. badUsage(command, "-val option must be 'strict' or 'lax'");
  409. }
  410. i++;
  411. } else if (option.equals("vlax")) {
  412. if (schemaAware) {
  413. factory.setAttribute(FeatureKeys.SCHEMA_VALIDATION,
  414. new Integer(Validation.LAX));
  415. } else {
  416. quit("The -vlax option requires a schema-aware processor", 2);
  417. }
  418. i++;
  419. } else if (option.equals("versionmsg")) {
  420. if (!("on".equals(value) || "off".equals(value))) {
  421. badUsage(command, "-versionmsg option must be -versionmsg:on or -versionmsg:off");
  422. }
  423. factory.setAttribute(FeatureKeys.VERSION_WARNING,
  424. Boolean.valueOf("on".equals(value)));
  425. i++;
  426. } else if (option.equals("vw")) {
  427. if (schemaAware) {
  428. factory.setAttribute(FeatureKeys.VALIDATION_WARNINGS,
  429. Boolean.valueOf(true));
  430. } else {
  431. quit("The -vw option requires a schema-aware processor", 2);
  432. }
  433. i++;
  434. } else if (option.equals("warnings")) {
  435. if ("silent".equals(value)) {
  436. factory.setAttribute(FeatureKeys.RECOVERY_POLICY,
  437. new Integer(Configuration.RECOVER_SILENTLY));
  438. } else if ("recover".equals(value)) {
  439. factory.setAttribute(FeatureKeys.RECOVERY_POLICY,
  440. new Integer(Configuration.RECOVER_WITH_WARNINGS));
  441. } else if ("fatal".equals(value)) {
  442. factory.setAttribute(FeatureKeys.RECOVERY_POLICY,
  443. new Integer(Configuration.DO_NOT_RECOVER));
  444. }
  445. i++;
  446. } else if (option.equals("w0")) {
  447. i++;
  448. factory.setAttribute(FeatureKeys.RECOVERY_POLICY,
  449. new Integer(Configuration.RECOVER_SILENTLY));
  450. } else if (option.equals("w1")) {
  451. i++;
  452. factory.setAttribute(FeatureKeys.RECOVERY_POLICY,
  453. new Integer(Configuration.RECOVER_WITH_WARNINGS));
  454. } else if (option.equals("w2")) {
  455. i++;
  456. factory.setAttribute(FeatureKeys.RECOVERY_POLICY,
  457. new Integer(Configuration.DO_NOT_RECOVER));
  458. } else if (option.equals("x")) {
  459. i++;
  460. if (value == null) {
  461. if (args.length < i + 2) {
  462. badUsage(command, "No source parser class after -x");
  463. }
  464. value = args[i++];
  465. }
  466. sourceParserName = value;
  467. factory.setAttribute(FeatureKeys.SOURCE_PARSER_CLASS, sourceParserName);
  468. } else if (option.equals("xi")) {
  469. if (!(value==null || "on".equals(value) || "off".equals(value))) {
  470. badUsage(command, "-xi option must be -xi:on or -xi:off");
  471. }
  472. if (!"off".equals(value)) {
  473. factory.setAttribute(FeatureKeys.XINCLUDE, Boolean.TRUE);
  474. }
  475. i++;
  476. } else if (option.equals("xmlversion")) { // XML 1.1
  477. i++;
  478. if (!("1.0".equals(value) | "1.1".equals(value))) {
  479. badUsage(command, "-xmlversion must be 1.0 or 1.1");
  480. }
  481. factory.setAttribute(FeatureKeys.XML_VERSION, value);
  482. } else if (option.equals("xsd")) {
  483. i++;
  484. additionalSchemas = value;
  485. } else if (option.equals("xsdversion")) { // XSD 1.1
  486. i++;
  487. if (!("1.0".equals(value) | "1.1".equals(value))) {
  488. badUsage(command, "-xsdversion must be 1.0 or 1.1");
  489. }
  490. config.setConfigurationProperty(FeatureKeys.XSD_VERSION, value);
  491. } else if (option.equals("xsiloc")) {
  492. i++;
  493. if ("off".equals(value)) {
  494. config.setConfigurationProperty(FeatureKeys.USE_XSI_SCHEMA_LOCATION, Boolean.FALSE);
  495. } else if ("on".equals(value)) {
  496. config.setConfigurationProperty(FeatureKeys.USE_XSI_SCHEMA_LOCATION, Boolean.TRUE);
  497. } else {
  498. badUsage(value, "format: -xsiloc:(on|off)");
  499. }
  500. } else if (option.equals("xsl")) {
  501. i++;
  502. styleFileName = value;
  503. } else if (option.equals("y")) {
  504. i++;
  505. if (value == null) {
  506. if (args.length < i + 2) {
  507. badUsage(command, "No stylesheet parser class after -y");
  508. }
  509. value = args[i++];
  510. }
  511. styleParserName = value;
  512. factory.setAttribute(FeatureKeys.STYLE_PARSER_CLASS, value);
  513. } else if (option.equals("1.1")) { // XML 1.1
  514. i++;
  515. factory.setAttribute(FeatureKeys.XML_VERSION, "1.1");
  516. } else if (args[i].equals("-?")) {
  517. badUsage(command, "");
  518. } else if (args[i].equals("-")) {
  519. break;
  520. // this means take the source from standard input
  521. } else {
  522. badUsage(command, "Unknown option " + args[i]);
  523. }
  524. } else {
  525. break;
  526. }
  527. }
  528. if (initialTemplate != null && useAssociatedStylesheet) {
  529. badUsage(command, "-it and -a options cannot be used together");
  530. }
  531. if (initialTemplate == null && sourceFileName == null) {
  532. if (args.length < i + 1) {
  533. badUsage(command, "No source file name");
  534. }
  535. sourceFileName = args[i++];
  536. }
  537. if (!useAssociatedStylesheet && styleFileName == null) {
  538. if (args.length < i + 1) {
  539. badUsage(command, "No stylesheet file name");
  540. }
  541. styleFileName = args[i++];
  542. }
  543. for (int p = i; p < args.length; p++) {
  544. String arg = args[p];
  545. int eq = arg.indexOf("=");
  546. if (eq < 1 || eq >= arg.length()) {
  547. badUsage(command, "Bad param=value pair on command line: " + arg);
  548. }
  549. parameterList.add(arg);
  550. }
  551. config.displayLicenseMessage();
  552. if (additionalSchemas != null) {
  553. Query.loadAdditionalSchemas(config, additionalSchemas);
  554. }
  555. List sources = null;
  556. if (sourceFileName != null) {
  557. boolean useSAXSource = sourceParserName != null || dtdValidation;
  558. Object loaded = loadDocuments(sourceFileName, useURLs, config, useSAXSource);
  559. if (loaded instanceof List) {
  560. wholeDirectory = true;
  561. sources = (List)loaded;
  562. } else {
  563. wholeDirectory = false;
  564. sources = new ArrayList(1);
  565. sources.add(loaded);
  566. }
  567. sources = preprocess(sources);
  568. if (wholeDirectory) {
  569. if (outputFileName == null) {
  570. quit("To process a directory, -o must be specified", 2);
  571. } else if (outputFileName.equals(sourceFileName)) {
  572. quit("Output directory must be different from input", 2);
  573. } else {
  574. outputFile = new File(outputFileName);
  575. if (!outputFile.isDirectory()) {
  576. quit("Input is a directory, but output is not", 2);
  577. }
  578. }
  579. }
  580. }
  581. if (outputFileName != null && !wholeDirectory) {
  582. outputFile = new File(outputFileName);
  583. if (outputFile.isDirectory()) {
  584. quit("Output is a directory, but input is not", 2);
  585. }
  586. }
  587. if (useAssociatedStylesheet) {
  588. if (wholeDirectory) {
  589. processDirectoryAssoc(sources, outputFile, parameterList,
  590. initialMode, traceDestination);
  591. } else {
  592. processFileAssoc((Source)sources.get(0), null, outputFile, parameterList,
  593. initialMode, traceDestination);
  594. }
  595. } else {
  596. long startTime = (new Date()).getTime();
  597. PreparedStylesheet sheet = null;
  598. if (precompiled) {
  599. try {
  600. sheet = PreparedStylesheet.loadCompiledStylesheet(config, styleFileName);
  601. if (showTime) {
  602. long endTime = (new Date()).getTime();
  603. System.err.println("Stylesheet loading time: " + (endTime - startTime) + " milliseconds");
  604. }
  605. } catch (Exception err) {
  606. err.printStackTrace();
  607. }
  608. } else {
  609. Source styleSource;
  610. XMLReader styleParser = null;
  611. if (useURLs || styleFileName.startsWith("http:")
  612. || styleFileName.startsWith("file:")) {
  613. styleSource = config.getURIResolver().resolve(styleFileName, null);
  614. if (styleSource == null) {
  615. styleSource = config.getSystemURIResolver().resolve(styleFileName, null);
  616. }
  617. } else if (styleFileName.equals("-")) {
  618. // take input from stdin
  619. if (styleParserName == null) {
  620. styleSource = new StreamSource(System.in);
  621. } else if (Configuration.getPlatform().isJava()) {
  622. styleParser = config.getStyleParser();
  623. styleSource = new SAXSource(styleParser, new InputSource(System.in));
  624. } else {
  625. styleSource = new StreamSource(System.in);
  626. }
  627. } else {
  628. File sheetFile = new File(styleFileName);
  629. if (!sheetFile.exists()) {
  630. quit("Stylesheet file " + sheetFile + " does not exist", 2);
  631. }
  632. if (styleParserName == null) {
  633. styleSource = new StreamSource(sheetFile.toURI().toString());
  634. } else {
  635. InputSource eis = new InputSource(sheetFile.toURI().toString());
  636. styleParser = config.getStyleParser();
  637. styleSource = new SAXSource(styleParser, eis);
  638. }
  639. }
  640. if (styleSource == null) {
  641. quit("URIResolver for stylesheet file must return a Source", 2);
  642. }
  643. sheet = (PreparedStylesheet)factory.newTemplates(styleSource);
  644. if (styleParser != null) {
  645. config.reuseStyleParser(styleParser);
  646. // pointless, because the Configuration won't be used again; but we want to set a good example
  647. }
  648. if (showTime) {
  649. long endTime = now();
  650. System.err.println("Stylesheet compilation time: " + (endTime - startTime) + " milliseconds");
  651. }
  652. if (explain) {
  653. OutputStream explainOutput;
  654. if (explainOutputFileName == null) {
  655. explainOutput = System.err;
  656. } else {
  657. explainOutput = new FileOutputStream(new File(explainOutputFileName));
  658. }
  659. Properties props = new Properties();
  660. props.setProperty(OutputKeys.METHOD, "xml");
  661. props.setProperty(OutputKeys.INDENT, "yes");
  662. props.setProperty(SaxonOutputKeys.INDENT_SPACES, "2");
  663. Receiver diag = config.getSerializerFactory().getReceiver(
  664. new StreamResult(explainOutput),
  665. config.makePipelineConfiguration(),
  666. props);
  667. ExpressionPresenter expressionPresenter = new ExpressionPresenter(config, diag);
  668. sheet.explain(expressionPresenter);
  669. expressionPresenter.close();
  670. }
  671. }
  672. if (wholeDirectory) {
  673. processDirectory(sources, sheet, outputFile,
  674. parameterList, initialTemplate, initialMode, traceDestination);
  675. } else {
  676. Source source = (sources == null ? null : (Source)sources.get(0));
  677. processFile(source, sheet, outputFile,
  678. parameterList, initialTemplate, initialMode, traceDestination);
  679. }
  680. if (closeTraceDestination) {
  681. traceDestination.close();
  682. }
  683. }
  684. } catch (TerminationException err) {
  685. quit(err.getMessage(), 1);
  686. } catch (TransformerConfigurationException err) {
  687. //err.printStackTrace();
  688. quit(err.getMessage(), 2);
  689. } catch (TransformerException err) {
  690. //err.printStackTrace();
  691. quit("Transformation failed: " + err.getMessage(), 2);
  692. } catch (TransformerFactoryConfigurationError err) {
  693. //err.printStackTrace();
  694. quit("Transformation failed: " + err.getMessage(), 2);
  695. } catch (Exception err2) {
  696. err2.printStackTrace();
  697. quit("Fatal error during transformation: " + err2.getClass().getName() + ": " +
  698. (err2.getMessage() == null ? " (no message)" : err2.getMessage()), 2);
  699. }
  700. //System.exit(0);
  701. }
  702. /**
  703. * Preprocess the list of sources. This method exists so that it can be
  704. * overridden in a subclass
  705. * @param sources the list of Source objects
  706. * @return a revised list of Source objects
  707. */
  708. public List preprocess(List sources) throws XPathException {
  709. return sources;
  710. }
  711. /**
  712. * Get the configuration.
  713. * @return the Saxon configuration
  714. */
  715. protected Configuration getConfiguration() {
  716. return config;
  717. }
  718. /**
  719. * Exit with a message
  720. *
  721. * @param message The message to be output
  722. * @param code The result code to be returned to the operating
  723. * system shell
  724. */
  725. protected static void quit(String message, int code) {
  726. System.err.println(message);
  727. System.exit(code);
  728. }
  729. /**
  730. * Load a document, or all the documents in a directory, given a filename or URL
  731. * @param sourceFileName the name of the source file or directory
  732. * @param useURLs true if the filename argument is to be treated as a URI
  733. * @param config the Saxon configuration
  734. * @param useSAXSource true if the method should use a SAXSource rather than a StreamSource
  735. * @return if sourceFileName represents a single source document, return a Source object representing
  736. * that document. If sourceFileName represents a directory, return a List containing multiple Source
  737. * objects, one for each file in the directory.
  738. */
  739. public static Object loadDocuments(String sourceFileName, boolean useURLs,
  740. Configuration config, boolean useSAXSource)
  741. throws TransformerException {
  742. Source sourceInput;
  743. XMLReader parser;
  744. if (useURLs || sourceFileName.startsWith("http:") || sourceFileName.startsWith("file:")) {
  745. sourceInput = config.getURIResolver().resolve(sourceFileName, null);
  746. if (sourceInput == null) {
  747. sourceInput = config.getSystemURIResolver().resolve(sourceFileName, null);
  748. }
  749. return sourceInput;
  750. } else if (sourceFileName.equals("-")) {
  751. // take input from stdin
  752. if (useSAXSource) {
  753. parser = config.getSourceParser();
  754. sourceInput = new SAXSource(parser, new InputSource(System.in));
  755. } else {
  756. sourceInput = new StreamSource(System.in);
  757. }
  758. return sourceInput;
  759. } else {
  760. File sourceFile = new File(sourceFileName);
  761. if (!sourceFile.exists()) {
  762. quit("Source file " + sourceFile + " does not exist", 2);
  763. }
  764. if (sourceFile.isDirectory()) {
  765. parser = config.getSourceParser();
  766. List result = new ArrayList(20);
  767. String[] files = sourceFile.list();
  768. for (int f = 0; f < files.length; f++) {
  769. File file = new File(sourceFile, files[f]);
  770. if (!file.isDirectory()) {
  771. if (useSAXSource) {
  772. InputSource eis = new InputSource(file.toURI().toString());
  773. sourceInput = new SAXSource(parser, eis);
  774. // it's safe to use the same parser for each document, as they
  775. // will be processed one at a time.
  776. } else {
  777. sourceInput = new StreamSource(file.toURI().toString());
  778. }
  779. result.add(sourceInput);
  780. }
  781. }
  782. return result;
  783. } else {
  784. if (useSAXSource) {
  785. InputSource eis = new InputSource(sourceFile.toURI().toString());
  786. sourceInput = new SAXSource(config.getSourceParser(), eis);
  787. } else {
  788. sourceInput = new StreamSource(sourceFile.toURI().toString());
  789. }
  790. return sourceInput;
  791. }
  792. }
  793. }
  794. /**
  795. * Process each file in the source directory using its own associated stylesheet
  796. *
  797. * @param sources The sources in the directory to be processed
  798. * @param outputDir The directory in which output files are to be
  799. * created
  800. * @param parameterList List of parameters to be supplied to each
  801. * transformation
  802. * @param initialMode Initial mode for executing each
  803. * transformation
  804. * @param traceDestination output destination for fn:trace() calls
  805. * @throws Exception when any error occurs during a transformation
  806. */
  807. public void processDirectoryAssoc(List sources, File outputDir,
  808. ArrayList parameterList, String initialMode, PrintStream traceDestination)
  809. throws Exception {
  810. int failures = 0;
  811. for (int f = 0; f < sources.size(); f++) {
  812. Source source = (Source)sources.get(f);
  813. String localName = getLocalFileName(source);
  814. try {
  815. processFileAssoc(source, localName, outputDir, parameterList, initialMode, traceDestination);
  816. } catch (XPathException err) {
  817. failures++;
  818. System.err.println("While processing " + localName +
  819. ": " + err.getMessage() + '\n');
  820. }
  821. }
  822. if (failures > 0) {
  823. throw new XPathException(failures + " transformation" +
  824. (failures == 1 ? "" : "s") + " failed");
  825. }
  826. }
  827. /**
  828. * Make an output file in the output directory, with filename extension derived from the
  829. * media-type produced by the stylesheet
  830. *
  831. * @param directory The directory in which the file is to be created
  832. * @param localName The local name of the file within the
  833. * directory, excluding the file type suffix
  834. * @param sheet The Templates object identifying the stylesheet -
  835. * used to determine the output method, and hence the suffix to be
  836. * used for the filename
  837. * @return The newly created file
  838. */
  839. private File makeOutputFile(File directory, String localName, Templates sheet) {
  840. String mediaType = sheet.getOutputProperties().getProperty(OutputKeys.MEDIA_TYPE);
  841. String suffix = ".xml";
  842. if ("text/html".equals(mediaType)) {
  843. suffix = ".html";
  844. } else if ("text/plain".equals(mediaType)) {
  845. suffix = ".txt";
  846. }
  847. String prefix = localName;
  848. if (localName.endsWith(".xml") || localName.endsWith(".XML")) {
  849. prefix = localName.substring(0, localName.length() - 4);
  850. }
  851. return new File(directory, prefix + suffix);
  852. }
  853. /**
  854. * Process a single source file using its associated stylesheet(s)
  855. *
  856. * @param sourceInput Identifies the source file to be transformed
  857. * @param localName The local name of the file within the
  858. * directory, excluding the file type suffix
  859. * @param outputFile The output file to contain the results of the
  860. * transformation
  861. * @param parameterList List of parameters to be supplied to the
  862. * transformation
  863. * @param initialMode Initial mode for executing the transformation
  864. * @param traceDestination Destination for trace output
  865. * @throws XPathException If the transformation fails
  866. */
  867. public void processFileAssoc(Source sourceInput, String localName, File outputFile,
  868. ArrayList parameterList, String initialMode, PrintStream traceDestination)
  869. throws TransformerException {
  870. if (showTime) {
  871. System.err.println("Processing " + sourceInput.getSystemId() + " using associated stylesheet");
  872. }
  873. long startTime = now();
  874. Source style = factory.getAssociatedStylesheet(sourceInput, null, null, null);
  875. Templates sheet = factory.newTemplates(style);
  876. if (showTime) {
  877. System.err.println("Prepared associated stylesheet " + style.getSystemId());
  878. }
  879. Controller controller =
  880. newController(sheet, parameterList, traceDestination, initialMode, null);
  881. File outFile = outputFile;
  882. if (outFile != null && outFile.isDirectory()) {
  883. outFile = makeOutputFile(outFile, localName, sheet);
  884. }
  885. StreamResult result =
  886. (outFile == null ? new StreamResult(System.out) : new StreamResult(outFile.toURI().toString()));
  887. try {
  888. controller.transform(sourceInput, result);
  889. } catch (TerminationException err) {
  890. throw err;
  891. } catch (XPathException err) {
  892. // The error message will already have been displayed; don't do it twice
  893. throw new XPathException("Run-time errors were reported");
  894. }
  895. if (showTime) {
  896. long endTime = now();
  897. System.err.println("Execution time: " + (endTime - startTime) + " milliseconds");
  898. }
  899. }
  900. /**
  901. * Create a new Controller. This method is protected so it can be overridden in a subclass, allowing additional
  902. * options to be set on the Controller
  903. * @param sheet The Templates object representing the compiled stylesheet
  904. * @param parameterList A list of "keyword=value" pairs representing parameter values, in their original
  905. * format from the command line, including any initial "+" or "!" qualifier
  906. * @param traceDestination destination for trace output
  907. * @param initialMode the initial mode for the transformation, as a Clark name. Can be null
  908. * @param initialTemplate the name of the initial template for the transformation, as a Clark name. Can be null
  909. * @return the newly constructed Controller to be used for the transformation
  910. * @throws TransformerException if any error occurs
  911. */
  912. protected Controller newController(
  913. Templates sheet, ArrayList parameterList, PrintStream traceDestination,
  914. String initialMode, String initialTemplate) throws TransformerException {
  915. Controller controller = (Controller)sheet.newTransformer();
  916. setParams(controller, parameterList);
  917. controller.setTraceFunctionDestination(traceDestination);
  918. if (initialMode != null) {
  919. controller.setInitialMode(initialMode);
  920. }
  921. if (initialTemplate != null) {
  922. controller.setInitialTemplate(initialTemplate);
  923. }
  924. return controller;
  925. }
  926. /**
  927. * Get current time in milliseconds
  928. * @return the current time in milliseconds since 1970
  929. */
  930. public static long now() {
  931. return System.currentTimeMillis();
  932. }
  933. /**
  934. * Process each file in the source directory using the same supplied stylesheet
  935. *
  936. * @param sources The sources in the directory to be processed
  937. * @param sheet The Templates object identifying the stylesheet
  938. * @param outputDir The directory in which output files are to be
  939. * created
  940. * @param parameterList List of parameters to be supplied to each
  941. * transformation
  942. * @param initialTemplate Initial template for executing each
  943. * transformation
  944. * @param initialMode Initial mode for executing each
  945. * transformation
  946. * @param traceDestination Destination for output from fn:trace() calls
  947. * @throws XPathException when any error occurs during a
  948. * transformation
  949. */
  950. public void processDirectory(List sources, Templates sheet, File outputDir, ArrayList parameterList,
  951. String initialTemplate, String initialMode, PrintStream traceDestination)
  952. throws TransformerException {
  953. int failures = 0;
  954. for (int f = 0; f < sources.size(); f++) {
  955. Source source = (Source)sources.get(f);
  956. String localName = getLocalFileName(source);
  957. try {
  958. File outputFile = makeOutputFile(outputDir, localName, sheet);
  959. processFile(source, sheet, outputFile, parameterList, initialTemplate, initialMode, traceDestination);
  960. } catch (XPathException err) {
  961. failures++;
  962. System.err.println("While processing " + localName + ": " + err.getMessage() + '\n');
  963. }
  964. }
  965. if (failures > 0) {
  966. throw new XPathException(failures + " transformation" +
  967. (failures == 1 ? "" : "s") + " failed");
  968. }
  969. }
  970. private static String getLocalFileName(Source source) {
  971. try {
  972. String path = new URI(source.getSystemId()

Large files files are truncated, but you can click here to view the full file