Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java XML validation does not work when schema comes from classpath

I am validating XML documents against a schema. Some more complex documents/schemas always fail when trying to validate them using this code:

    DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
    dbfac.setNamespaceAware(true);
    dbfac.setIgnoringElementContentWhitespace(true);
    DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
    Document doc = docBuilder.parse("sampleResponse.xml");

    SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    Source schemaSource = new StreamSource(getClass().getResourceAsStream("/" + "SampleResponse.xsd"));

    Schema schema = schemaFactory.newSchema(schemaSource);
    Validator validator = schema.newValidator();
    Source source = new DOMSource(doc);
    // Set a custom error handler that simple re-throws every exception
    validator.setErrorHandler(new ValidationErrorHandler());
    validator.validate(source);

The problem is this line:

    Source schemaSource = new StreamSource(getClass().getResourceAsStream("/" + "SampleResponse.xsd"));

If I read the schema as a file, it works:

    Source schemaSource = new StreamSource(new File("somepath/SampleResponse.xsd"));

Why doesn't validation work when I get the schema directly from classpath?

(Using Java 1.6 on Windows 7 64-bit)

Exception message when failing: Could not validate against schema SampleResponse.xsd. Nested exception: src-resolve: Cannot resolve the name 'oa:Attachments' to a(n) 'element declaration' component.

like image 573
Victor Lyuboslavsky Avatar asked Jun 12 '12 13:06

Victor Lyuboslavsky


1 Answers

When you pass a File to StreamSource, the InputStream is set to the contents of the file, but also the systemId is set to be the URL of the File. This allows relative URIs in your schema to be resolved. If your schema has any relative URLs, this is definitely your problem. To make those relative URLs resolvable when reading the schema from the classpath, you need to implement an EntityResolver. If you don't use relative URIs there might still be other more subtle impacts of the systemId being null. I would recommend using the constructor

StreamSource(InputStream inputStream, String systemId)

Try setting systemId to: null, the File containing the schema, some other file, a File that doesn't exist. That might give you a hint of what Validator is doing with the systemId.

like image 58
John Watts Avatar answered Sep 19 '22 18:09

John Watts