| /* DoParse.java -- |
| Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| package gnu.xml.util; |
| |
| import java.io.IOException; |
| |
| import org.xml.sax.ErrorHandler; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXParseException; |
| import org.xml.sax.XMLReader; |
| import org.xml.sax.helpers.XMLReaderFactory; |
| |
| import gnu.xml.pipeline.EventConsumer; |
| import gnu.xml.pipeline.EventFilter; |
| import gnu.xml.pipeline.NSFilter; |
| import gnu.xml.pipeline.PipelineFactory; |
| import gnu.xml.pipeline.TeeConsumer; |
| import gnu.xml.pipeline.ValidationConsumer; |
| import gnu.xml.pipeline.WellFormednessFilter; |
| |
| /** |
| * This class provides a driver which may be invoked from the command line |
| * to process a document using a SAX2 parser and a specified XML processing |
| * pipeline. |
| * This facilitates some common types of command line tools, such as parsing an |
| * XML document in order test it for well formedness or validity. |
| * |
| * <p>The SAX2 XMLReaderFactory should return a SAX2 XML parser which |
| * supports both of the standardized extension handlers (for declaration |
| * and lexical events). That parser will be used to produce events. |
| * |
| * <p>The first parameter to the command gives the name of the document that |
| * will be given to that processor. If it is a file name, it is converted |
| * to a URL first. |
| * |
| * <p>The second parameter describes a simple processing pipeline, and will |
| * be used as input to {@link gnu.xml.pipeline.PipelineFactory} |
| * methods which identify the processing to be done. Examples of such a |
| * pipeline include <pre> |
| * |
| * nsfix | validate <em>to validate the input document </em> |
| * nsfix | write ( stdout ) <em>to echo the file as XML text</em> |
| * dom | nsfix | write ( stdout ) <em>parse into DOM, print the result</em> |
| * </pre> |
| * |
| * <p> Relatively complex pipelines can be described on the command line, but |
| * not all interesting ones will require as little configuration as can be done |
| * in that way. Put filters like "nsfix", perhaps followed by "validate", |
| * at the front of the pipeline so they can be optimized out if a parser |
| * supports those modes natively. |
| * |
| * <p> If the parsing is aborted for any reason, the JVM will exit with a |
| * failure code. If a validating parse was done then both validation and |
| * well formedness errors will cause a failure. A non-validating parse |
| * will report failure on well formedness errors. |
| * |
| * @see gnu.xml.pipeline.PipelineFactory |
| * |
| * @author David Brownell |
| */ |
| final public class DoParse |
| { |
| private DoParse () { /* no instances allowed */ } |
| |
| // first reported nonrecoverable error |
| private static SAXParseException fatal; |
| |
| // error categories |
| private static int errorCount; |
| private static int fatalCount; |
| |
| /** |
| * Command line invoker for this class; pass a filename or URL |
| * as the first argument, and a pipeline description as the second. |
| * Make sure to use filters to condition the input to stages that |
| * require it; an <em>nsfix</em> filter will be a common requirement, |
| * to restore syntax that SAX2 parsers delete by default. Some |
| * conditioning filters may be eliminated by setting parser options. |
| * (For example, "nsfix" can set the "namespace-prefixes" feature to |
| * a non-default value of "true". In the same way, "validate" can set |
| * the "validation" feature to "true".) |
| */ |
| public static void main (String argv []) |
| throws IOException |
| { |
| int exitStatus = 1; |
| |
| if (argv.length != 2) { |
| System.err.println ("Usage: DoParse [filename|URL] pipeline-spec"); |
| System.err.println ("Example pipeline specs:"); |
| System.err.println (" 'nsfix | validate'"); |
| System.err.println ( |
| " ... restore namespace syntax, validate"); |
| System.err.println (" 'nsfix | write ( stdout )'"); |
| System.err.println ( |
| " ... restore namespace syntax, write to stdout as XML" |
| ); |
| System.exit (1); |
| } |
| |
| try { |
| // |
| // Get input source for specified document (or try ;-) |
| // |
| argv [0] = Resolver.getURL (argv [0]); |
| InputSource input = new InputSource (argv [0]); |
| |
| // |
| // Get the producer, using the system default parser (which |
| // can be overridden for this particular invocation). |
| // |
| // And the pipeline, using commandline options. |
| // |
| XMLReader producer; |
| EventConsumer consumer; |
| |
| producer = XMLReaderFactory.createXMLReader (); |
| |
| // |
| // XXX pipeline factory now has a pre-tokenized input |
| // method, use it ... that way at least some params |
| // can be written using quotes (have spaces, ...) |
| // |
| consumer = PipelineFactory.createPipeline (argv [1]); |
| |
| // |
| // XXX want commandline option for tweaking error handler. |
| // Want to be able to present warnings. |
| // |
| producer.setErrorHandler (new MyErrorHandler ()); |
| |
| // XXX need facility enabling resolving to local DTDs |
| |
| // |
| // Parse. The pipeline may get optimized a bit, so we |
| // can't always fail cleanly for validation without taking |
| // a look at the filter stages. |
| // |
| EventFilter.bind (producer, consumer); |
| producer.parse (input); |
| |
| try { |
| if (producer.getFeature ( |
| "http://org.xml/sax/features/validation")) |
| exitStatus = ((errorCount + fatalCount) > 0) ? 1 : 0; |
| else if (fatalCount == 0) |
| exitStatus = 0; |
| } catch (SAXException e) { |
| if (hasValidator (consumer)) |
| exitStatus = ((errorCount + fatalCount) > 0) ? 1 : 0; |
| else if (fatalCount == 0) |
| exitStatus = 0; |
| } |
| |
| } catch (java.net.MalformedURLException e) { |
| System.err.println ("** Malformed URL: " + e.getMessage ()); |
| System.err.println ("Is '" + argv [0] + "' a non-existent file?"); |
| e.printStackTrace (); |
| // e.g. FNF |
| |
| } catch (SAXParseException e) { |
| if (e != fatal) { |
| System.err.print (printParseException ("Parsing Aborted", e)); |
| e.printStackTrace (); |
| if (e.getException () != null) { |
| System.err.println ("++ Wrapped exception:"); |
| e.getException ().printStackTrace (); |
| } |
| } |
| |
| } catch (SAXException e) { |
| Exception x = e; |
| if (e.getException () != null) |
| x = e.getException (); |
| x.printStackTrace (); |
| |
| } catch (Throwable t) { |
| t.printStackTrace (); |
| } |
| |
| System.exit (exitStatus); |
| } |
| |
| // returns true if saw a validator (before end or unrecognized node) |
| // false otherwise |
| private static boolean hasValidator (EventConsumer e) |
| { |
| if (e == null) |
| return false; |
| if (e instanceof ValidationConsumer) |
| return true; |
| if (e instanceof TeeConsumer) { |
| TeeConsumer t = (TeeConsumer) e; |
| return hasValidator (t.getFirst ()) |
| || hasValidator (t.getRest ()); |
| } |
| if (e instanceof WellFormednessFilter |
| || e instanceof NSFilter |
| ) |
| return hasValidator (((EventFilter)e).getNext ()); |
| |
| // else ... gee, we can't know. Assume not. |
| |
| return false; |
| } |
| |
| static class MyErrorHandler implements ErrorHandler |
| { |
| // dump validation errors, but continue |
| public void error (SAXParseException e) |
| throws SAXParseException |
| { |
| errorCount++; |
| System.err.print (printParseException ("Error", e)); |
| } |
| |
| public void warning (SAXParseException e) |
| throws SAXParseException |
| { |
| // System.err.print (printParseException ("Warning", e)); |
| } |
| |
| // try to continue fatal errors, in case a parser reports more |
| public void fatalError (SAXParseException e) |
| throws SAXParseException |
| { |
| fatalCount++; |
| if (fatal == null) |
| fatal = e; |
| System.err.print (printParseException ("Nonrecoverable Error", e)); |
| } |
| } |
| |
| static private String printParseException ( |
| String label, |
| SAXParseException e |
| ) { |
| StringBuffer buf = new StringBuffer (); |
| int temp; |
| |
| buf.append ("** "); |
| buf.append (label); |
| buf.append (": "); |
| buf.append (e.getMessage ()); |
| buf.append ('\n'); |
| if (e.getSystemId () != null) { |
| buf.append (" URI: "); |
| buf.append (e.getSystemId ()); |
| buf.append ('\n'); |
| } |
| if ((temp = e.getLineNumber ()) != -1) { |
| buf.append (" line: "); |
| buf.append (temp); |
| buf.append ('\n'); |
| } |
| if ((temp = e.getColumnNumber ()) != -1) { |
| buf.append (" char: "); |
| buf.append (temp); |
| buf.append ('\n'); |
| } |
| |
| return buf.toString (); |
| } |
| } |