XSD - keyref in complexeType - No match found

227 Views Asked by At

I write an XSD to define followin elements:

  • glossary
    • definition [term=unique]
      • term [ref=term]

"Glossary" contains a list of "definition". Each "definition" has an unique attribute "term". A "definition" can contain mixed text with elements "term". Each "term" has an attribute "ref" that refers to a definition's term attribute.

Please, note that keyref (named "termRef") is a part of a complexType definition (named "textType"), because this type should be useful in several places of the xsd document, not only in "definition".

I do not understand why XML linter does not find the key reference.

Here is the code I have written:

XSD:

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

    <xs:complexType name="textType" mixed="true">
        <xs:choice maxOccurs="unbounded">
            <xs:element name="term" minOccurs="0" maxOccurs="unbounded">
                <xs:complexType>
                    <xs:simpleContent>
                        <xs:extension base="xs:normalizedString">
                            <xs:attribute name="ref" use="required" type="xs:token"/>
                        </xs:extension>
                    </xs:simpleContent>
                </xs:complexType>
                <xs:keyref name="termRef" refer="glossaryTermUnique">
                    <xs:selector xpath="."/>
                    <xs:field xpath="@ref"/>
                </xs:keyref>
            </xs:element>
        </xs:choice>
    </xs:complexType>

    <xs:element name="foo">
        <xs:complexType>
            <xs:sequence>

                <xs:element name="glossary">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="definition" minOccurs="0" maxOccurs="unbounded">
                                <xs:complexType>
                                    <xs:complexContent>
                                        <xs:extension base="textType">
                                            <xs:attribute name="term" use="required" type="xs:token"/>
                                        </xs:extension>
                                    </xs:complexContent>
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>
                    <xs:unique name="glossaryTermUnique">
                        <xs:selector xpath="xsfoo:definition"/>
                        <xs:field xpath="@term"/>
                    </xs:unique>
                </xs:element>

            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>

XML:


<?xml version="1.0"?>
<foo
        xmlns="foo"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="foo/none.xsd">
    <glossary>
        <definition term="ik 1">identification key 1</definition>
        <definition term="ik 2">identification key 2 with <term ref="ik 1">a ik 1 reference</term></definition>
    </glossary>
</foo>

Here is the error message from xmllint:

Schemas validity error : Element '{foo}term': No match found for key-sequence ['ik 1'] of keyref '{foo}termRef'.

Thank you very much for your help! :)

2

There are 2 best solutions below

1
Martin Honnen On

I think the nesting of the elements in the XSD matters, Xerces says

Identity Constraint error: the keyref identity constraint "termRef" refers to a key or unique that is out of scope.

while

               <xs:unique name="glossaryTermUnique">
                    <xs:selector xpath="xsfoo:definition"/>
                    <xs:field xpath="@term"/>
                </xs:unique>
                <xs:keyref name="termRef" refer="glossaryTermUnique">
                    <xs:selector xpath="xsfoo:definition/xsfoo:term"/>
                    <xs:field xpath="@ref"/>
                </xs:keyref>

fixes that it seems.

0
Raphhh On

As pointed in the answer before, nesting seems to be the key.

To solve the problem of reusability of "textType", we can move keyref into "foo" definition with the following xpath for the selector: .//xsfoo:term. So, the definition of "textType" is splitted (so, maybe not semantically correct?), but it works.

Full XSD:

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

    <xs:complexType name="textType" mixed="true">
        <xs:choice maxOccurs="unbounded">
            <xs:element name="term" minOccurs="0" maxOccurs="unbounded">
                <xs:complexType>
                    <xs:simpleContent>
                        <xs:extension base="xs:normalizedString">
                            <xs:attribute name="ref" use="required" type="xs:token"/>
                        </xs:extension>
                    </xs:simpleContent>
                </xs:complexType>
            </xs:element>
        </xs:choice>
    </xs:complexType>

    <xs:element name="foo">
        <xs:complexType>
            <xs:sequence>

                <xs:element name="glossary">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="definition" minOccurs="0" maxOccurs="unbounded">
                                <xs:complexType>
                                    <xs:complexContent>
                                        <xs:extension base="textType">
                                            <xs:attribute name="term" use="required" type="xs:token"/>
                                        </xs:extension>
                                    </xs:complexContent>
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>
                    <xs:unique name="glossaryTermUnique">
                        <xs:selector xpath="xsfoo:definition"/>
                        <xs:field xpath="@term"/>
                    </xs:unique>
                </xs:element>

            </xs:sequence>
        </xs:complexType>

        <xs:keyref name="termRef" refer="glossaryTermUnique">
            <xs:selector xpath=".//xsfoo:term"/>
            <xs:field xpath="@ref"/>
        </xs:keyref>

    </xs:element>

</xs:schema>