Question

I am using the following code:

    Unmarshaller unmarshaller = inputXmlContext.createUnmarshaller();
    SchemaFactory sf = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
    URL urlSchema = ProbeOutputTranslator.class.getResource("/a.xsd");
    Schema schema = sf.newSchema(new File(urlSchema.toURI()));

To validate an xml against a.xsd. The problem is that a.xsd defines an abstract element and the containing element for it:

<xs:complexType name="abstract_operation" abstract="true"/>

<xs:element name="operation" type="ac:abstract_operation"/>

<xs:complexType name="so_operations">
    <xs:sequence>
        <xs:element ref="ac:operation" minOccurs = "0" maxOccurs="unbounded"/> 
    </xs:sequence>
</xs:complexType>

The concrete types are defined in b.xsd. In the xml file, the default namespace is a.xsd, b.xsd's namespace is bound to prefix ops and it looks like this:

<so_operations>
    <ops:a_concrete_operation>
                 ....
    </ops:a_concrete_operation>
</so_operations>

This setup of course causes validation error when the above mentioned code is used. How do I achieve that also b.xsd schema is taken in consideration when being validated?

The schemas are located only in program's resources (therefore schema location cannot be defined in xml file).

Was it helpful?

Solution

You can combine the multiple schemas into a single schema programmatically and then validate against the combined schema.

SchemaFactory.newSchema() has a variant that takes an array of source documents, and combines them into a single Schema instance. However, this method is documented to behave as if creating a new schema document with import directives for each of the source documents. As a result, you can't combine source files with the same target namespace, and you must order the source documents so that definitions in one namespace are available when requested from another (I haven't found anything in the docs to justify this).

Provided that your schema documents are accessible via URL or filesystem, the best solution is to create a single top-level schema document, and use explicit import and include directives to reference your definitions.

Below code may help in getting starting:

URL xsdUrlA = this.getClass().getResource("a.xsd");
URL xsdUrlB = this.getClass().getResource("b.xsd");

SchemaFactory schemaFactory = schemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
//---
String W3C_XSD_TOP_ELEMENT =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\">\n"
+ "<xs:include schemaLocation=\"" +xsdUrlB.getPath() +"\"/>\n"
+ "<xs:include schemaLocation=\"" +xsdUrlA.getPath() +"\"/>\n"
+"</xs:schema>";
Schema schema = schemaFactory.newSchema(new StreamSource(new StringReader(W3C_XSD_TOP_ELEMENT), "xsdTop"));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top