001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: Process.java 475586 2006-11-16 05:19:36Z minchau $
020     */
021    package org.apache.xalan.xslt;
022    
023    import java.io.FileOutputStream;
024    import java.io.FileWriter;
025    import java.io.PrintWriter;
026    import java.io.StringReader;
027    import java.util.Properties;
028    import java.util.ResourceBundle;
029    import java.util.Vector;
030    
031    import javax.xml.XMLConstants;
032    import javax.xml.parsers.DocumentBuilder;
033    import javax.xml.parsers.DocumentBuilderFactory;
034    import javax.xml.parsers.ParserConfigurationException;
035    import javax.xml.transform.OutputKeys;
036    import javax.xml.transform.Source;
037    import javax.xml.transform.Templates;
038    import javax.xml.transform.Transformer;
039    import javax.xml.transform.TransformerConfigurationException;
040    import javax.xml.transform.TransformerException;
041    import javax.xml.transform.TransformerFactory;
042    import javax.xml.transform.TransformerFactoryConfigurationError;
043    import javax.xml.transform.URIResolver;
044    import javax.xml.transform.dom.DOMResult;
045    import javax.xml.transform.dom.DOMSource;
046    import javax.xml.transform.sax.SAXResult;
047    import javax.xml.transform.sax.SAXSource;
048    import javax.xml.transform.sax.SAXTransformerFactory;
049    import javax.xml.transform.sax.TransformerHandler;
050    import javax.xml.transform.stream.StreamResult;
051    import javax.xml.transform.stream.StreamSource;
052    
053    import org.apache.xalan.Version;
054    import org.apache.xalan.res.XSLMessages;
055    import org.apache.xalan.res.XSLTErrorResources;
056    import org.apache.xalan.trace.PrintTraceListener;
057    import org.apache.xalan.trace.TraceManager;
058    import org.apache.xalan.transformer.XalanProperties;
059    import org.apache.xml.utils.DefaultErrorHandler;
060    
061    import org.w3c.dom.Document;
062    import org.w3c.dom.Node;
063    
064    import org.xml.sax.ContentHandler;
065    import org.xml.sax.EntityResolver;
066    import org.xml.sax.InputSource;
067    import org.xml.sax.XMLReader;
068    import org.xml.sax.helpers.XMLReaderFactory;
069    
070    /**
071     * The main() method handles the Xalan command-line interface.
072     * @xsl.usage general
073     */
074    public class Process
075    {
076      /**
077       * Prints argument options.
078       *
079       * @param resbundle Resource bundle
080       */
081      protected static void printArgOptions(ResourceBundle resbundle)
082      {
083        System.out.println(resbundle.getString("xslProc_option"));  //"xslproc options: ");
084        System.out.println("\n\t\t\t" + resbundle.getString("xslProc_common_options") + "\n");
085        System.out.println(resbundle.getString("optionXSLTC"));  //"    [-XSLTC (use XSLTC for transformation)]
086        System.out.println(resbundle.getString("optionIN"));  //"    [-IN inputXMLURL]");
087        System.out.println(resbundle.getString("optionXSL"));  //"   [-XSL XSLTransformationURL]");
088        System.out.println(resbundle.getString("optionOUT"));  //"   [-OUT outputFileName]");
089    
090        // System.out.println(resbundle.getString("optionE")); //"   [-E (Do not expand entity refs)]");
091        System.out.println(resbundle.getString("optionV"));  //"   [-V (Version info)]");
092    
093        // System.out.println(resbundle.getString("optionVALIDATE")); //"   [-VALIDATE (Set whether validation occurs.  Validation is off by default.)]");
094        System.out.println(resbundle.getString("optionEDUMP"));  //"   [-EDUMP {optional filename} (Do stackdump on error.)]");
095        System.out.println(resbundle.getString("optionXML"));  //"   [-XML (Use XML formatter and add XML header.)]");
096        System.out.println(resbundle.getString("optionTEXT"));  //"   [-TEXT (Use simple Text formatter.)]");
097        System.out.println(resbundle.getString("optionHTML"));  //"   [-HTML (Use HTML formatter.)]");
098        System.out.println(resbundle.getString("optionPARAM"));  //"   [-PARAM name expression (Set a stylesheet parameter)]");
099        
100        System.out.println(resbundle.getString("optionMEDIA"));
101        System.out.println(resbundle.getString("optionFLAVOR"));
102        System.out.println(resbundle.getString("optionDIAG"));
103        System.out.println(resbundle.getString("optionURIRESOLVER"));  //"   [-URIRESOLVER full class name (URIResolver to be used to resolve URIs)]");    
104        System.out.println(resbundle.getString("optionENTITYRESOLVER"));  //"   [-ENTITYRESOLVER full class name (EntityResolver to be used to resolve entities)]");
105        waitForReturnKey(resbundle);
106        System.out.println(resbundle.getString("optionCONTENTHANDLER"));  //"   [-CONTENTHANDLER full class name (ContentHandler to be used to serialize output)]");
107        System.out.println(resbundle.getString("optionSECUREPROCESSING")); //"   [-SECURE (set the secure processing feature to true)]");
108        
109        System.out.println("\n\t\t\t" + resbundle.getString("xslProc_xalan_options") + "\n");
110        
111        System.out.println(resbundle.getString("optionQC"));  //"   [-QC (Quiet Pattern Conflicts Warnings)]");
112    
113        // System.out.println(resbundle.getString("optionQ"));  //"   [-Q  (Quiet Mode)]"); // sc 28-Feb-01 commented out
114        System.out.println(resbundle.getString("optionTT"));  //"   [-TT (Trace the templates as they are being called.)]");
115        System.out.println(resbundle.getString("optionTG"));  //"   [-TG (Trace each generation event.)]");
116        System.out.println(resbundle.getString("optionTS"));  //"   [-TS (Trace each selection event.)]");
117        System.out.println(resbundle.getString("optionTTC"));  //"   [-TTC (Trace the template children as they are being processed.)]");
118        System.out.println(resbundle.getString("optionTCLASS"));  //"   [-TCLASS (TraceListener class for trace extensions.)]");
119        System.out.println(resbundle.getString("optionLINENUMBERS")); //"   [-L use line numbers]"
120        System.out.println(resbundle.getString("optionINCREMENTAL"));
121        System.out.println(resbundle.getString("optionNOOPTIMIMIZE"));
122        System.out.println(resbundle.getString("optionRL"));
123            
124        System.out.println("\n\t\t\t" + resbundle.getString("xslProc_xsltc_options") + "\n");
125        System.out.println(resbundle.getString("optionXO"));
126        waitForReturnKey(resbundle);    
127        System.out.println(resbundle.getString("optionXD"));
128        System.out.println(resbundle.getString("optionXJ"));
129        System.out.println(resbundle.getString("optionXP"));
130        System.out.println(resbundle.getString("optionXN"));
131        System.out.println(resbundle.getString("optionXX"));
132        System.out.println(resbundle.getString("optionXT"));
133      }
134      
135      /**
136       * Command line interface to transform an XML document according to
137       * the instructions found in an XSL stylesheet.  
138       * <p>The Process class provides basic functionality for 
139       * performing transformations from the command line.  To see a 
140       * list of arguments supported, call with zero arguments.</p>
141       * <p>To set stylesheet parameters from the command line, use 
142       * <code>-PARAM name expression</code>. If you want to set the 
143       * parameter to a string value, simply pass the string value 
144       * as-is, and it will be interpreted as a string.  (Note: if 
145       * the value has spaces in it, you may need to quote it depending 
146       * on your shell environment).</p>
147       *
148       * @param argv Input parameters from command line
149       */
150      public static void main(String argv[])
151      {
152        
153        // Runtime.getRuntime().traceMethodCalls(false); // turns Java tracing off
154        boolean doStackDumpOnError = false;
155        boolean setQuietMode = false;
156        boolean doDiag = false;
157        String msg = null;
158        boolean isSecureProcessing = false;
159    
160        // Runtime.getRuntime().traceMethodCalls(false);
161        // Runtime.getRuntime().traceInstructions(false);
162    
163        /**
164         * The default diagnostic writer...
165         */
166        java.io.PrintWriter diagnosticsWriter = new PrintWriter(System.err, true);
167        java.io.PrintWriter dumpWriter = diagnosticsWriter;
168        ResourceBundle resbundle =
169          (XSLMessages.loadResourceBundle(
170            org.apache.xml.utils.res.XResourceBundle.ERROR_RESOURCES));
171        String flavor = "s2s";
172    
173        if (argv.length < 1)
174        {
175          printArgOptions(resbundle);
176        }
177        else
178        {
179          boolean useXSLTC = false;
180          for (int i = 0; i < argv.length; i++)
181          {
182            if ("-XSLTC".equalsIgnoreCase(argv[i]))
183            {
184              useXSLTC = true;
185            }
186          }
187            
188          TransformerFactory tfactory;
189          if (useXSLTC)
190          {
191             String key = "javax.xml.transform.TransformerFactory";
192             String value = "org.apache.xalan.xsltc.trax.TransformerFactoryImpl";
193             Properties props = System.getProperties();
194             props.put(key, value);
195             System.setProperties(props);      
196          }
197          
198          try
199          {
200            tfactory = TransformerFactory.newInstance();
201            tfactory.setErrorListener(new DefaultErrorHandler(false));
202          }
203          catch (TransformerFactoryConfigurationError pfe)
204          {
205            pfe.printStackTrace(dumpWriter);
206    //      "XSL Process was not successful.");
207            msg = XSLMessages.createMessage(
208                XSLTErrorResources.ER_NOT_SUCCESSFUL, null);
209            diagnosticsWriter.println(msg);  
210    
211            tfactory = null;  // shut up compiler
212    
213            doExit(msg);
214          }
215    
216          boolean formatOutput = false;
217          boolean useSourceLocation = false;
218          String inFileName = null;
219          String outFileName = null;
220          String dumpFileName = null;
221          String xslFileName = null;
222          String treedumpFileName = null;
223          PrintTraceListener tracer = null;
224          String outputType = null;
225          String media = null;
226          Vector params = new Vector();
227          boolean quietConflictWarnings = false;
228          URIResolver uriResolver = null;
229          EntityResolver entityResolver = null;
230          ContentHandler contentHandler = null;
231          int recursionLimit=-1;
232    
233          for (int i = 0; i < argv.length; i++)
234          {
235            if ("-XSLTC".equalsIgnoreCase(argv[i]))
236            {
237              // The -XSLTC option has been processed.
238            }
239            else if ("-TT".equalsIgnoreCase(argv[i]))
240            {
241              if (!useXSLTC)
242              {
243                if (null == tracer)
244                  tracer = new PrintTraceListener(diagnosticsWriter);
245    
246                tracer.m_traceTemplates = true;
247              }
248              else
249                printInvalidXSLTCOption("-TT");
250    
251              // tfactory.setTraceTemplates(true);
252            }
253            else if ("-TG".equalsIgnoreCase(argv[i]))
254            {
255              if (!useXSLTC)
256              {
257                if (null == tracer)
258                  tracer = new PrintTraceListener(diagnosticsWriter);
259    
260                tracer.m_traceGeneration = true;
261              }
262              else
263                printInvalidXSLTCOption("-TG");
264    
265              // tfactory.setTraceSelect(true);
266            }
267            else if ("-TS".equalsIgnoreCase(argv[i]))
268            {
269              if (!useXSLTC)
270              {
271                if (null == tracer)
272                  tracer = new PrintTraceListener(diagnosticsWriter);
273    
274                tracer.m_traceSelection = true;
275              }
276              else
277                printInvalidXSLTCOption("-TS");
278    
279              // tfactory.setTraceTemplates(true);
280            }
281            else if ("-TTC".equalsIgnoreCase(argv[i]))
282            {
283              if (!useXSLTC)
284              {
285                if (null == tracer)
286                  tracer = new PrintTraceListener(diagnosticsWriter);
287    
288                tracer.m_traceElements = true;
289              }
290              else
291                printInvalidXSLTCOption("-TTC");
292    
293              // tfactory.setTraceTemplateChildren(true);
294            }
295            else if ("-INDENT".equalsIgnoreCase(argv[i]))
296            {
297              int indentAmount;
298    
299              if (((i + 1) < argv.length) && (argv[i + 1].charAt(0) != '-'))
300              {
301                indentAmount = Integer.parseInt(argv[++i]);
302              }
303              else
304              {
305                indentAmount = 0;
306              }
307    
308              // TBD:
309              // xmlProcessorLiaison.setIndent(indentAmount);
310            }
311            else if ("-IN".equalsIgnoreCase(argv[i]))
312            {
313              if (i + 1 < argv.length && argv[i + 1].charAt(0) != '-')
314                inFileName = argv[++i];
315              else
316                System.err.println(
317                  XSLMessages.createMessage(
318                    XSLTErrorResources.ER_MISSING_ARG_FOR_OPTION,
319                    new Object[]{ "-IN" }));  //"Missing argument for);
320            }
321            else if ("-MEDIA".equalsIgnoreCase(argv[i]))
322            {
323              if (i + 1 < argv.length)
324                media = argv[++i];
325              else
326                System.err.println(
327                  XSLMessages.createMessage(
328                    XSLTErrorResources.ER_MISSING_ARG_FOR_OPTION,
329                    new Object[]{ "-MEDIA" }));  //"Missing argument for);
330            }
331            else if ("-OUT".equalsIgnoreCase(argv[i]))
332            {
333              if (i + 1 < argv.length && argv[i + 1].charAt(0) != '-')
334                outFileName = argv[++i];
335              else
336                System.err.println(
337                  XSLMessages.createMessage(
338                    XSLTErrorResources.ER_MISSING_ARG_FOR_OPTION,
339                    new Object[]{ "-OUT" }));  //"Missing argument for);
340            }
341            else if ("-XSL".equalsIgnoreCase(argv[i]))
342            {
343              if (i + 1 < argv.length && argv[i + 1].charAt(0) != '-')
344                xslFileName = argv[++i];
345              else
346                System.err.println(
347                  XSLMessages.createMessage(
348                    XSLTErrorResources.ER_MISSING_ARG_FOR_OPTION,
349                    new Object[]{ "-XSL" }));  //"Missing argument for);
350            }
351            else if ("-FLAVOR".equalsIgnoreCase(argv[i]))
352            {
353              if (i + 1 < argv.length)
354              {
355                flavor = argv[++i];
356              }
357              else
358                System.err.println(
359                  XSLMessages.createMessage(
360                    XSLTErrorResources.ER_MISSING_ARG_FOR_OPTION,
361                    new Object[]{ "-FLAVOR" }));  //"Missing argument for);
362            }
363            else if ("-PARAM".equalsIgnoreCase(argv[i]))
364            {
365              if (i + 2 < argv.length)
366              {
367                String name = argv[++i];
368    
369                params.addElement(name);
370    
371                String expression = argv[++i];
372    
373                params.addElement(expression);
374              }
375              else
376                System.err.println(
377                  XSLMessages.createMessage(
378                    XSLTErrorResources.ER_MISSING_ARG_FOR_OPTION,
379                    new Object[]{ "-PARAM" }));  //"Missing argument for);
380            }
381            else if ("-E".equalsIgnoreCase(argv[i]))
382            {
383    
384              // TBD:
385              // xmlProcessorLiaison.setShouldExpandEntityRefs(false);
386            }
387            else if ("-V".equalsIgnoreCase(argv[i]))
388            {
389              diagnosticsWriter.println(resbundle.getString("version")  //">>>>>>> Xalan Version "
390                                        + Version.getVersion() + ", " +
391    
392              /* xmlProcessorLiaison.getParserDescription()+ */
393              resbundle.getString("version2"));  // "<<<<<<<");
394            }
395            else if ("-QC".equalsIgnoreCase(argv[i]))
396            {
397              if (!useXSLTC)
398                quietConflictWarnings = true;
399              else
400                printInvalidXSLTCOption("-QC");
401            }
402            else if ("-Q".equalsIgnoreCase(argv[i]))
403            {
404              setQuietMode = true;
405            }
406            else if ("-DIAG".equalsIgnoreCase(argv[i]))
407            {
408              doDiag = true;
409            }
410            else if ("-XML".equalsIgnoreCase(argv[i]))
411            {
412              outputType = "xml";
413            }
414            else if ("-TEXT".equalsIgnoreCase(argv[i]))
415            {
416              outputType = "text";
417            }
418            else if ("-HTML".equalsIgnoreCase(argv[i]))
419            {
420              outputType = "html";
421            }
422            else if ("-EDUMP".equalsIgnoreCase(argv[i]))
423            {
424              doStackDumpOnError = true;
425    
426              if (((i + 1) < argv.length) && (argv[i + 1].charAt(0) != '-'))
427              {
428                dumpFileName = argv[++i];
429              }
430            }
431            else if ("-URIRESOLVER".equalsIgnoreCase(argv[i]))
432            {
433              if (i + 1 < argv.length)
434              {
435                try
436                {
437                  uriResolver = (URIResolver) ObjectFactory.newInstance(
438                    argv[++i], ObjectFactory.findClassLoader(), true);
439    
440                  tfactory.setURIResolver(uriResolver);
441                }
442                catch (ObjectFactory.ConfigurationError cnfe)
443                {
444                    msg = XSLMessages.createMessage(
445                        XSLTErrorResources.ER_CLASS_NOT_FOUND_FOR_OPTION,
446                        new Object[]{ "-URIResolver" });
447                  System.err.println(msg);
448                  doExit(msg);
449                }
450              }
451              else
452              {
453                msg = XSLMessages.createMessage(
454                        XSLTErrorResources.ER_MISSING_ARG_FOR_OPTION,
455                        new Object[]{ "-URIResolver" });  //"Missing argument for);
456                System.err.println(msg);
457                doExit(msg);
458              }
459            }
460            else if ("-ENTITYRESOLVER".equalsIgnoreCase(argv[i]))
461            {
462              if (i + 1 < argv.length)
463              {
464                try
465                {
466                  entityResolver = (EntityResolver) ObjectFactory.newInstance(
467                    argv[++i], ObjectFactory.findClassLoader(), true);
468                }
469                catch (ObjectFactory.ConfigurationError cnfe)
470                {
471                    msg = XSLMessages.createMessage(
472                        XSLTErrorResources.ER_CLASS_NOT_FOUND_FOR_OPTION,
473                        new Object[]{ "-EntityResolver" });
474                  System.err.println(msg);
475                  doExit(msg);
476                }
477              }
478              else
479              {
480    //            "Missing argument for);
481                  msg = XSLMessages.createMessage(
482                        XSLTErrorResources.ER_MISSING_ARG_FOR_OPTION,
483                        new Object[]{ "-EntityResolver" });
484                System.err.println(msg);  
485                doExit(msg);
486              }
487            }
488            else if ("-CONTENTHANDLER".equalsIgnoreCase(argv[i]))
489            {
490              if (i + 1 < argv.length)
491              {
492                try
493                {
494                  contentHandler = (ContentHandler) ObjectFactory.newInstance(
495                    argv[++i], ObjectFactory.findClassLoader(), true);
496                }
497                catch (ObjectFactory.ConfigurationError cnfe)
498                {
499                    msg = XSLMessages.createMessage(
500                        XSLTErrorResources.ER_CLASS_NOT_FOUND_FOR_OPTION,
501                        new Object[]{ "-ContentHandler" });
502                  System.err.println(msg);
503                  doExit(msg);
504                }
505              }
506              else
507              {
508    //            "Missing argument for);
509                  msg = XSLMessages.createMessage(
510                        XSLTErrorResources.ER_MISSING_ARG_FOR_OPTION,
511                        new Object[]{ "-ContentHandler" });
512                System.err.println(msg);  
513                doExit(msg);
514              }
515            }
516            else if ("-L".equalsIgnoreCase(argv[i]))
517            {
518              if (!useXSLTC)
519                tfactory.setAttribute(XalanProperties.SOURCE_LOCATION, Boolean.TRUE); 
520              else
521                printInvalidXSLTCOption("-L");
522            }
523            else if ("-INCREMENTAL".equalsIgnoreCase(argv[i]))
524            {
525              if (!useXSLTC)
526                tfactory.setAttribute
527                  ("http://xml.apache.org/xalan/features/incremental", 
528                   java.lang.Boolean.TRUE);
529              else
530                printInvalidXSLTCOption("-INCREMENTAL");
531            }
532            else if ("-NOOPTIMIZE".equalsIgnoreCase(argv[i]))
533            {
534              // Default is true.
535              //
536              // %REVIEW% We should have a generalized syntax for negative
537              // switches...  and probably should accept the inverse even
538              // if it is the default.
539              if (!useXSLTC)
540                tfactory.setAttribute
541                  ("http://xml.apache.org/xalan/features/optimize", 
542                   java.lang.Boolean.FALSE);
543              else
544                printInvalidXSLTCOption("-NOOPTIMIZE");
545            }
546            else if ("-RL".equalsIgnoreCase(argv[i]))
547            {
548              if (!useXSLTC)
549              {
550                if (i + 1 < argv.length)
551                  recursionLimit = Integer.parseInt(argv[++i]);
552                else
553                  System.err.println(
554                    XSLMessages.createMessage(
555                      XSLTErrorResources.ER_MISSING_ARG_FOR_OPTION,
556                      new Object[]{ "-rl" }));  //"Missing argument for);
557              }
558              else
559              {
560                if (i + 1 < argv.length && argv[i + 1].charAt(0) != '-')
561                 i++;
562                 
563                printInvalidXSLTCOption("-RL");
564              }
565            }
566            // Generate the translet class and optionally specify the name
567            // of the translet class.
568            else if ("-XO".equalsIgnoreCase(argv[i]))
569            {
570              if (useXSLTC)
571              {
572                if (i + 1 < argv.length && argv[i+1].charAt(0) != '-')
573                {
574                  tfactory.setAttribute("generate-translet", "true");
575                  tfactory.setAttribute("translet-name", argv[++i]);
576                }
577                else
578                  tfactory.setAttribute("generate-translet", "true");
579              }
580              else
581              {
582                if (i + 1 < argv.length && argv[i + 1].charAt(0) != '-')
583                 i++;
584                printInvalidXalanOption("-XO");
585              }
586            }
587            // Specify the destination directory for the translet classes.
588            else if ("-XD".equalsIgnoreCase(argv[i]))
589            {
590              if (useXSLTC)
591              {
592                if (i + 1 < argv.length && argv[i+1].charAt(0) != '-')
593                  tfactory.setAttribute("destination-directory", argv[++i]);
594                else
595                  System.err.println(
596                    XSLMessages.createMessage(
597                      XSLTErrorResources.ER_MISSING_ARG_FOR_OPTION,
598                      new Object[]{ "-XD" }));  //"Missing argument for);
599                
600              }          
601              else
602              {
603                if (i + 1 < argv.length && argv[i + 1].charAt(0) != '-')
604                 i++;
605                 
606                printInvalidXalanOption("-XD");
607              }
608            }
609            // Specify the jar file name which the translet classes are packaged into.
610            else if ("-XJ".equalsIgnoreCase(argv[i]))
611            {
612              if (useXSLTC)
613              {
614                if (i + 1 < argv.length && argv[i+1].charAt(0) != '-')
615                {
616                  tfactory.setAttribute("generate-translet", "true");
617                  tfactory.setAttribute("jar-name", argv[++i]);
618                }
619                else
620                  System.err.println(
621                    XSLMessages.createMessage(
622                      XSLTErrorResources.ER_MISSING_ARG_FOR_OPTION,
623                      new Object[]{ "-XJ" }));  //"Missing argument for);
624              }                    
625              else
626              {
627                if (i + 1 < argv.length && argv[i + 1].charAt(0) != '-')
628                 i++;
629                 
630                printInvalidXalanOption("-XJ");
631              }
632            
633            }
634            // Specify the package name prefix for the generated translet classes.
635            else if ("-XP".equalsIgnoreCase(argv[i]))
636            {
637              if (useXSLTC)
638              {
639                if (i + 1 < argv.length && argv[i+1].charAt(0) != '-')
640                  tfactory.setAttribute("package-name", argv[++i]);
641                else
642                  System.err.println(
643                    XSLMessages.createMessage(
644                      XSLTErrorResources.ER_MISSING_ARG_FOR_OPTION,
645                      new Object[]{ "-XP" }));  //"Missing argument for);
646              }                              
647              else
648              {
649                if (i + 1 < argv.length && argv[i + 1].charAt(0) != '-')
650                 i++;
651                 
652                printInvalidXalanOption("-XP");
653              }
654            
655            }
656            // Enable template inlining.
657            else if ("-XN".equalsIgnoreCase(argv[i]))
658            {
659              if (useXSLTC)
660              {
661                tfactory.setAttribute("enable-inlining", "true");
662              }                                        
663              else
664                printInvalidXalanOption("-XN");        
665            }
666            // Turns on additional debugging message output
667            else if ("-XX".equalsIgnoreCase(argv[i]))
668            {
669              if (useXSLTC)
670              {
671                tfactory.setAttribute("debug", "true");
672              }                                        
673              else
674                printInvalidXalanOption("-XX");        
675            }
676            // Create the Transformer from the translet if the translet class is newer
677            // than the stylesheet.
678            else if ("-XT".equalsIgnoreCase(argv[i]))
679            {
680              if (useXSLTC)
681              {
682                tfactory.setAttribute("auto-translet", "true");
683              }                                        
684              else
685                printInvalidXalanOption("-XT");        
686            }
687            else if ("-SECURE".equalsIgnoreCase(argv[i]))
688            {
689              isSecureProcessing = true;
690              try
691              {
692                tfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
693              }
694              catch (TransformerConfigurationException e) {}
695            }
696            else
697              System.err.println(
698                XSLMessages.createMessage(
699                  XSLTErrorResources.ER_INVALID_OPTION, new Object[]{ argv[i] }));  //"Invalid argument:);
700          }
701          
702          // Print usage instructions if no xml and xsl file is specified in the command line
703          if (inFileName == null && xslFileName == null)
704          {
705              msg = resbundle.getString("xslProc_no_input");
706            System.err.println(msg);
707            doExit(msg);
708          }
709    
710          // Note that there are usage cases for calling us without a -IN arg
711          // The main XSL transformation occurs here!
712          try
713          {
714            long start = System.currentTimeMillis();
715    
716            if (null != dumpFileName)
717            {
718              dumpWriter = new PrintWriter(new FileWriter(dumpFileName));
719            }
720    
721            Templates stylesheet = null;
722    
723            if (null != xslFileName)
724            {
725              if (flavor.equals("d2d"))
726              {
727    
728                // Parse in the xml data into a DOM
729                DocumentBuilderFactory dfactory =
730                  DocumentBuilderFactory.newInstance();
731    
732                dfactory.setNamespaceAware(true);
733    
734                if (isSecureProcessing)
735                {
736                  try
737                  {
738                    dfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
739                  }
740                  catch (ParserConfigurationException pce) {}
741                }
742    
743                DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
744                Node xslDOM = docBuilder.parse(new InputSource(xslFileName));
745    
746                stylesheet = tfactory.newTemplates(new DOMSource(xslDOM,
747                        xslFileName));
748              }
749              else
750              {
751                // System.out.println("Calling newTemplates: "+xslFileName);
752                stylesheet = tfactory.newTemplates(new StreamSource(xslFileName));
753                // System.out.println("Done calling newTemplates: "+xslFileName);
754              }
755            }
756    
757            PrintWriter resultWriter;
758            StreamResult strResult;
759    
760            if (null != outFileName)
761            {
762              strResult = new StreamResult(new FileOutputStream(outFileName));
763              // One possible improvement might be to ensure this is 
764              //  a valid URI before setting the systemId, but that 
765              //  might have subtle changes that pre-existing users 
766              //  might notice; we can think about that later -sc r1.46
767              strResult.setSystemId(outFileName);
768            }
769            else
770            {
771              strResult = new StreamResult(System.out);
772              // We used to default to incremental mode in this case.
773              // We've since decided that since the -INCREMENTAL switch is
774              // available, that default is probably not necessary nor
775              // necessarily a good idea.
776            }
777    
778            SAXTransformerFactory stf = (SAXTransformerFactory) tfactory;
779            
780                    // This is currently controlled via TransformerFactoryImpl.
781            if (!useXSLTC && useSourceLocation)
782               stf.setAttribute(XalanProperties.SOURCE_LOCATION, Boolean.TRUE);        
783    
784            // Did they pass in a stylesheet, or should we get it from the 
785            // document?
786            if (null == stylesheet)
787            {
788              Source source =
789                stf.getAssociatedStylesheet(new StreamSource(inFileName), media,
790                                            null, null);
791    
792              if (null != source)
793                stylesheet = tfactory.newTemplates(source);
794              else
795              {
796                if (null != media)
797                  throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_NO_STYLESHEET_IN_MEDIA, new Object[]{inFileName, media})); //"No stylesheet found in: "
798                                                // + inFileName + ", media="
799                                                // + media);
800                else
801                  throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_NO_STYLESHEET_PI, new Object[]{inFileName})); //"No xml-stylesheet PI found in: "
802                                                 //+ inFileName);
803              }
804            }
805    
806            if (null != stylesheet)
807            {
808              Transformer transformer = flavor.equals("th") ? null : stylesheet.newTransformer();
809              transformer.setErrorListener(new DefaultErrorHandler(false));
810    
811              // Override the output format?
812              if (null != outputType)
813              {
814                transformer.setOutputProperty(OutputKeys.METHOD, outputType);
815              }
816    
817              if (transformer instanceof org.apache.xalan.transformer.TransformerImpl)
818              {
819                org.apache.xalan.transformer.TransformerImpl impl = (org.apache.xalan.transformer.TransformerImpl)transformer;
820                TraceManager tm = impl.getTraceManager();
821    
822                if (null != tracer)
823                  tm.addTraceListener(tracer);
824    
825                impl.setQuietConflictWarnings(quietConflictWarnings);
826    
827                            // This is currently controlled via TransformerFactoryImpl.
828                if (useSourceLocation)
829                  impl.setProperty(XalanProperties.SOURCE_LOCATION, Boolean.TRUE);
830    
831                if(recursionLimit>0)
832                  impl.setRecursionLimit(recursionLimit);
833    
834                // sc 28-Feb-01 if we re-implement this, please uncomment helpmsg in printArgOptions
835                // impl.setDiagnosticsOutput( setQuietMode ? null : diagnosticsWriter );
836              }
837    
838              int nParams = params.size();
839    
840              for (int i = 0; i < nParams; i += 2)
841              {
842                transformer.setParameter((String) params.elementAt(i),
843                                         (String) params.elementAt(i + 1));
844              }
845    
846              if (uriResolver != null)
847                transformer.setURIResolver(uriResolver);
848    
849              if (null != inFileName)
850              {
851                if (flavor.equals("d2d"))
852                {
853    
854                  // Parse in the xml data into a DOM
855                  DocumentBuilderFactory dfactory =
856                    DocumentBuilderFactory.newInstance();
857    
858                  dfactory.setCoalescing(true);
859                  dfactory.setNamespaceAware(true);
860    
861                  if (isSecureProcessing)
862                  {
863                    try
864                    {
865                      dfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
866                    }
867                    catch (ParserConfigurationException pce) {}
868                  }
869    
870                  DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
871    
872                  if (entityResolver != null)
873                    docBuilder.setEntityResolver(entityResolver);
874    
875                  Node xmlDoc = docBuilder.parse(new InputSource(inFileName));
876                  Document doc = docBuilder.newDocument();
877                  org.w3c.dom.DocumentFragment outNode =
878                    doc.createDocumentFragment();
879    
880                  transformer.transform(new DOMSource(xmlDoc, inFileName),
881                                        new DOMResult(outNode));
882    
883                  // Now serialize output to disk with identity transformer
884                  Transformer serializer = stf.newTransformer();
885                  serializer.setErrorListener(new DefaultErrorHandler(false));
886                  
887                  Properties serializationProps =
888                    stylesheet.getOutputProperties();
889    
890                  serializer.setOutputProperties(serializationProps);
891    
892                  if (contentHandler != null)
893                  {
894                    SAXResult result = new SAXResult(contentHandler);
895    
896                    serializer.transform(new DOMSource(outNode), result);
897                  }
898                  else
899                    serializer.transform(new DOMSource(outNode), strResult);
900                }
901                else if (flavor.equals("th"))
902                {
903                  for (int i = 0; i < 1; i++) // Loop for diagnosing bugs with inconsistent behavior
904                  {
905                  // System.out.println("Testing the TransformerHandler...");
906    
907                  // ===============
908                  XMLReader reader = null;
909    
910                  // Use JAXP1.1 ( if possible )      
911                  try
912                  {
913                    javax.xml.parsers.SAXParserFactory factory =
914                      javax.xml.parsers.SAXParserFactory.newInstance();
915    
916                    factory.setNamespaceAware(true);
917    
918                    if (isSecureProcessing)
919                    {
920                      try
921                      {
922                        factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
923                      }
924                      catch (org.xml.sax.SAXException se) {}
925                    }
926    
927                    javax.xml.parsers.SAXParser jaxpParser =
928                      factory.newSAXParser();
929    
930                    reader = jaxpParser.getXMLReader();
931                  }
932                  catch (javax.xml.parsers.ParserConfigurationException ex)
933                  {
934                    throw new org.xml.sax.SAXException(ex);
935                  }
936                  catch (javax.xml.parsers.FactoryConfigurationError ex1)
937                  {
938                    throw new org.xml.sax.SAXException(ex1.toString());
939                  }
940                  catch (NoSuchMethodError ex2){}
941                  catch (AbstractMethodError ame){}
942    
943                  if (null == reader)
944                  {
945                    reader = XMLReaderFactory.createXMLReader();
946                  }
947                  
948                  if (!useXSLTC)
949                    stf.setAttribute(org.apache.xalan.processor.TransformerFactoryImpl.FEATURE_INCREMENTAL, 
950                       Boolean.TRUE);
951                     
952                  TransformerHandler th = stf.newTransformerHandler(stylesheet);
953                  
954                  reader.setContentHandler(th);
955                  reader.setDTDHandler(th);
956                  
957                  if(th instanceof org.xml.sax.ErrorHandler)
958                    reader.setErrorHandler((org.xml.sax.ErrorHandler)th);
959                  
960                  try
961                  {
962                    reader.setProperty(
963                      "http://xml.org/sax/properties/lexical-handler", th);
964                  }
965                  catch (org.xml.sax.SAXNotRecognizedException e){}
966                  catch (org.xml.sax.SAXNotSupportedException e){}
967                  try
968                  {
969                    reader.setFeature("http://xml.org/sax/features/namespace-prefixes",
970                                      true);
971                  } catch (org.xml.sax.SAXException se) {}
972            
973                  th.setResult(strResult);
974                  
975                  reader.parse(new InputSource(inFileName));
976                  }                            
977                }
978                else
979                {
980                  if (entityResolver != null)
981                  {
982                    XMLReader reader = null;
983    
984                    // Use JAXP1.1 ( if possible )      
985                    try
986                    {
987                      javax.xml.parsers.SAXParserFactory factory =
988                        javax.xml.parsers.SAXParserFactory.newInstance();
989    
990                      factory.setNamespaceAware(true);
991    
992                      if (isSecureProcessing)
993                      {
994                        try
995                        {
996                          factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
997                        }
998                        catch (org.xml.sax.SAXException se) {}
999                      }
1000    
1001                      javax.xml.parsers.SAXParser jaxpParser =
1002                        factory.newSAXParser();
1003    
1004                      reader = jaxpParser.getXMLReader();
1005                    }
1006                    catch (javax.xml.parsers.ParserConfigurationException ex)
1007                    {
1008                      throw new org.xml.sax.SAXException(ex);
1009                    }
1010                    catch (javax.xml.parsers.FactoryConfigurationError ex1)
1011                    {
1012                      throw new org.xml.sax.SAXException(ex1.toString());
1013                    }
1014                    catch (NoSuchMethodError ex2){}
1015                    catch (AbstractMethodError ame){}
1016    
1017                    if (null == reader)
1018                    {
1019                      reader = XMLReaderFactory.createXMLReader();
1020                    }
1021    
1022                    reader.setEntityResolver(entityResolver);
1023    
1024                    if (contentHandler != null)
1025                    {
1026                      SAXResult result = new SAXResult(contentHandler);
1027    
1028                      transformer.transform(
1029                        new SAXSource(reader, new InputSource(inFileName)),
1030                        result);
1031                    }
1032                    else
1033                    {
1034                      transformer.transform(
1035                        new SAXSource(reader, new InputSource(inFileName)),
1036                        strResult);
1037                    }
1038                  }
1039                  else if (contentHandler != null)
1040                  {
1041                    SAXResult result = new SAXResult(contentHandler);
1042    
1043                    transformer.transform(new StreamSource(inFileName), result);
1044                  }
1045                  else
1046                  {
1047                    // System.out.println("Starting transform");
1048                    transformer.transform(new StreamSource(inFileName),
1049                                          strResult);
1050                    // System.out.println("Done with transform");
1051                  }
1052                }
1053              }
1054              else
1055              {
1056                StringReader reader =
1057                  new StringReader("<?xml version=\"1.0\"?> <doc/>");
1058    
1059                transformer.transform(new StreamSource(reader), strResult);
1060              }
1061            }
1062            else
1063            {
1064    //          "XSL Process was not successful.");
1065                msg = XSLMessages.createMessage(
1066                    XSLTErrorResources.ER_NOT_SUCCESSFUL, null);
1067              diagnosticsWriter.println(msg);  
1068              doExit(msg);
1069            }
1070            
1071            // close output streams
1072            if (null != outFileName && strResult!=null)
1073            {
1074              java.io.OutputStream out = strResult.getOutputStream();
1075              java.io.Writer writer = strResult.getWriter();
1076              try
1077              {
1078                if (out != null) out.close();
1079                if (writer != null) writer.close();
1080              }
1081              catch(java.io.IOException ie) {}
1082            }        
1083    
1084            long stop = System.currentTimeMillis();
1085            long millisecondsDuration = stop - start;
1086    
1087            if (doDiag)
1088            {
1089                    Object[] msgArgs = new Object[]{ inFileName, xslFileName, new Long(millisecondsDuration) };
1090                msg = XSLMessages.createMessage("diagTiming", msgArgs);
1091                    diagnosticsWriter.println('\n');
1092                    diagnosticsWriter.println(msg);
1093            }
1094              
1095          }
1096          catch (Throwable throwable)
1097          {
1098            while (throwable
1099                   instanceof org.apache.xml.utils.WrappedRuntimeException)
1100            {
1101              throwable =
1102                ((org.apache.xml.utils.WrappedRuntimeException) throwable).getException();
1103            }
1104    
1105            if ((throwable instanceof NullPointerException)
1106                    || (throwable instanceof ClassCastException))
1107              doStackDumpOnError = true;
1108    
1109            diagnosticsWriter.println();
1110    
1111            if (doStackDumpOnError)
1112              throwable.printStackTrace(dumpWriter);
1113            else
1114            {
1115              DefaultErrorHandler.printLocation(diagnosticsWriter, throwable);
1116              diagnosticsWriter.println(
1117                XSLMessages.createMessage(XSLTErrorResources.ER_XSLT_ERROR, null)
1118                + " (" + throwable.getClass().getName() + "): "
1119                + throwable.getMessage());
1120            }
1121    
1122            // diagnosticsWriter.println(XSLMessages.createMessage(XSLTErrorResources.ER_NOT_SUCCESSFUL, null)); //"XSL Process was not successful.");
1123            if (null != dumpFileName)
1124            {
1125              dumpWriter.close();
1126            }
1127    
1128            doExit(throwable.getMessage());
1129          }
1130    
1131          if (null != dumpFileName)
1132          {
1133            dumpWriter.close();
1134          }
1135    
1136          if (null != diagnosticsWriter)
1137          {
1138    
1139            // diagnosticsWriter.close();
1140          }
1141    
1142          // if(!setQuietMode)
1143          //  diagnosticsWriter.println(resbundle.getString("xsldone")); //"Xalan: done");
1144          // else
1145          // diagnosticsWriter.println("");  //"Xalan: done");
1146        }
1147      }
1148      
1149      /** It is _much_ easier to debug under VJ++ if I can set a single breakpoint 
1150       * before this blows itself out of the water...
1151       * (I keep checking this in, it keeps vanishing. Grr!)
1152       * */
1153      static void doExit(String msg)
1154      {
1155        throw new RuntimeException(msg);
1156      }
1157      
1158      /**
1159       * Wait for a return key to continue
1160       * 
1161       * @param resbundle The resource bundle
1162       */
1163      private static void waitForReturnKey(ResourceBundle resbundle)
1164      {
1165        System.out.println(resbundle.getString("xslProc_return_to_continue"));
1166        try
1167        {
1168          while (System.in.read() != '\n');
1169        }
1170        catch (java.io.IOException e) { }  
1171      }
1172      
1173      /**
1174       * Print a message if an option cannot be used with -XSLTC.
1175       *
1176       * @param option The option String
1177       */
1178      private static void printInvalidXSLTCOption(String option)
1179      {
1180        System.err.println(XSLMessages.createMessage("xslProc_invalid_xsltc_option", new Object[]{option}));
1181      }
1182      
1183      /**
1184       * Print a message if an option can only be used with -XSLTC.
1185       *
1186       * @param option The option String
1187       */
1188      private static void printInvalidXalanOption(String option)
1189      {
1190        System.err.println(XSLMessages.createMessage("xslProc_invalid_xalan_option", new Object[]{option}));
1191      }
1192    }