XML validation with XSD loaded as File vs InputStream

64 Views Asked by At

I'm experiencing different behavior in XML validation if the XSD is loaded as a File or resource.

If i load the XSD as File everything is fine and validation works well:

SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new ClassPathResource("my/perfect/path/myFile.xsd").getFile());
Validator validator = schema.newValidator();
validator.validate(sourceToValidate);

Instead since i decided to include xsd file into jar i load it as resource, but the behavior is different and i get into a SAXParseException when i construct the Schema and error is complaining about some issue in resolving a name in xsd file as a type definition. The xsd file is absolutely correct

SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("my/perfect/path/myFile.xsd");
Source schemaSource = new StreamSource(inputStream);
Schema schema = sf.newSchema(schemaSource); // here i get the SAXParseException
Validator validator = schema.newValidator();
validator.validate(sourceToValidate);

I really can't understand why load the xsd as ResourceAsStream causes a different behavior

I'm using JAXB for xml validation

1

There are 1 best solutions below

2
lance-java On

I'm guessing that your xsd references other xsd's and your validator does not know how to resolve the references.

You may need to provide a LSResourceResolver to the Validator

ClassLoader loader = getClass().getClassLoader();
LSResourceResolver resolver = new LSResourceResolver() {
   public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
      InputStream stream = loader.getResourceAsStream(systemId);
      if (stream == null) throw new RuntimeException("Could not find " + systemId);
      LSInput input = new DOMInputImpl();
      input.setPublicId(publicId);
      input.setSystemId(systemId);
      input.setBaseURI(baseURI);
      input.setByteStream(stream);             
      return input;
   }
};

String path = "my/perfect/path/myFile.xsd";
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setResourceResolver(resolver);
Source schemaSource = new StreamSource(loader.getResourceAsStream(path), path);
Schema schema = schemaFactory.newSchema(schemaSource);
Validator validator = schema.newValidator();
validator.setResourceResolver(resolver);

You will also want to set the systemId on the InputSource by calling the two args constructor of StreamSource.

String xsdPath = "my/perfect/path/myFile.xsd";
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(xsdPath);
Source schemaSource = new StreamSource(inputStream, xsdPath);

See StreamSource(InputStream, String)

This constructor allows the systemID to be set in addition to the input stream, which allows relative URIs to be processed.