I am trying to validate a XML instance that depends on another instance (from a different namespace), and it has a keyref to a key in that namespace. When I try to validate the instance, it produces an error that says the key is out of scope.
These are my XSDs:
test1.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="test1" xmlns="test1">
<xs:complexType name="Host">
<xs:attribute name="id" type="xs:string"/>
</xs:complexType>
<xs:element name="root">
<xs:complexType>
<xs:all>
<xs:element name="hosts">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="host" type="Host"
/>
</xs:sequence>
</xs:complexType>
<xs:key name="Host-PK">
<xs:selector xpath="host"/>
<xs:field xpath="@id"/>
</xs:key>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
test2.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="test2" xmlns="test2" xmlns:t1="test1">
<xs:import namespace="test1" schemaLocation="test1.xsd"/>
<xs:element name="root">
<xs:complexType>
<xs:all>
<xs:element name="server">
<xs:complexType>
<xs:attribute name="host" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
<xs:keyref name="Host-FK" refer="t1:Host-PK">
<xs:selector xpath="server"/>
<xs:field xpath="@host"/>
</xs:keyref>
</xs:element>
</xs:schema>
And my instances:
test1.xml
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="test1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="test1 test1.xsd">
<hosts>
<host id="ABC"/>
<host id="DEF"/>
</hosts>
</root>
test2.xml
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:t1="test1" xmlns="test2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="test2 test2.xsd">
<server host="ABC"/>
</root>
The server host attribute is a key reference to the host ids.
During schema validation the test2.xml file raised the error below:
Error: [Xerces] Identity Constraint error: the keyref identity constraint "Host-FK" refers to a key or unique that is out of scope.
How can I fix that?
And how can I reference test1.xml instance from test2.xml?
I'm assuming you can change both XSDs, and that you are using XSD 1.0.
In the first XSD, you will need to qualify your XPath elements, since unprefixed elements belong to no namespace. As is your key will not work. You can verify this adding a duplicate ID to
test1:It still validates, when it shouldn't.
To fix that, add a second
test1namespace declaration with a prefix:Now you can qualify your XPath expression:
And the validation for the duplicate ID will fail, as expected.
Now your second XSD won't be able to find any
Host-PK. Itsrootelement is a completely different one. It just shares the same name with therootoftest1. There's no way it could be in scope. If you want to share the same key in both schemas one thing you could do is to declare therootintest2as an extension of therootintest1. But that will require some changes intest1.xsdin order to allowtest2to refer to elements and types intest1.xsd.To allow other schemas to extend the type of the
rootelement, make it top-level. Also, make thehostselement top-level, since we will need to refer to it in order to define thekeyref. You can also use it to validate a file which hashostsas a root element (this will be useful, as we'll see ahead).We won't be able to extend
xs:all, but in your case you can safely replace it with axs:sequence. This is the final test1.xsd after refactoring:I also added
minOccurs="0"tohostsso it will be possible to define arootcontaining only a server (but this is temporary - we will make it required again before we finish)Now we can refer to the
hostselement and to theRoottype intest2.xsd. We can start by extending therootelement's base type, to allow for theserverelement:It's also a sequence.
The
rootelement should be declared as:Now the
rootelement intest2is an extension of therootelement intest1, and thehostelement will be in context.Since we have to use XPath to select the server element, it's necessary to declare a prefix for the namespace of
test2so we can use it in the XPath expression:Now you can define a local key that refers to
hosts/hostand use it for thehostattribute inserver:And this is your final test2.xsd after refactoring:
So now you try to validate
test2.xmland ... it fails, but no longer with the "out of scope" error. It fails because it didn't find any key with theABCvalue. That means it's validating the key all right, but it can't access thehostelements. You need to have them in your XML instance.It will work if you simply cut and paste the
hostselement from thetest1.xmland set a default namespace for them:You can try it out. It won't validate unless
hostisABCorDEF.You might also want to keep the
hostssubtree in a separate file, and import it into both your XML instances. The native way to do that is declaring a DTD entity. First place yourhostsin a file (test3.xml):Now include it into
test1.xmlandtest2.xmlusing an<!ENTITY>:test1.xml
test2.xml
Now you can place the
minOccurs="0"back in the declaration forhostsintest1.xsd, to guarantee that it will always be present.