blob: 96c578cf68026cffea40db4c3a56d62472b0e614 [file] [log] [blame]
lmandel3c550af2005-06-16 05:46:02 +00001/*******************************************************************************
kchong5f556c52008-03-26 19:37:20 +00002 * Copyright (c) 2001, 2008 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;
vbaciu185864d2007-04-11 20:20:32 +000023import org.eclipse.wst.common.uriresolver.internal.util.URIHelper;
lmandel3c550af2005-06-16 05:46:02 +000024import org.xml.sax.Attributes;
25import org.xml.sax.InputSource;
26import org.xml.sax.SAXException;
27import org.xml.sax.SAXParseException;
28import org.xml.sax.XMLReader;
29import org.xml.sax.ext.LexicalHandler;
30
31/**
32 * A helper class for the XML validator.
33 *
34 * @author Craig Salter, IBM
35 * @author Lawrence Mandel, IBM
36 */
37public class ValidatorHelper
38{
lmandel3c550af2005-06-16 05:46:02 +000039 public List namespaceURIList = new Vector();
lmandel3c550af2005-06-16 05:46:02 +000040 public boolean isGrammarEncountered = false;
41 public boolean isDTDEncountered = false;
42 public boolean isNamespaceEncountered = false;
nitind95409d02005-11-10 05:32:16 +000043 public String schemaLocationString = ""; //$NON-NLS-1$
lmandel3c550af2005-06-16 05:46:02 +000044 public int numDTDElements = 0;
45
lmandel3c550af2005-06-16 05:46:02 +000046 /**
47 * Constructor.
48 */
49 public ValidatorHelper()
50 {
51 }
52
53 /**
54 * Create an XML Reader.
55 *
56 * @return An XML Reader if one can be created or null.
57 * @throws Exception
58 */
csalter59f3bd32005-11-12 06:55:35 +000059 protected XMLReader createXMLReader(String uri) throws Exception
lmandel3c550af2005-06-16 05:46:02 +000060 {
61 XMLReader reader = null;
lmandeledffe172005-11-03 00:00:30 +000062
63 reader = new org.apache.xerces.parsers.SAXParser();
nitind95409d02005-11-10 05:32:16 +000064 reader.setFeature("http://apache.org/xml/features/continue-after-fatal-error", false); //$NON-NLS-1$
65 reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); //$NON-NLS-1$
66 reader.setFeature("http://xml.org/sax/features/namespaces", false); //$NON-NLS-1$
67 reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); //$NON-NLS-1$
csalter59f3bd32005-11-12 06:55:35 +000068 reader.setContentHandler(new MyContentHandler(uri));
lmandeledffe172005-11-03 00:00:30 +000069 reader.setErrorHandler(new InternalErrorHandler());
lmandel3c550af2005-06-16 05:46:02 +000070
lmandeledffe172005-11-03 00:00:30 +000071 LexicalHandler lexicalHandler = new LexicalHandler()
72 {
73 public void startDTD (String name, String publicId, String systemId)
74 {
75 isGrammarEncountered = true;
76 isDTDEncountered = true;
77 }
lmandel3c550af2005-06-16 05:46:02 +000078
lmandeledffe172005-11-03 00:00:30 +000079 public void endDTD() throws SAXException
80 {
81 }
lmandel3c550af2005-06-16 05:46:02 +000082
lmandeledffe172005-11-03 00:00:30 +000083 public void startEntity(String name) throws SAXException
84 {
85 }
lmandel3c550af2005-06-16 05:46:02 +000086
lmandeledffe172005-11-03 00:00:30 +000087 public void endEntity(String name) throws SAXException
88 {
89 }
lmandel3c550af2005-06-16 05:46:02 +000090
lmandeledffe172005-11-03 00:00:30 +000091 public void startCDATA() throws SAXException
92 {
93 }
94
95 public void endCDATA() throws SAXException
96 {
97 }
lmandel3c550af2005-06-16 05:46:02 +000098
lmandeledffe172005-11-03 00:00:30 +000099 public void comment (char ch[], int start, int length) throws SAXException
100 {
101 }
102 };
nitind95409d02005-11-10 05:32:16 +0000103 reader.setProperty("http://xml.org/sax/properties/lexical-handler", lexicalHandler); //$NON-NLS-1$
lmandeledffe172005-11-03 00:00:30 +0000104
lmandel3c550af2005-06-16 05:46:02 +0000105 return reader;
106 }
107
108 /**
109 * An error handler to suppress error and warning information.
110 */
111 private class InternalErrorHandler implements org.xml.sax.ErrorHandler
112 {
lmandel4ff07b92006-04-18 05:12:19 +0000113 public InternalErrorHandler()
114 {
115 super();
116 }
117
lmandel3c550af2005-06-16 05:46:02 +0000118 public void error(SAXParseException exception) throws SAXException
119 {
120 }
121
122 public void fatalError(SAXParseException exception) throws SAXException
123 {
124 }
125
126 public void warning(SAXParseException exception) throws SAXException
127 {
128 }
129 }
130
131
132 /**
133 * Figures out the information needed for validation.
134 *
135 * @param uri The uri of the file to validate.
136 * @param uriResolver A helper to resolve locations.
137 */
138 public void computeValidationInformation(String uri, Reader characterStream, URIResolver uriResolver)
139 {
140 try
141 {
csalter59f3bd32005-11-12 06:55:35 +0000142 XMLReader reader = createXMLReader(uri);
lmandel3c550af2005-06-16 05:46:02 +0000143 InputSource inputSource = new InputSource(uri);
144 inputSource.setCharacterStream(characterStream);
145 reader.parse(inputSource);
lmandel3c550af2005-06-16 05:46:02 +0000146 }
147 catch (Exception e)
148 {
149 //System.out.println(e);
150 }
151 }
152
153
154
155 /**
156 * Handle the content while parsing the file.
157 */
158 class MyContentHandler extends org.xml.sax.helpers.DefaultHandler
159 {
160 /* (non-Javadoc)
161 * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
162 */
csalter2b696842005-07-09 04:25:15 +0000163 boolean isRootElement = true;
csalter59f3bd32005-11-12 06:55:35 +0000164 String baseURI;
165
166 MyContentHandler(String uri)
167 {
168 this.baseURI = uri;
169 }
csalter2b696842005-07-09 04:25:15 +0000170
lmandel3c550af2005-06-16 05:46:02 +0000171 public void error(SAXParseException e) throws SAXException
172 {
173 }
174 /* (non-Javadoc)
175 * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
176 */
177 public void fatalError(SAXParseException e) throws SAXException
178 {
179 }
180 /* (non-Javadoc)
181 * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
182 */
183 public void warning(SAXParseException e) throws SAXException
184 {
185 }
186 public String getPrefix(String name)
187 {
188 String prefix = null;
nitind95409d02005-11-10 05:32:16 +0000189 int index = name.indexOf(":"); //$NON-NLS-1$
lmandel3c550af2005-06-16 05:46:02 +0000190 if (index != -1)
191 {
192 prefix = name.substring(0, index);
193 }
194 return prefix;
195 }
196
197 public String getUnprefixedName(String name)
198 {
nitind95409d02005-11-10 05:32:16 +0000199 int index = name.indexOf(":"); //$NON-NLS-1$
lmandel3c550af2005-06-16 05:46:02 +0000200 if (index != -1)
201 {
202 name = name.substring(index + 1);
203 }
204 return name;
205 }
csalter2b696842005-07-09 04:25:15 +0000206
207 public String getPrefixedName(String prefix, String localName)
208 {
nitind95409d02005-11-10 05:32:16 +0000209 return prefix != null && prefix.length() > 0 ? prefix + ":" + localName : localName; //$NON-NLS-1$
csalter2b696842005-07-09 04:25:15 +0000210 }
lmandel3c550af2005-06-16 05:46:02 +0000211
212 public void startElement(String namespaceURI, String localName, String rawName, Attributes atts)
213 {
214 //String explicitLocation = null;
csalter2b696842005-07-09 04:25:15 +0000215 if (isRootElement)
216 {
217
218 isRootElement = false;
219 int nAtts = atts.getLength();
220 String schemaInstancePrefix = null;
221 for (int i =0; i < nAtts; i++)
222 {
223 String attributeName = atts.getQName(i);
nitind95409d02005-11-10 05:32:16 +0000224 if (attributeName.equals("xmlns") || attributeName.startsWith("xmlns:")) //$NON-NLS-1$ //$NON-NLS-2$
csalter2b696842005-07-09 04:25:15 +0000225 {
226 isNamespaceEncountered = true;
227 String value = atts.getValue(i);
nitind95409d02005-11-10 05:32:16 +0000228 if (value.startsWith("http://www.w3.org/") && value.endsWith("/XMLSchema-instance")) //$NON-NLS-1$ //$NON-NLS-2$
csalter2b696842005-07-09 04:25:15 +0000229 {
nitind95409d02005-11-10 05:32:16 +0000230 schemaInstancePrefix = attributeName.equals("xmlns") ? "" : getUnprefixedName(attributeName); //$NON-NLS-1$ //$NON-NLS-2$
csalter2b696842005-07-09 04:25:15 +0000231 }
232 }
233 }
234
235 String prefix = getPrefix(rawName);
nitind95409d02005-11-10 05:32:16 +0000236 String rootElementNamespaceDeclarationName = (prefix != null && prefix.length() > 0) ? "xmlns:" + prefix : "xmlns"; //$NON-NLS-1$ //$NON-NLS-2$
csalter2b696842005-07-09 04:25:15 +0000237 String rootElementNamespace = rootElementNamespaceDeclarationName != null ? atts.getValue(rootElementNamespaceDeclarationName) : null;
238
239 String location = null;
240
241 // first we use any 'xsi:schemaLocation' or 'xsi:noNamespaceSchemaLocation' attribute
242 // to determine a location
243 if (schemaInstancePrefix != null)
244 {
nitind95409d02005-11-10 05:32:16 +0000245 location = atts.getValue(getPrefixedName(schemaInstancePrefix, "noNamespaceSchemaLocation")); //$NON-NLS-1$
csalter2b696842005-07-09 04:25:15 +0000246 if (location == null)
csalter59f3bd32005-11-12 06:55:35 +0000247 {
nitind95409d02005-11-10 05:32:16 +0000248 String schemaLoc = atts.getValue(getPrefixedName(schemaInstancePrefix, "schemaLocation")); //$NON-NLS-1$
csalter59f3bd32005-11-12 06:55:35 +0000249 location = getSchemaLocationForNamespace(schemaLoc, rootElementNamespace);
250 }
csalter2b696842005-07-09 04:25:15 +0000251 }
lmandel85875042006-05-02 22:54:39 +0000252 if (rootElementNamespace == null)
csalter2b696842005-07-09 04:25:15 +0000253 {
lmandel85875042006-05-02 22:54:39 +0000254 rootElementNamespace = "";
255 }
256
257 location = URIResolverPlugin.createResolver().resolve(baseURI, rootElementNamespace, location);
258 location = URIResolverPlugin.createResolver().resolvePhysicalLocation(baseURI, rootElementNamespace, location);
vbaciu185864d2007-04-11 20:20:32 +0000259 location = URIHelper.addImpliedFileProtocol(location);
csalter2b696842005-07-09 04:25:15 +0000260
kchong5f556c52008-03-26 19:37:20 +0000261 schemaLocationString = location;
262
csalter2b696842005-07-09 04:25:15 +0000263 if (location != null)
264 {
lmandeladbf5dc2005-10-12 02:58:29 +0000265 InputStream is = null;
266 try
267 {
268 URL url = new URL(location);
269 is = url.openStream();
270 isGrammarEncountered = true;
271 }
272 catch(Exception e)
273 {
274 // Do nothing.
275 }
276 finally
277 {
278 if(is != null)
279 {
280 try
281 {
282 is.close();
283 }
284 catch(Exception e)
285 {
286 // Do nothing.
287 }
288 }
289 }
lmandel3c550af2005-06-16 05:46:02 +0000290 }
291 }
292 }
293 /* (non-Javadoc)
294 * @see org.xml.sax.ext.DeclHandler#elementDecl(java.lang.String, java.lang.String)
295 */
296 public void elementDecl(String name, String model)
297 {
298 numDTDElements++;
299 }
csalter59f3bd32005-11-12 06:55:35 +0000300
301 // The xsiSchemaLocationValue is a list of namespace/location pairs that are separated by whitespace
302 // this method walks the list of pairs looking for the specified namespace and returns the associated
303 // location.
304 //
305 protected String getSchemaLocationForNamespace(String xsiSchemaLocationValue, String namespace)
306 {
307 String result = null;
308 if (xsiSchemaLocationValue != null && namespace != null)
309 {
310
311 StringTokenizer st = new StringTokenizer(xsiSchemaLocationValue);
312 while(st.hasMoreTokens())
313 {
314 if(st.nextToken().equals(namespace))
315 {
316 if(st.hasMoreTokens())
317 {
318 result = st.nextToken();
319 }
320 }
321 else
322 {
323 if(st.hasMoreTokens())
324 {
325 st.nextToken();
326 }
327 }
328 }
329 }
330 return result;
331 }
lmandel3c550af2005-06-16 05:46:02 +0000332 }
333
lmandel3c550af2005-06-16 05:46:02 +0000334
335 /**
336 * Replace all instances in the string of the old pattern with the new pattern.
337 *
338 * @param string The string to replace the patterns in.
339 * @param oldPattern The old pattern to replace.
340 * @param newPattern The pattern used for replacement.
341 * @return The modified string with all occurrances of oldPattern replaced by new Pattern.
342 */
343 protected static String replace(String string, String oldPattern, String newPattern)
344 {
345 int index = 0;
346 while (index != -1)
347 {
348 index = string.indexOf(oldPattern, index);
349 if (index != -1)
350 {
351 string = string.substring(0, index) + newPattern + string.substring(index + oldPattern.length());
352 index = index + oldPattern.length();
353 }
354 }
355 return string;
356 }
amywuecebb042007-04-10 20:07:35 +0000357}