I'am using JIBX in order to map my XML data to Java objects. This perfectly works when the XML is containing only one target namespace. Unfortunately, the requirements have changed and now I get XML data with two different namespaces inside.
Example:
<a:foo>
<b:bar>Simple Example</b:bar>
</a:foo>
My question is, how to write a xsd that yields two different target namespaces?
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="namespace_of_a"
xmlns:a="namespace_of_a"
xmlns:b="namespace_of_b"
elementFormDefault="qualified">
<xs:element name="foo">
<xs:complexType>
<xs:sequence>
<!-- this won't work, because b is part of a different namespace -->
<xs:attribute type="xs:string" use="required" name="bar"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
I already tried:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="namespace_of_a"
xmlns:a="namespace_of_a"
xmlns:b="namespace_of_b"
elementFormDefault="qualified">
<xs:element name="foo">
<xs:complexType>
<xs:sequence>
<!-- this won't work, because jibx is reporting that targetNamespace is an unknown attribute -->
<xs:attribute targetNamespace="namespace_of_b" type="xs:string" use="required" name="bar"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Please help. I'm not sure whether this is possible in general or not? Thanks in advance!
Yes, it's possible. It's one of the core scenarios XSD was designed to handle.
(1) Write separate schema documents for each namespace involved, with that namespace given as the targetNamespace
of the xs:schema
element.
If your a:foo
element can accept only a b:bar
element as a child, then in the schema document for a
you will want to import namespace b
, so that the content model for a:foo
can refer to element b:bar
. For example, modify your sample schema document to include:
<xs:import namespace="namespace_of_b"/>
(Note: some people would add a schemaLocation
hint here; I wouldn't.)
Then change the declaration of a:foo
to read:
<xs:element name="foo">
<xs:complexType>
<xs:sequence>
<xs:element ref="b:bar"/>
</xs:sequence>
</xs:complexType>
</xs:element>
If a:foo
can accept anything, then use an xs:any
wildcard in its content model, and you don't need to import namespace b
(because you're not referring to anything in it).
In the schema document for namespace b
define element bar
in the normal way (or attribute bar
-- I think you must have changed your mind on how to present the example).
(2) Write a simple top-level 'driver' schema document that imports the two namespace-specific schema documents you prepared in step 1. It's on the xs:import
statements here that I'd provide the schema location information.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import namespace="namespace_of_a" schemaLocation="a.xsd"/>
<xs:import namespace="namespace_of_b" schemaLocation="b.xsd"/>
</xs:schema>
Segregating information about physical location of schema documents into a single driver file complicates matters a bit in the short run, by requiring yet another schema document. But it avoids a number of nasty problems that arise when you want to change things just a little bit, later on.