blob: 9d282f1e3275eebfbc99d51426818df113428dbd [file] [log] [blame]
lmandel3c550af2005-06-16 05:46:02 +00001/*******************************************************************************
amywuecebb042007-04-10 20:07:35 +00002 * Copyright (c) 2001, 2006 IBM Corporation and others.
lmandel3c550af2005-06-16 05:46:02 +00003 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
amywuecebb042007-04-10 20:07:35 +00007 *
lmandel3c550af2005-06-16 05:46:02 +00008 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11
12package org.eclipse.wst.xml.core.internal.validation;
13
lmandeladbf5dc2005-10-12 02:58:29 +000014import java.io.InputStream;
lmandel3c550af2005-06-16 05:46:02 +000015import java.io.Reader;
lmandeladbf5dc2005-10-12 02:58:29 +000016import java.net.URL;
lmandel3c550af2005-06-16 05:46:02 +000017import java.util.List;
amywufecd7a92006-05-10 07:22:58 +000018import com.ibm.icu.util.StringTokenizer;
lmandel3c550af2005-06-16 05:46:02 +000019import java.util.Vector;
lmandeladbf5dc2005-10-12 02:58:29 +000020
lmandel3c550af2005-06-16 05:46:02 +000021import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolver;
csalter2b696842005-07-09 04:25:15 +000022import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolverPlugin;
lmandel3c550af2005-06-16 05:46:02 +000023import org.xml.sax.Attributes;
24import org.xml.sax.InputSource;
25import org.xml.sax.SAXException;
26import org.xml.sax.SAXParseException;
27import org.xml.sax.XMLReader;
28import org.xml.sax.ext.LexicalHandler;
29
30/**
31 * A helper class for the XML validator.
32 *
33 * @author Craig Salter, IBM
34 * @author Lawrence Mandel, IBM
35 */
36public class ValidatorHelper
37{
lmandel3c550af2005-06-16 05:46:02 +000038 public List namespaceURIList = new Vector();
lmandel3c550af2005-06-16 05:46:02 +000039 public boolean isGrammarEncountered = false;
40 public boolean isDTDEncountered = false;
41 public boolean isNamespaceEncountered = false;
nitind95409d02005-11-10 05:32:16 +000042 public String schemaLocationString = ""; //$NON-NLS-1$
lmandel3c550af2005-06-16 05:46:02 +000043 public int numDTDElements = 0;
44
lmandel3c550af2005-06-16 05:46:02 +000045 /**
46 * Constructor.
47 */
48 public ValidatorHelper()
49 {
50 }
51
52 /**
53 * Create an XML Reader.
54 *
55 * @return An XML Reader if one can be created or null.
56 * @throws Exception
57 */
csalter59f3bd32005-11-12 06:55:35 +000058 protected XMLReader createXMLReader(String uri) throws Exception
lmandel3c550af2005-06-16 05:46:02 +000059 {
60 XMLReader reader = null;
lmandeledffe172005-11-03 00:00:30 +000061
62 reader = new org.apache.xerces.parsers.SAXParser();
nitind95409d02005-11-10 05:32:16 +000063 reader.setFeature("http://apache.org/xml/features/continue-after-fatal-error", false); //$NON-NLS-1$
64 reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); //$NON-NLS-1$
65 reader.setFeature("http://xml.org/sax/features/namespaces", false); //$NON-NLS-1$
66 reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); //$NON-NLS-1$
csalter59f3bd32005-11-12 06:55:35 +000067 reader.setContentHandler(new MyContentHandler(uri));
lmandeledffe172005-11-03 00:00:30 +000068 reader.setErrorHandler(new InternalErrorHandler());
lmandel3c550af2005-06-16 05:46:02 +000069
lmandeledffe172005-11-03 00:00:30 +000070 LexicalHandler lexicalHandler = new LexicalHandler()
71 {
72 public void startDTD (String name, String publicId, String systemId)
73 {
74 isGrammarEncountered = true;
75 isDTDEncountered = true;
76 }
lmandel3c550af2005-06-16 05:46:02 +000077
lmandeledffe172005-11-03 00:00:30 +000078 public void endDTD() throws SAXException
79 {
80 }
lmandel3c550af2005-06-16 05:46:02 +000081
lmandeledffe172005-11-03 00:00:30 +000082 public void startEntity(String name) throws SAXException
83 {
84 }
lmandel3c550af2005-06-16 05:46:02 +000085
lmandeledffe172005-11-03 00:00:30 +000086 public void endEntity(String name) throws SAXException
87 {
88 }
lmandel3c550af2005-06-16 05:46:02 +000089
lmandeledffe172005-11-03 00:00:30 +000090 public void startCDATA() throws SAXException
91 {
92 }
93
94 public void endCDATA() throws SAXException
95 {
96 }
lmandel3c550af2005-06-16 05:46:02 +000097
lmandeledffe172005-11-03 00:00:30 +000098 public void comment (char ch[], int start, int length) throws SAXException
99 {
100 }
101 };
nitind95409d02005-11-10 05:32:16 +0000102 reader.setProperty("http://xml.org/sax/properties/lexical-handler", lexicalHandler); //$NON-NLS-1$
lmandeledffe172005-11-03 00:00:30 +0000103
lmandel3c550af2005-06-16 05:46:02 +0000104 return reader;
105 }
106
107 /**
108 * An error handler to suppress error and warning information.
109 */
110 private class InternalErrorHandler implements org.xml.sax.ErrorHandler
111 {
lmandel4ff07b92006-04-18 05:12:19 +0000112 public InternalErrorHandler()
113 {
114 super();
115 }
116
lmandel3c550af2005-06-16 05:46:02 +0000117 public void error(SAXParseException exception) throws SAXException
118 {
119 }
120
121 public void fatalError(SAXParseException exception) throws SAXException
122 {
123 }
124
125 public void warning(SAXParseException exception) throws SAXException
126 {
127 }
128 }
129
130
131 /**
132 * Figures out the information needed for validation.
133 *
134 * @param uri The uri of the file to validate.
135 * @param uriResolver A helper to resolve locations.
136 */
137 public void computeValidationInformation(String uri, Reader characterStream, URIResolver uriResolver)
138 {
139 try
140 {
csalter59f3bd32005-11-12 06:55:35 +0000141 XMLReader reader = createXMLReader(uri);
lmandel3c550af2005-06-16 05:46:02 +0000142 InputSource inputSource = new InputSource(uri);
143 inputSource.setCharacterStream(characterStream);
144 reader.parse(inputSource);
lmandel3c550af2005-06-16 05:46:02 +0000145 }
146 catch (Exception e)
147 {
148 //System.out.println(e);
149 }
150 }
151
152
153
154 /**
155 * Handle the content while parsing the file.
156 */
157 class MyContentHandler extends org.xml.sax.helpers.DefaultHandler
158 {
159 /* (non-Javadoc)
160 * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
161 */
csalter2b696842005-07-09 04:25:15 +0000162 boolean isRootElement = true;
csalter59f3bd32005-11-12 06:55:35 +0000163 String baseURI;
164
165 MyContentHandler(String uri)
166 {
167 this.baseURI = uri;
168 }
csalter2b696842005-07-09 04:25:15 +0000169
lmandel3c550af2005-06-16 05:46:02 +0000170 public void error(SAXParseException e) throws SAXException
171 {
172 }
173 /* (non-Javadoc)
174 * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
175 */
176 public void fatalError(SAXParseException e) throws SAXException
177 {
178 }
179 /* (non-Javadoc)
180 * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
181 */
182 public void warning(SAXParseException e) throws SAXException
183 {
184 }
185 public String getPrefix(String name)
186 {
187 String prefix = null;
nitind95409d02005-11-10 05:32:16 +0000188 int index = name.indexOf(":"); //$NON-NLS-1$
lmandel3c550af2005-06-16 05:46:02 +0000189 if (index != -1)
190 {
191 prefix = name.substring(0, index);
192 }
193 return prefix;
194 }
195
196 public String getUnprefixedName(String name)
197 {
nitind95409d02005-11-10 05:32:16 +0000198 int index = name.indexOf(":"); //$NON-NLS-1$
lmandel3c550af2005-06-16 05:46:02 +0000199 if (index != -1)
200 {
201 name = name.substring(index + 1);
202 }
203 return name;
204 }
csalter2b696842005-07-09 04:25:15 +0000205
206 public String getPrefixedName(String prefix, String localName)
207 {
nitind95409d02005-11-10 05:32:16 +0000208 return prefix != null && prefix.length() > 0 ? prefix + ":" + localName : localName; //$NON-NLS-1$
csalter2b696842005-07-09 04:25:15 +0000209 }
lmandel3c550af2005-06-16 05:46:02 +0000210
211 public void startElement(String namespaceURI, String localName, String rawName, Attributes atts)
212 {
213 //String explicitLocation = null;
csalter2b696842005-07-09 04:25:15 +0000214 if (isRootElement)
215 {
216
217 isRootElement = false;
218 int nAtts = atts.getLength();
219 String schemaInstancePrefix = null;
220 for (int i =0; i < nAtts; i++)
221 {
222 String attributeName = atts.getQName(i);
nitind95409d02005-11-10 05:32:16 +0000223 if (attributeName.equals("xmlns") || attributeName.startsWith("xmlns:")) //$NON-NLS-1$ //$NON-NLS-2$
csalter2b696842005-07-09 04:25:15 +0000224 {
225 isNamespaceEncountered = true;
226 String value = atts.getValue(i);
nitind95409d02005-11-10 05:32:16 +0000227 if (value.startsWith("http://www.w3.org/") && value.endsWith("/XMLSchema-instance")) //$NON-NLS-1$ //$NON-NLS-2$
csalter2b696842005-07-09 04:25:15 +0000228 {
nitind95409d02005-11-10 05:32:16 +0000229 schemaInstancePrefix = attributeName.equals("xmlns") ? "" : getUnprefixedName(attributeName); //$NON-NLS-1$ //$NON-NLS-2$
csalter2b696842005-07-09 04:25:15 +0000230 }
231 }
232 }
233
234 String prefix = getPrefix(rawName);
nitind95409d02005-11-10 05:32:16 +0000235 String rootElementNamespaceDeclarationName = (prefix != null && prefix.length() > 0) ? "xmlns:" + prefix : "xmlns"; //$NON-NLS-1$ //$NON-NLS-2$
csalter2b696842005-07-09 04:25:15 +0000236 String rootElementNamespace = rootElementNamespaceDeclarationName != null ? atts.getValue(rootElementNamespaceDeclarationName) : null;
237
238 String location = null;
239
240 // first we use any 'xsi:schemaLocation' or 'xsi:noNamespaceSchemaLocation' attribute
241 // to determine a location
242 if (schemaInstancePrefix != null)
243 {
nitind95409d02005-11-10 05:32:16 +0000244 location = atts.getValue(getPrefixedName(schemaInstancePrefix, "noNamespaceSchemaLocation")); //$NON-NLS-1$
csalter2b696842005-07-09 04:25:15 +0000245 if (location == null)
csalter59f3bd32005-11-12 06:55:35 +0000246 {
nitind95409d02005-11-10 05:32:16 +0000247 String schemaLoc = atts.getValue(getPrefixedName(schemaInstancePrefix, "schemaLocation")); //$NON-NLS-1$
csalter59f3bd32005-11-12 06:55:35 +0000248 location = getSchemaLocationForNamespace(schemaLoc, rootElementNamespace);
249 }
csalter2b696842005-07-09 04:25:15 +0000250 }
lmandel85875042006-05-02 22:54:39 +0000251 if (rootElementNamespace == null)
csalter2b696842005-07-09 04:25:15 +0000252 {
lmandel85875042006-05-02 22:54:39 +0000253 rootElementNamespace = "";
254 }
255
256 location = URIResolverPlugin.createResolver().resolve(baseURI, rootElementNamespace, location);
257 location = URIResolverPlugin.createResolver().resolvePhysicalLocation(baseURI, rootElementNamespace, location);
csalter2b696842005-07-09 04:25:15 +0000258
259 if (location != null)
260 {
lmandeladbf5dc2005-10-12 02:58:29 +0000261 InputStream is = null;
262 try
263 {
264 URL url = new URL(location);
265 is = url.openStream();
266 isGrammarEncountered = true;
267 }
268 catch(Exception e)
269 {
270 // Do nothing.
271 }
272 finally
273 {
274 if(is != null)
275 {
276 try
277 {
278 is.close();
279 }
280 catch(Exception e)
281 {
282 // Do nothing.
283 }
284 }
285 }
lmandel3c550af2005-06-16 05:46:02 +0000286 }
287 }
288 }
289 /* (non-Javadoc)
290 * @see org.xml.sax.ext.DeclHandler#elementDecl(java.lang.String, java.lang.String)
291 */
292 public void elementDecl(String name, String model)
293 {
294 numDTDElements++;
295 }
csalter59f3bd32005-11-12 06:55:35 +0000296
297 // The xsiSchemaLocationValue is a list of namespace/location pairs that are separated by whitespace
298 // this method walks the list of pairs looking for the specified namespace and returns the associated
299 // location.
300 //
301 protected String getSchemaLocationForNamespace(String xsiSchemaLocationValue, String namespace)
302 {
303 String result = null;
304 if (xsiSchemaLocationValue != null && namespace != null)
305 {
306
307 StringTokenizer st = new StringTokenizer(xsiSchemaLocationValue);
308 while(st.hasMoreTokens())
309 {
310 if(st.nextToken().equals(namespace))
311 {
312 if(st.hasMoreTokens())
313 {
314 result = st.nextToken();
315 }
316 }
317 else
318 {
319 if(st.hasMoreTokens())
320 {
321 st.nextToken();
322 }
323 }
324 }
325 }
326 return result;
327 }
lmandel3c550af2005-06-16 05:46:02 +0000328 }
329
lmandel3c550af2005-06-16 05:46:02 +0000330
331 /**
332 * Replace all instances in the string of the old pattern with the new pattern.
333 *
334 * @param string The string to replace the patterns in.
335 * @param oldPattern The old pattern to replace.
336 * @param newPattern The pattern used for replacement.
337 * @return The modified string with all occurrances of oldPattern replaced by new Pattern.
338 */
339 protected static String replace(String string, String oldPattern, String newPattern)
340 {
341 int index = 0;
342 while (index != -1)
343 {
344 index = string.indexOf(oldPattern, index);
345 if (index != -1)
346 {
347 string = string.substring(0, index) + newPattern + string.substring(index + oldPattern.length());
348 index = index + oldPattern.length();
349 }
350 }
351 return string;
352 }
amywuecebb042007-04-10 20:07:35 +0000353}