1   /**
2    * Distribution License:
3    * JSword is free software; you can redistribute it and/or modify it under
4    * the terms of the GNU Lesser General Public License, version 2.1 as published by
5    * the Free Software Foundation. This program is distributed in the hope
6    * that it will be useful, but WITHOUT ANY WARRANTY; without even the
7    * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8    * See the GNU Lesser General Public License for more details.
9    *
10   * The License is available on the internet at:
11   *       http://www.gnu.org/copyleft/lgpl.html
12   * or by writing to:
13   *      Free Software Foundation, Inc.
14   *      59 Temple Place - Suite 330
15   *      Boston, MA 02111-1307, USA
16   *
17   * Copyright: 2005
18   *     The copyright to this program is held by it's authors.
19   *
20   * ID: $Id: XMLProcess.java 2012 2010-11-11 23:24:41Z dmsmith $
21   */
22  package org.crosswire.common.xml;
23  
24  import java.io.IOException;
25  
26  import org.crosswire.common.util.ClassUtil;
27  import org.xml.sax.SAXException;
28  import org.xml.sax.XMLReader;
29  import org.xml.sax.helpers.XMLReaderFactory;
30  
31  /**
32   * Runs an xml parser on an xml file using an xml handler. The default behavior
33   * is to check that the xml file is well-formed.
34   * 
35   * @see gnu.lgpl.License for license details.<br>
36   *      The copyright to this program is held by it's authors.
37   * @author DM Smith [dmsmith555 at yahoo dot com]
38   */
39  public class XMLProcess {
40  
41      public XMLProcess() {
42          features = new XMLFeatureSet();
43      }
44  
45      /**
46       * @return Returns the features.
47       */
48      public XMLFeatureSet getFeatures() {
49          return features;
50      }
51  
52      /**
53       * Process an xml file according to the arguments.
54       * 
55       * @param argv
56       */
57      public static void main(String[] argv) {
58          XMLProcess checker = new XMLProcess();
59  
60          // is there anything to do?
61          if (argv.length == 0) {
62              checker.usage();
63              System.exit(1);
64          }
65  
66          // variables
67          String arg = null;
68  
69          // process arguments
70          for (int i = 0; i < argv.length; i++) {
71              arg = argv[i];
72              if (arg.charAt(0) == '-') {
73                  String option = arg.substring(1);
74                  if ("h".equals(option)) {
75                      checker.usage();
76                      System.exit(0);
77                  }
78              }
79          }
80  
81          checker.initialize(argv);
82          checker.parse(arg);
83  
84      }
85  
86      private void initialize(String[] argv) {
87          // process arguments
88          int i = 0;
89          for (i = 0; i < argv.length; i++) {
90              String arg = argv[i];
91              if (arg.charAt(0) == '-') {
92                  String option = arg.substring(1);
93                  if ("p".equals(option)) {
94                      // get parser name
95                      if (++i == argv.length) {
96                          System.err.println("error: Missing argument to -p option.");
97                      }
98                      parserName = argv[i];
99  
100                     createParser();
101                     continue;
102                 }
103                 if ("a".equals(option)) {
104                     // get parser name
105                     if (++i == argv.length) {
106                         System.err.println("error: Missing argument to -a option.");
107                     }
108                     adapterName = argv[i];
109 
110                     createAdapter();
111                     continue;
112                 }
113             }
114         }
115 
116         features.setFeatureStates(argv);
117     }
118 
119     private void bind() {
120         createParser();
121         createAdapter();
122 
123         // Now that we have a parser and a handler
124         // make the parser use them.
125         setHandlers();
126         features.setFeatures(parser);
127 
128     }
129 
130     private void createParser() {
131         if (parser != null) {
132             return;
133         }
134 
135         try {
136             parser = XMLReaderFactory.createXMLReader(parserName);
137         } catch (SAXException e) {
138             System.err.println("error: Unable to instantiate parser (" + parserName + ")");
139         }
140 
141     }
142 
143     private void createAdapter() {
144         if (adapter != null) {
145             return;
146         }
147 
148         try {
149             adapter = (XMLHandlerAdapter) ClassUtil.forName(adapterName).newInstance();
150         } catch (ClassNotFoundException e) {
151             System.err.println("error: Unable to instantiate XMLHandlerAdpater (" + adapterName + ")");
152         } catch (InstantiationException e) {
153             System.err.println("error: Unable to instantiate XMLHandlerAdpater (" + adapterName + ")");
154         } catch (IllegalAccessException e) {
155             System.err.println("error: Unable to instantiate XMLHandlerAdpater (" + adapterName + ")");
156         }
157 
158     }
159 
160     private void setHandlers() {
161         parser.setDTDHandler(adapter);
162         parser.setErrorHandler(adapter);
163         parser.setContentHandler(adapter);
164 
165         try {
166             parser.setProperty(DECLARATION_HANDLER_PROPERTY_ID, adapter);
167         } catch (SAXException e) {
168             e.printStackTrace(System.err);
169         }
170 
171         try {
172             parser.setProperty(LEXICAL_HANDLER_PROPERTY_ID, adapter);
173         } catch (SAXException e) {
174             e.printStackTrace(System.err);
175         }
176     }
177 
178     public void parse(String xmlFile) {
179         bind();
180         // parse file
181         try {
182             System.out.println("Parsing with the following:");
183             printActual();
184             parser.parse(xmlFile);
185             System.out.println("Done: no problems found.");
186         } catch (SAXException e) {
187             System.err.println("error: Parse error occurred - " + e.getMessage());
188             Exception nested = e.getException();
189             if (nested != null) {
190                 nested.printStackTrace(System.err);
191             } else {
192                 e.printStackTrace(System.err);
193             }
194         } catch (IOException e) {
195             e.printStackTrace(System.err);
196         }
197     }
198 
199     /** Prints the usage. */
200     private void usage() {
201         System.err.println("usage: java org.crosswire.common.xml.XMLProcess (options) uri");
202         System.err.println();
203 
204         System.err.println("options:");
205         printUsage();
206         System.err.println("  -h          This help screen.");
207         System.err.println();
208 
209         System.err.println("defaults:");
210         printDefaults();
211     }
212 
213     public void printUsage() {
214         System.err.println("  -p name     Select parser by name.");
215         System.err.println("  -a name     Select XMLHandlerAdapter by name.");
216         features.printUsage();
217     }
218 
219     public void printDefaults() {
220         System.err.println("Parser:     " + DEFAULT_PARSER_NAME);
221         System.err.println("Handler:    " + DEFAULT_HANDLER_NAME);
222         System.err.println(new XMLFeatureSet().toString());
223     }
224 
225     public void printActual() {
226         System.err.println("Parser:     " + parserName);
227         System.err.println("Handler:    " + adapterName);
228         System.err.println(new XMLFeatureSet().toString());
229     }
230 
231     // property ids
232 
233     /**
234      * Lexical handler property id
235      */
236     private static final String LEXICAL_HANDLER_PROPERTY_ID = "http://xml.org/sax/properties/lexical-handler";
237 
238     /**
239      * Declaration handler property id
240      */
241     private static final String DECLARATION_HANDLER_PROPERTY_ID = "http://xml.org/sax/properties/declaration-handler";
242 
243     // default settings
244 
245     /** Default parser name. */
246     private static final String DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser";
247     private static final String DEFAULT_HANDLER_NAME = "org.crosswire.common.xml.XMLHandlerAdapter";
248 
249     private String parserName = DEFAULT_PARSER_NAME;
250     private XMLReader parser;
251     private String adapterName = DEFAULT_HANDLER_NAME;
252     private XMLHandlerAdapter adapter;
253     private XMLFeatureSet features;
254 }
255