PageRenderTime 18ms CodeModel.GetById 148ms app.highlight 139ms RepoModel.GetById 21ms app.codeStats 2ms

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

https://bitbucket.org/dmwelch/phdxnat_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

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

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