Search code examples
xmlxsdxmllint

Why is xmllint not validating the unique constraint for elements?


I want to validate if a certain element is unique. Unfortunately xmllint is not validating it. Is this a bug in xmllint (or libxml)?

I have created a minimal example:

example.xml

<?xml version="1.0" encoding="utf-8"?>
<book-list
    xmlns="https://example.com/book"
    xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
    xs:schemaLocation="https://example.com/book example.xsd">
    <book>Example 1</book>
    <book>Example 2</book>
    <book>Example 1</book>
</book-list>

example.xsd

<?xml version="1.0" encoding="utf-8"?>
<xs:schema
    xmlns="https://example.com/book"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="https://example.com/book"
    elementFormDefault="qualified">
    <xs:element name="book-list">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="book" maxOccurs="unbounded" type="xs:string" />
            </xs:sequence>
        </xs:complexType>
        <xs:unique name="unique-books">
            <xs:selector xpath="book" />
            <xs:field xpath="." />
        </xs:unique>
    </xs:element>
</xs:schema>

In my opinion xmllint should throw an error, when I validate the xml against the xsd:

xmllint --schema example.xsd --noout example.xml

Why is xmllint not throwing an error?


Solution

  • If you're using targetNamespace attribute in your schema then you should specify fully qualified XPath to unique node - check this schema, xmlint is failing as expected:

    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema xmlns:lib="https://example.com/book" xmlns:xs="http://www.w3.org/2001/XMLSchema"
        targetNamespace="https://example.com/book" elementFormDefault="qualified">
        <xs:element name="book-list">
            <xs:complexType>
                <xs:sequence>
                    <xs:element name="book" maxOccurs="unbounded" type="xs:string"/>
                </xs:sequence>
            </xs:complexType>
            <xs:unique name="unique-books">
                <xs:selector xpath="lib:book"/>
                <xs:field xpath="."/>
            </xs:unique>
        </xs:element>
    </xs:schema>