Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that validates XML documents
4
 *             This class is designed to be 'parser independent
5
 *             i.e. it uses only org.xml.sax classes
6
 *             It is tied to SAX 2.0 methods
7
 *  Copyright: 2000 Regents of the University of California and the
8
 *             National Center for Ecological Analysis and Synthesis
9
 *    Authors: Dan Higgins, Matt Jones
10
 *    Release: @release@
11
 * 
12
 *   '$Author: jones $'
13
 *     '$Date: 2001-01-18 11:52:00 -0800 (Thu, 18 Jan 2001) $'
14
 * '$Revision: 669 $'
15
 *
16
 * This program is free software; you can redistribute it and/or modify
17
 * it under the terms of the GNU General Public License as published by
18
 * the Free Software Foundation; either version 2 of the License, or
19
 * (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, write to the Free Software
28
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
 */
30
package edu.ucsb.nceas.metacat;
31

    
32

    
33
import java.net.URL;
34
import java.net.MalformedURLException;
35
import java.util.*;
36
import java.io.*;
37
import java.lang.reflect.*;
38
import java.sql.*;
39

    
40
import org.w3c.dom.*;
41
import org.xml.sax.*;
42
import org.xml.sax.XMLReader;
43
import org.xml.sax.helpers.XMLReaderFactory;
44

    
45
import com.arbortext.catalog.*;
46

    
47
/**
48
 * Name: DBValidate.java
49
 *       Purpose: A Class that validates XML documents
50
 * 			   This class is designed to be parser independent
51
 *    			   i.e. it uses only org.xml.sax classes
52
 * 			   It is tied to SAX 2.0 methods
53
 *     Copyright: 2000 Regents of the University of California and the
54
 *                National Center for Ecological Analysis and Synthesis
55
 *                April 28, 2000
56
 *    Authors: Dan Higgins, Matt Jones
57
 */
58
public class DBValidate {
59
    
60
  static int WARNING = 0;
61
  static int ERROR=1;
62
  static int FATAL_ERROR=2;
63

    
64
  XMLReader parser;
65
  ErrorStorer ef;
66
  String xml_doc; // document to be parsed
67
    
68
  /** Construct a new validation object */
69
  public DBValidate(String parserName) {
70

    
71
    try {
72
      // Get an instance of the parser
73
      parser = XMLReaderFactory.createXMLReader(parserName);
74
      parser.setFeature("http://xml.org/sax/features/validation",true);
75
      //parser.setValidationMode(true);     // Oracle
76
    } catch (Exception e) {
77
      System.err.println("Could not create parser!!!");
78
    }
79
  }
80
    
81
  /** Construct a new validation object using an OASIS catalog file */
82
  public DBValidate(String parserName, String xmlcatalogfile)  {
83
    this(parserName);
84

    
85
    CatalogEntityResolver cer = new CatalogEntityResolver();
86
    try {
87
      Catalog myCatalog = new Catalog();
88
      myCatalog.loadSystemCatalogs();
89
      myCatalog.parseCatalog(xmlcatalogfile);
90
      cer.setCatalog(myCatalog);
91
    } catch (Exception e) {System.out.println("Problem creating Catalog!");}
92

    
93
    parser.setEntityResolver(cer);
94
  }
95

    
96
  /** Construct a new validation object using a database entity resolver */
97
  public DBValidate(String parserName, Connection conn) {
98
    this(parserName);
99

    
100
    DBEntityResolver dbresolver = new DBEntityResolver(conn);
101
    parser.setEntityResolver(dbresolver);
102
  }
103

    
104
  /** 
105
   * validate an xml document against its DTD
106
   *
107
   * @param doc the filename of the document to validate
108
   */
109
  public boolean validate(String doc) {
110
    xml_doc = doc;    
111
    ef = new ErrorStorer();
112
    ef.resetErrors();
113
    parser.setErrorHandler(ef);
114
    try {
115
      parser.parse((createURL(xml_doc)).toString());
116
    } catch (IOException e) {
117
      System.out.println("IOException:Could not parse :"+xml_doc);
118
      ParseError eip = null;
119
      eip = new ParseError("",0,0,
120
                "IOException:Could not parse :"+xml_doc);
121
      if (ef.errorNodes == null)  ef.errorNodes = new Vector();
122
      ef.errorNodes.addElement(eip);
123
        
124
    } catch (Exception e) {} 
125

    
126
      // {System.out.println("Exception parsing:Could not parse :"+xml_doc);} 
127
    
128
    if (ef != null && ef.getErrorNodes()!=null && 
129
      ef.getErrorNodes().size() > 0 ) {
130
      return false; 
131
    } else {
132
      return true;
133
    }
134
  }
135
    
136
  /** 
137
   * validate an xml document against its DTD
138
   *
139
   * @param xmldoc the String containing the xml document to validate
140
   */
141
  public boolean validateString(String xmldoc) {
142
    // string is actual XML here, NOT URL or file name    
143
    ef = new ErrorStorer();
144
    ef.resetErrors();
145
    parser.setErrorHandler(ef);
146
      
147
    InputSource is = new InputSource(new StringReader(xmldoc));
148
    try {
149
      parser.parse(is);
150
    }
151
    catch (Exception e) {System.out.println("Error in parsing!");}
152

    
153
    if (ef != null && ef.getErrorNodes()!=null && 
154
      ef.getErrorNodes().size() > 0 ) {
155
      return false; 
156
    } else {
157
      return true;
158
    }
159
  }
160
    
161
  /** provide a list of errors from the validation process */
162
  public String returnErrors() {
163
    StringBuffer errorstring = new StringBuffer();
164
    errorstring.append("<?xml version=\"1.0\" ?>\n");
165
    if (ef != null && ef.getErrorNodes()!=null && 
166
        ef.getErrorNodes().size() > 0 ) {
167
      Vector errors = ef.getErrorNodes();
168
      errorstring.append("<validationerrors>\n");
169
      for (Enumeration e = errors.elements() ; e.hasMoreElements() ;) {
170
        errorstring.append(
171
                      ((ParseError)(e.nextElement())).toXML());
172
      }
173
      errorstring.append("</validationerrors>\n");
174
    } else {
175
      errorstring.append("<valid />\n");
176
    }
177
    return errorstring.toString();
178
  }
179
              
180
  /** Create a URL object from either a URL string or a plain file name. */
181
  private URL createURL(String name) throws Exception {
182
    try {
183
      URL u = new URL(name);
184
      return u;
185
    } catch (MalformedURLException ex) {
186
    }
187
    URL u = new URL("file:" + new File(name).getAbsolutePath());
188
    return u;
189
  }    
190

    
191
  /** 
192
   * main method for testing 
193
   * <p>
194
   * Usage: java DBValidate <xmlfile or URL>
195
   */
196
  public static void main(String[] args) {
197

    
198
    if (args.length != 1) {
199
      System.out.println("Usage: java DBValidate <xmlfile or URL>");
200
      System.exit(0);
201
    }
202

    
203
    String doc = args[0];
204

    
205
    MetaCatUtil util = new MetaCatUtil();
206
    try {
207
      Connection conn = util.openDBConnection();
208
  
209
      DBValidate gxv = new DBValidate(util.getOption("saxparser"), conn);
210
      if (gxv.validate(doc)) {
211
        System.out.print(gxv.returnErrors());
212
      } else {
213
        System.out.print(gxv.returnErrors());
214
      }
215
    } catch (SQLException e) {
216
      System.out.println("<error>Couldn't open database connection.</error>");
217
    } catch (ClassNotFoundException e) {
218
      System.out.println("<error>Couldn't open database connection.</error>");
219
    }
220
  }
221

    
222
    
223
  /**
224
   * ErrorStorer has been revised here to simply create a Vector of 
225
   * ParseError objects
226
   *
227
   */
228
  class ErrorStorer implements ErrorHandler {
229

    
230
    //
231
    // Data
232
    //
233
    Vector errorNodes = null;
234
        
235
    /**
236
     * Constructor
237
     */
238
    public ErrorStorer() {
239
    }
240

    
241
    /**
242
     * The client is is allowed to get a reference to the Hashtable,
243
     * and so could corrupt it, or add to it...
244
     */
245
    public Vector getErrorNodes() {
246
        return errorNodes;
247
    }
248

    
249
    /**
250
     * The ParseError object for the node key is returned.
251
     * If the node doesn't have errors, null is returned.
252
     */
253
    public Object getError() {
254
        if (errorNodes == null)
255
            return null;
256
        return errorNodes;
257
    }
258
        
259
    /**
260
     * Reset the error storage.
261
     */
262
    public void resetErrors() {
263
        if (errorNodes != null)
264
        errorNodes.removeAllElements();
265
    }
266
    
267
    /***/
268
    public void warning(SAXParseException ex) {
269
        handleError(ex, WARNING);
270
    }
271

    
272
    public void error(SAXParseException ex) {
273
        handleError(ex, ERROR);
274
    }
275

    
276
    public void fatalError(SAXParseException ex) throws SAXException {
277
        handleError(ex, FATAL_ERROR);
278
    }
279
        
280
    private void handleError(SAXParseException ex, int type) {
281
      // System.out.println("!!! handleError: "+ex.getMessage());
282

    
283
      if (errorNodes == null) {
284
        errorNodes = new Vector();
285
      }
286

    
287
      ParseError eip = null;
288
      eip = new ParseError(ex.getSystemId(), ex.getLineNumber(),
289
                           ex.getColumnNumber(), ex.getMessage());
290
        
291
      // put it in the Hashtable.
292
      errorNodes.addElement(eip);
293
    }
294
        
295
  }
296
    
297
  /**
298
   * The ParseError class wraps up all the error info from
299
   * the ErrorStorer's error method.
300
   *
301
   * @see ErrorStorer
302
   */
303
  class ParseError extends Object {
304

    
305
    //
306
    // Data
307
    //
308

    
309
    String fileName;
310
    int lineNo;
311
    int charOffset;
312
    String msg;
313

    
314
    /**
315
     * Constructor
316
     */
317
    public ParseError(String fileName, int lineNo, int charOffset, String msg) {
318
      this.fileName=fileName;
319
      this.lineNo=lineNo;
320
      this.charOffset=charOffset;
321
      this.msg=msg;
322
    }
323

    
324
    //
325
    // Getters...
326
    //
327
    public String getFileName() { return fileName; }
328
    public int getLineNo() { return lineNo; }
329
    public int getCharOffset() { return charOffset;}
330
    public String getMsg() { return msg; }
331
    public void setMsg(String s) { msg = s; }
332

    
333
    /** Return the error message as an xml fragment */
334
    public String toXML() {
335
      StringBuffer err = new StringBuffer();
336
      err.append("<error>\n");
337
      err.append("<filename>").append(getFileName()).append("</filename>\n");
338
      err.append("<line>").append(getLineNo()).append("</line>\n");
339
      err.append("<offset>").append(getCharOffset()).append("</offset>\n");
340
      err.append("<message>").append(getMsg()).append("</message>\n");
341
      err.append("</error>\n");
342
      return err.toString();
343
    }
344
  }
345
}
(20-20/43)