Search code examples
javaxmlxsdmoxyxsd-validation

How do I validate an XML with a schema file that imports another schema file?


I want to validate XML files against this schema (that is inside the zip); it imports two other XSD files.

   <import namespace="http://www.w3.org/2000/09/xmldsig#" 
       schemaLocation="xmldsig-core-schema.xsd"/>
   <import namespace="http://www.w3.org/2001/04/xmlenc#" 
       schemaLocation="xenc-schema.xsd"/>

The 2 files are also available here:

On validation, I get this error:

Src-resolve: Cannot Resolve The Name 'xenc:EncryptedData' To A(n) 'element Declaration' Component.

My validation/unmarshalling code looks like this (using moxy as a JAXB provider):

jaxbContext = JAXBContext.newInstance(type.getRequestType().getPackage().getName());
Unmarshaller um = jaxbContext.createUnmarshaller();

SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new StreamSource(this.getClass().getResourceAsStream("/xsd/" + type.getXsdName())));
um.setSchema(schema);

root = um.unmarshal(new StreamSource(new ByteArrayInputStream(xmlData)), type.getRequestType());

Before you ask what does the type do: I wrote code that could import all types of invoices from http://www.forum-datenaustausch.ch/. But versions 4.3 and above use the two additional schema files. How can validate the XML files?


Solution

  • Have a look at the accepted answer for this post. Based on the little I can see in your post, and from what I can remember, the problem with the way you're loading the XSD has to do with the fact that doing it your way, the factory doesn't get a base uri, hence it can't apply its smarts to resolve references to the other two XSDs. I have to assume that your other two XSDs are also packed as resources in the same jar, in the same directory.

    I have to admit that I am intrigued by the error message, which seems to imply the schema it loaded is valid, so it might be an XML issue; if the above doesn't help you, then you should consider posting the offending XML as well...

    UPDATE: As per my comments, it is working as described. See code snippet below:

    SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
    Schema compiledSchema = schemaFactory.newSchema(new SOTests().getClass()
        .getClassLoader().getResource("generalInvoiceRequest_430.xsd"));
    Validator validator = compiledSchema.newValidator();
    try {
        validator.validate(new StreamSource("D:\\...\\dentist_ersred_TG_430.xml"));
        System.out.println("Valid.");
    }
    catch (SAXException ex) {
        System.out.print("Not valid because..." + ex.getMessage());
    }  
    

    You don't need to load more than the first XSD, and you shouldn't, since all the imports provide hints to the schema location.

    enter image description here

    The XSD files are all in the same directory in the generated jar, and they must be, since the relative URIs used for imports indicate same parent.

    enter image description here

    The program output with one of the files downloaded from here:

    Valid.
    

    And after introducing invalid content:

    Not valid because...cvc-complex-type.2.4.a: Invalid content was found starting with element 'wrong'. One of '{"http://www.forum-datenaustausch.ch/invoice":processing}' is expected.
    

    My recommendations to who reads this:

    • use getResource() to get an URL; as I've said above, a StreamResource doesn't have a base URI, hence relative references as per your xsd:import schemaLocation attribute cannot be de-referenced.
    • Let the schema/factory do the loading for you, when they're explicitly provided.
    • make sure that when provided, relative references match the folder structure in your jar file.