Search code examples
javaxmlvalidationxsd

Validate XML against two XSD: Cant resolve the name 'Elem' to a(n) 'type definition' component


I have an XML file and two XSD files for it: xsd_1.xsd and xsd_2.xsd. xsd_1.xsd refers to the xsd_2.xsd but it seems that does not load when validation is performed.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
            xmlns="..." targetNamespace="..."
            elementFormDefault="qualified" attributeFormDefault="unqualified">

    <xsd:include schemaLocation = "http://.../xmlschema/xsd_2.xsd"/>

    ... 
</xsd:schema>

XML file has some simple structure. I use the following code to validate this xml:

Source[] schemes = new StreamSource[] {
        new StreamSource("C:/java-projects/xsl/src/test/resources/ex/xsd_1.xsd"),
        new StreamSource("C:/java-projects/xsl/src/test/resources/ex/xsd_2.xsd")
};

Source xml = new StreamSource(new File(XML_PATH));

SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(schemes);
Validator validator = schema.newValidator();
validator.validate(xml);

I can't validate xml using this code, the following exception is thrown:

org.xml.sax.SAXParseException; systemId: file:///C:/java-projects/xsl/src/test/resources/ex/xsd_1.xsd; lineNumber: 16; columnNumber: 49; src-resolve: Cannot resolve the name 'Elem' to a(n) 'type definition' component.

The Elem tag is defined in the xsd_2 file.xsd and it looks like this file is not loading.

But the following trick works. If I create a wrapper with these two xsd files, the validation will be successful:

URL firstXsd = XMLValidator.class.getResource(FIRST_XSD_PATH);
URL secondXsd = XMLValidator.class.getResource(SECOND_XSD_PATH);

SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
val wrapper =
        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n "
        + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\" "
        + "targetNamespace=\"...\">\n "
        + "<xs:include schemaLocation=\"" + firstXsd.getPath() + "\"/>\n "
        + "<xs:include schemaLocation=\"" + secondXsd.getPath() + "\"/>\n "
        +"</xs:schema>";

Schema schema = schemaFactory.newSchema(new StreamSource(new StringReader(wrapper)));
Validator validator = schema.newValidator();
validator.validate(new StreamSource(new File(XML_PATH)));

This solution is not suitable for a number of reasons. Why I can't validate xml using the first approach?

Perhaps something wrong with this instruction?

<xsd:include schemaLocation = "http://.../xmlschema/xsd_2.xsd"/>

This resource does not exist on the network, all xsd files are stored locally. But I can't make changes to them.


Solution

  • The issue you're facing is related to the way you are specifying the schema locations in the xsd_1.xsd file:

    <xsd:include schemaLocation="http://.../xmlschema/xsd_2.xsd"/>
    

    The schemaLocation attribute is expecting a relative or absolute path, but you've provided an HTTP URL. This is likely the reason why xsd_2.xsd is not loading properly during validation.

    To fix this issue, you should use a relative or absolute path instead of an HTTP URL. If both XSD files are in the same directory, you can use a relative path like this:

    <xsd:include schemaLocation="xsd_2.xsd"/>
    

    Make sure that the paths are correct and that the XSD files are accessible from the location where you are running the validation.

    Here's how your corrected xsd_1.xsd might look:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                xmlns="..." targetNamespace="..."
                elementFormDefault="qualified" attributeFormDefault="unqualified">
    
        <xsd:include schemaLocation="xsd_2.xsd"/>
    
        ... 
    </xsd:schema>