I'm trying to add schema validation to the Servlet and JSP containers
by leveraging the javax.xml.validation package.
Both containers need to be able to validate a given deployment or tag
library descriptor file against its underlying schema.
A given descriptor file may adhere to one of the following schemas:
"web-jsptaglibrary_2_0.xsd", "web-jsptaglibrary_2_1.xsd",
"web-app_2_4.xsd", or "web-app_2_5.xsd".
I'm using
javax.xml.validation.SchemaFactory.newSchema(Source[] schemas)
and pass it the above schemas (see attached source).
I can construct "schema1" just fine, but when I use it to validate a
Servlet 2.4 based deployment descriptor, I get this error:
Document is invalid: no grammar found.
which makes we wonder if the "web-app_2_4.xsd" schema was parsed at all.
When I try to construct "schema2" from just "web-app_2_4.xsd", I get
this error:
Exception in thread "main" org.xml.sax.SAXParseException:
sch-props-correct.2: A schema cannot contain two global components
with the same name; this schema contains two occurrences of
'
http://java.sun.com/xml/ns/j2ee,descriptionGroup'.
at
com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:236)
at
com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:172)
at
com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:382)
at
com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaError(XSDHandler.java:2241)
at
com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.checkForDuplicateNames(XSDHandler.java:1918)
at
com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.buildGlobalNameRegistries(XSDHandler.java:983)
at
com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.parseSchema(XSDHandler.java:478)
at
com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadSchema(XMLSchemaLoader.java:556)
at
com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:523)
at
com.sun.org.apache.xerces.internal.jaxp.validation.xs.SchemaFactoryImpl.newSchema(SchemaFactoryImpl.java:206)
at javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:489)
at SchemaTester.main(SchemaTester.java:34)
"j2ee:descriptionGroup" is declared by both jsp_2_0.xsd and
j2ee_1_4.xsd, both of which are included by "web-app_2_4.xsd".
Does this make "web-app_2_4.xsd" invalid, or is there a way to avoid the
above error?
You can reproduce the error by compiling the attached source file and
running:
java -classpath {S1AS_HOME}/lib:. SchemaTester
(The -classpath argument is necessary for the program to be able to
retrieve the various schema resources, which are located under
{S1AS_HOME}/lib/schemas/.)
Thank you for any pointers you may have.
Jan
import java.io.InputStream;
import java.io.Reader;
import javax.xml.XMLConstants;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.ls.LSResourceResolver;
import org.w3c.dom.ls.LSInput;
public class SchemaTester {
public static void main(String[] args) throws Exception {
SchemaFactory schemaFactory = SchemaFactory.newInstance(
XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setResourceResolver(new MyLSResourceResolver());
Schema schema1 = schemaFactory.newSchema(new Source[] {
new StreamSource(
SchemaTester.class.getResourceAsStream(
"/schemas/web-jsptaglibrary_2_0.xsd")),
new StreamSource(
SchemaTester.class.getResourceAsStream(
"/schemas/web-jsptaglibrary_2_1.xsd")),
new StreamSource(
SchemaTester.class.getResourceAsStream(
"/schemas/web-app_2_4.xsd")),
new StreamSource(
SchemaTester.class.getResourceAsStream(
"/schemas/web-app_2_5.xsd"))
});
Schema schema2 = schemaFactory.newSchema(
new StreamSource(
SchemaTester.class.getResourceAsStream(
"/schemas/web-app_2_4.xsd")));
}
}
class MyLSResourceResolver implements LSResourceResolver {
private static final String SCHEMA_RESOURCE_PREFIX = "/schemas/";
public LSInput resolveResource(String type,
String namespaceURI,
String publicId,
String systemId,
String baseURI) {
String resourceName = systemId;
int index = systemId.lastIndexOf('/');
if (index != -1) {
resourceName = systemId.substring(index+1);
}
String resourcePath = SCHEMA_RESOURCE_PREFIX + resourceName;
InputStream is = MyLSResourceResolver.class.getResourceAsStream(
resourcePath);
MyLSInput ls = new MyLSInput();
ls.setByteStream(is);
return ls;
}
}
class MyLSInput implements LSInput {
private Reader charStream;
private InputStream byteStream;
private String stringData;
private String systemId;
private String publicId;
private String baseURI;
private String encoding;
private boolean certifiedText;
public Reader getCharacterStream() {
return charStream;
}
public void setCharacterStream(Reader charStream) {
this.charStream = charStream;
}
public InputStream getByteStream() {
return byteStream;
}
public void setByteStream(InputStream byteStream) {
this.byteStream = byteStream;
}
public String getStringData() {
return stringData;
}
public void setStringData(String stringData) {
this.stringData = stringData;
}
public String getSystemId() {
return systemId;
}
public void setSystemId(String systemId) {
this.systemId = systemId;
}
public String getPublicId() {
return publicId;
}
public void setPublicId(String publicId) {
this.publicId = publicId;
}
public String getBaseURI() {
return baseURI;
}
public void setBaseURI(String baseURI) {
this.baseURI = baseURI;
}
public String getEncoding() {
return encoding;
}
public void setEncoding(String encoding) {
this.encoding = encoding;
}
public boolean getCertifiedText() {
return certifiedText;
}
public void setCertifiedText(boolean certifiedText) {
this.certifiedText = certifiedText;
}
}