Home > Blockchain >  cvc-elt.1.a: Cannot find the declaration of element 'core:configuration'
cvc-elt.1.a: Cannot find the declaration of element 'core:configuration'

Time:10-31

Abstract

In the project I am currently working on, I have multiple modules, each defining an XSD file. When loading a configuration I plan to locate these XSD files programmatically and then validate the configuration using SchemaFactory.newSchema(Source[]), for example

public void validate(Document document, InputStream... schemas) throws Exception {
    Source[] sources = new Source[schemas.length];
    for (int i = 0; i < schemas.length; i  ) {
        sources[i] = new StreamSource(schemas[i]);
    }
    SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    Schema schema = factory.newSchema(sources);
    schema.newValidator().validate(new DOMSource(document.getDocumentElement()));
}

Up until now I followed this Stack Overflow post, but in order to use the aforementioned method, I think I need to build the references using different namespaces.

The resulting schema contains components from the specified sources. The same result would be achieved if all these sources were imported, using appropriate values for schemaLocation and namespace, into a single schema document with a different targetNamespace and no components of its own, if the import elements were given in the same order as the sources.

Test

With core.xsd I define the static structure of the configuration.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema 
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:core="http://web.com/core"
        targetNamespace="http://web.com/core">
    <xsd:element name="configuration" type="core:configuration" />
    <xsd:complexType name="configuration">
        <xsd:sequence>
            <!-- other elements -->
            <xsd:element maxOccurs="unbounded" name="agent" type="core:agent" />
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="agent">
        <xsd:sequence>
            <!-- other elements -->
            <xsd:element ref="core:agentImpl" />
        </xsd:sequence>
        <!--  attributes -->
    </xsd:complexType>
    <xsd:element name="agentImpl" type="core:agentImpl" />
    <xsd:complexType name="agentImpl" abstract="true" />
</xsd:schema>

With ext.xsd I add implementations for the child element under agent. In this example, I add two agents using one XSD file, but later on, such agent definitions should be separated into several ext-*.xsd files.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:core="http://web.com/core"
        xmlns:ext="http://web.com/ext"
        targetNamespace="http://web.com/ext">
    <xsd:import namespace="http://web.com/core" schemaLocation="core.xsd" />
    <xsd:element name="file-mover" type="ext:file-mover" substitutionGroup="core:agentImpl" />
    <xsd:complexType name="file-mover">
        <xsd:complexContent>
            <xsd:extension base="core:agentImpl">
                <!-- implementation-specific stuff -->
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>
    <xsd:element name="junction" type="ext:junction" substitutionGroup="core:agentImpl" />
    <xsd:complexType name="junction">
        <xsd:complexContent>
            <xsd:extension base="core:agentImpl">
                <!-- implementation-specific stuff -->
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>
</xsd:schema>

However, when testing this setup with

@Test
void singleExtension() throws Exception {
    try (InputStream docIn = getClass().getResourceAsStream("configuration.xml");
         InputStream coreIn = getClass().getResourceAsStream("core.xsd");
         InputStream extIn = getClass().getResourceAsStream("ext.xsd")) {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(new StreamSource(docIn));
        validate(document, coreIn, extIn);
    }
}

and configuration.xml

<?xml version="1.0" encoding="UTF-8"?>
<core:configuration xmlns:core="http://web.com/core" xmlns:ext="http://web.com/ext">
    <agent>
        <ext:file-mover />
    </agent>
    <agent>
        <ext:junction />
    </agent>
</core:configuration>

I get

org.xml.sax.SAXParseException; cvc-elt.1.a: Cannot find the declaration of element 'core:configuration'.
    at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
    at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:135)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:396)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:284)
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:2132)
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:829)
    at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.DOMValidatorHelper.beginNode(DOMValidatorHelper.java:276)
    at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.DOMValidatorHelper.validate(DOMValidatorHelper.java:243)
    at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.DOMValidatorHelper.validate(DOMValidatorHelper.java:189)
    at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorImpl.validate(ValidatorImpl.java:108)
    at java.xml/javax.xml.validation.Validator.validate(Validator.java:124)
    at com.spell.moreen.core.xsd.so.StackOverflowTest.validate(StackOverflowTest.java:27)
    at com.spell.moreen.core.xsd.so.StackOverflowTest.singleExtension(StackOverflowTest.java:38)
    ... (only jupiter stuff from here on)

Conclusion

The posts I found on Stack Overflow regarding this specific exception all resolved to some namespace declaration being wrong plus one instance where the root element was not declared but only its type.

If I add xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" and xsi:schemaLocation="http://web.com/core core.xsd http://web.com/ext ext.xsd" to configuration.xml, eclipse can validate it just fine, so I assume the namespaces to be correct.

The root element is present with <xsd:element name="configuration" type="core:configuration" /> in core.xsd, which is always bound via xmlns:core="...", so I can't see anything wrong there, too.

What am I overlooking or understanding wrong?

CodePudding user response:

In order to validate an XML using namespaces, that XML must be parsed with namespaces in mind. Here, this means that DocumentBuilderFactory must be set to be aware of namespaces.

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // default is 'false'

Otherwise I guess the parser simply ignores this information, which in turn makes them unavailable for the schema validator.

  • Related