0

I'm struggling with the problem of the correct use of xsd:key Element in my xml schema to preserve uniqueness of records. I've seen many working examples, yet when I try to utilize them to fit my needs I can't achieve desired results.

Here's a simple example, written by me, which doesn't work as expected:

KeyTest.xml

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<KeyTest xmlns="keytest" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="keytest keytest.xsd">
    <ManyThings>
        <OneThing>
            <Id>a</Id>
        </OneThing>
        <OneThing>
            <Id>b</Id>
        </OneThing>
        <OneThing>
            <Id>b</Id>
        </OneThing>
    </ManyThings>
</KeyTest>

KeyTest.xsd

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           targetNamespace="keytest"
           xmlns="keytest" 
           elementFormDefault="qualified">

    <xs:element name="KeyTest">
        <xs:complexType>
            <xs:all>
                <xs:element name="ManyThings" type="ManyThingsType">
                    <xs:key name="PK_ManyThings">
                        <xs:selector xpath="OneThing"/>
                        <xs:field xpath="Id"/>
                    </xs:key>
                </xs:element>
            </xs:all>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="ManyThingsType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="OneThing" type="OneThingType"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="OneThingType">
        <xs:all>
            <xs:element name="Id" type="xs:string"/>
        </xs:all>
    </xs:complexType>

</xs:schema>

I expect validator to refuse KeyTest.xml because there are multiple records with Id "b". However, KeyTest.xml is considered valid. Could you point me where's a mistake in my code, please?

I've been using Utilties Online Validator to validate my files. I'm xml/xsd beginner, so please take into consideration the fact that I might have made some basic mistakes.

C. M. Sperberg-McQueen
  • 24,596
  • 5
  • 38
  • 65
browning0
  • 901
  • 2
  • 11
  • 21

1 Answers1

1

Your problem appears to be that the XPath expressions in XSD keys default to the XPath 1.0 rule that says unprefixed QNames like the "Id" in your field specification match unqualified elements.

Your key constraint is defined on an element whose expanded name is Q{keytest}ManyThings, and it's selecting children of that element named Q{}OneThing, and requiring that those children need to have a child named Q{}Id with a unique value. This would be fine, except that the rest of your schema specifies that the children and grand-children of Q{keytest}ManyThings are namespace-qualified elements named, respectively, Q{keytest}OneThing and Q{keytest}Id.

One way to repair this, in XSD 1.1, is to use the xpathDefaultNamespace attribute on the schema element (or on the selector and field elements) and give it the value "keytest". I have no idea whether the validation service you are using supports XSD 1.1.

Another way, which will work in either 1.1 or 1.0, is to bind an explicit namespace prefix to your target namespace, e.g. by writing xmlns:keytest="keytest" on your schema document, and then using that prefix in your XPath expressions:

<xs:key name="PK_ManyThings">
    <xs:selector xpath="keytest:OneThing"/>
    <xs:field xpath="keytest:Id"/>
</xs:key>

When I do the latter, both Saxon and Xerces J find the error in your XML.

C. M. Sperberg-McQueen
  • 24,596
  • 5
  • 38
  • 65
  • Unfortunately, mentioned validator does not support XSD 1.1. I also failed to find online any validator that would. Anyway, 1.0 approach works perfectly. – browning0 Oct 06 '14 at 13:23