001: /* Copyright (c) 2001, 2003 TOPP - www.openplans.org. All rights reserved.
002: * This code is licensed under the GPL 2.0 license.
003: */
004: package net.refractions.udig.style.sld.editor;
005:
006: import java.io.BufferedReader;
007: import java.io.InputStream;
008: import java.io.InputStreamReader;
009: import java.io.Reader;
010: import java.util.ArrayList;
011: import java.util.List;
012:
013: import net.refractions.udig.style.sld.internal.Messages;
014:
015: import org.apache.xerces.parsers.SAXParser;
016: import org.xml.sax.InputSource;
017: import org.xml.sax.SAXException;
018: import org.xml.sax.SAXParseException;
019: import org.xml.sax.helpers.DefaultHandler;
020:
021: /**
022: * SLDValidator borrowed from geoserver org.vfny.geoserver.util
023: * <p>
024: *
025: * </p>
026: * @author chorner
027: * @since 1.1.0
028: */
029: public class SLDValidator {
030: public SLDValidator() {
031: }
032:
033: public static String getErrorMessage(InputStream xml, List errors) {
034: return getErrorMessage(new InputStreamReader(xml), errors);
035: }
036:
037: /**
038: * returns a better formatted error message - suitable for framing. There's
039: * a more complex version in StylesEditorAction. This will kick out a VERY
040: * LARGE errorMessage.
041: *
042: * @param xml
043: * @param errors
044: *
045: * @return DOCUMENT ME!
046: */
047: public static String getErrorMessage(Reader xml, List errors) {
048: BufferedReader reader = null;
049: StringBuffer result = new StringBuffer();
050: result.append(Messages.StyleEditor_xml_validator_common);
051:
052: try {
053: reader = new BufferedReader(xml);
054:
055: String line = reader.readLine();
056: int linenumber = 1;
057: int exceptionNum = 0;
058:
059: //check for lineNumber -1 errors --> invalid XML
060: if (errors.size() > 0) {
061: SAXParseException sax = (SAXParseException) errors
062: .get(0);
063:
064: if (sax.getLineNumber() < 0) {
065: result.append(" INVALID XML: " //$NON-NLS-1$
066: + sax.getLocalizedMessage() + "\n"); //$NON-NLS-1$
067: result.append(" \n"); //$NON-NLS-1$
068: exceptionNum = 1; // skip ahead (you only ever get one error in this case)
069: }
070: }
071:
072: while (line != null) {
073: line = line.replace('\n', ' ');
074: line = line.replace('\r', ' ');
075:
076: String header = linenumber + ": "; //$NON-NLS-1$
077: result.append(header + line + "\n"); // record the current line //$NON-NLS-1$
078:
079: boolean keep_going = true;
080:
081: while (keep_going) {
082: if ((exceptionNum < errors.size())) {
083: SAXParseException sax = (SAXParseException) errors
084: .get(exceptionNum);
085:
086: if (sax.getLineNumber() <= linenumber) {
087: String head = "---------------------".substring(0, //$NON-NLS-1$
088: header.length() - 1);
089: String body = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"; //$NON-NLS-1$
090:
091: int colNum = sax.getColumnNumber(); //protect against col 0 problems
092:
093: if (colNum < 1) {
094: colNum = 1;
095: }
096:
097: if (colNum > body.length()) {
098: body = body + body + body + body + body
099: + body; // make it longer (not usually required, but might be for SLD_BODY=... which is all one line)
100:
101: if (colNum > body.length()) {
102: colNum = body.length();
103: }
104: }
105:
106: result.append(head
107: + body.substring(0, colNum - 1)
108: + "^\n"); //$NON-NLS-1$
109: result
110: .append(" (line " + sax.getLineNumber() //$NON-NLS-1$
111: + ", column " + sax.getColumnNumber() + ")" //$NON-NLS-1$//$NON-NLS-2$
112: + sax.getLocalizedMessage()
113: + "\n"); //$NON-NLS-1$
114: exceptionNum++;
115: } else {
116: keep_going = false; //report later (sax.getLineNumber() > linenumber)
117: }
118: } else {
119: keep_going = false; // no more errors to report
120: }
121: }
122:
123: line = reader.readLine(); //will be null at eof
124: linenumber++;
125: }
126:
127: for (int t = exceptionNum; t < errors.size(); t++) {
128: SAXParseException sax = (SAXParseException) errors
129: .get(t);
130: result.append(" (line " + sax.getLineNumber() //$NON-NLS-1$
131: + ", column " + sax.getColumnNumber() + ")" //$NON-NLS-1$ //$NON-NLS-2$
132: + sax.getLocalizedMessage() + "\n"); //$NON-NLS-1$
133: }
134: } catch (Exception e) {
135: e.printStackTrace();
136: } finally {
137: try {
138: if (reader != null) {
139: reader.close();
140: }
141: } catch (Exception e) {
142: e.printStackTrace();
143: }
144: }
145:
146: return result.toString();
147: }
148:
149: public List validateSLD(InputStream xml, String SchemaUrl) {
150: return validateSLD(new InputSource(xml), SchemaUrl);
151: }
152:
153: /**
154: * validate a .sld against the schema
155: *
156: * @param xml input stream representing the .sld file
157: * @param SchemaUrl location of the schemas. Normally use
158: * ".../schemas/sld/StyleLayerDescriptor.xsd"
159: *
160: * @return list of SAXExceptions (0 if the file's okay)
161: */
162: public List validateSLD(InputSource xml, String SchemaUrl) {
163: SAXParser parser = new SAXParser();
164:
165: try {
166: // 1. tell the parser to validate the XML document vs the schema
167: // 2. does not validate the schema (the GML schema is *not* valid. This is
168: // an OGC blunder)
169: // 3. tells the validator that the tags without a namespace are actually
170: // SLD tags.
171: // 4. tells the validator to 'override' the SLD schema that a user may
172: // include with the one inside geoserver.
173:
174: parser.setFeature(
175: "http://xml.org/sax/features/validation", true); //$NON-NLS-1$
176: parser.setFeature(
177: "http://apache.org/xml/features/validation/schema", //$NON-NLS-1$
178: true);
179: parser
180: .setFeature(
181: "http://apache.org/xml/features/validation/schema-full-checking", //$NON-NLS-1$
182: false);
183: parser
184: .setProperty(
185: "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation", //$NON-NLS-1$
186: SchemaUrl);
187: parser
188: .setProperty(
189: "http://apache.org/xml/properties/schema/external-schemaLocation", //$NON-NLS-1$
190: "http://www.opengis.net/sld " + SchemaUrl); //$NON-NLS-1$
191:
192: //parser.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation","http://www.opengis.net/ows "+SchemaUrl);
193: Validator handler = new Validator();
194: parser.setErrorHandler(handler);
195: parser.parse(xml);
196:
197: return handler.errors;
198: } catch (java.io.IOException ioe) {
199: ArrayList<SAXParseException> al = new ArrayList<SAXParseException>();
200: al.add(new SAXParseException(ioe.getLocalizedMessage(),
201: null));
202:
203: return al;
204: } catch (SAXException e) {
205: ArrayList<SAXParseException> al = new ArrayList<SAXParseException>();
206: al
207: .add(new SAXParseException(e.getLocalizedMessage(),
208: null));
209:
210: return al;
211: }
212: }
213:
214: // errors in the document will be put in "errors".
215: // if errors.size() ==0 then there were no errors.
216: private class Validator extends DefaultHandler {
217: public ArrayList<SAXParseException> errors = new ArrayList<SAXParseException>();
218:
219: @Override
220: public void error(SAXParseException exception)
221: throws SAXException {
222: errors.add(exception);
223: }
224:
225: @Override
226: public void fatalError(SAXParseException exception)
227: throws SAXException {
228: errors.add(exception);
229: }
230:
231: @Override
232: public void warning(SAXParseException exception)
233: throws SAXException {
234: //do nothing
235: }
236: }
237: }
|