Home > database >  Validate XML with XSD issue
Validate XML with XSD issue

Time:08-08

I have this simple XML:

<company>
<departments>
    <department IDDepartment="A01" director="00001234S">
        <employee PassportNumber="00001234S">
            <name>Daniel</name>
            <lastname>Robinson Harris</lastname>
            <salary>2100.86</salary>
        </employee>
        <employee PassportNumber="79300210A">
            <name>Lara</name>
            <lastname>Williams</lastname>
            <salary>1100</salary>
        </employee>
    </department>
    <department IDDepartment="A02" director="09448822T">
        <employee PassportNumber="12345678A">
            <name>Daniel</name>
            <lastname>Brown</lastname>
            <salary>1200</salary>
        </employee>
        <employee PassportNumber="09448822T">
            <name>Tom</name>
            <lastname>Johnson Smith</lastname>
            <salary>2500.50</salary>
        </employee>
    </department>
</departments>

I want to validate with XSD that the "director" value corresponds to the passport number of one of the employees. I'm new to XSD and I'm trying to figure out how to do it. Thanks.

CodePudding user response:

You would need to use XSD 1.1.

It has an assert functionality to validate business rules.

XSD processors Saxon, Xerces, and some others are conformant with the XSD 1.1

The XSD below is using Xerces 2.12.2 for tailored validation messages.

XML

<?xml version="1.0"?>
<company>
    <departments>
        <department IDDepartment="A01" director="00001234S">
            <employee PassportNumber="00001234S">
                <name>Daniel</name>
                <lastname>Robinson Harris</lastname>
                <salary>2100.86</salary>
            </employee>
            <employee PassportNumber="79300210A">
                <name>Lara</name>
                <lastname>Williams</lastname>
                <salary>1100</salary>
            </employee>
        </department>
        <department IDDepartment="A02" director="09448822T">
            <employee PassportNumber="12345678A">
                <name>Daniel</name>
                <lastname>Brown</lastname>
                <salary>1200</salary>
            </employee>
            <employee PassportNumber="09448822T">
                <name>Tom</name>
                <lastname>Johnson Smith</lastname>
                <salary>2500.50</salary>
            </employee>
        </department>
    </departments>
</company>

XSD

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xmlns:xerces="http://xerces.apache.org" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1">
    <xs:element name="company">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="departments"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="departments">
        <xs:complexType>
            <xs:sequence>
                <xs:element maxOccurs="unbounded" ref="department"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="department">
        <xs:complexType>
            <xs:sequence>
                <xs:element maxOccurs="unbounded" ref="employee"/>
            </xs:sequence>
            <xs:attribute name="IDDepartment" use="required" type="xs:string"/>
            <xs:attribute name="director" use="required" type="xs:NMTOKEN"/>
            <xs:assert test="count(employee[@PassportNumber=../@director])=1" xerces:message="Department's director value shall corresponds to the passport number of one of the employees">
                <xs:annotation>
                    <xs:documentation>Rule #: 28-34</xs:documentation>
                    <xs:documentation>Department's director value shall corresponds to the passport number of one of the employees</xs:documentation>
                </xs:annotation>
            </xs:assert>
        </xs:complexType>
    </xs:element>
    <xs:element name="employee">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="name"/>
                <xs:element ref="lastname"/>
                <xs:element ref="salary"/>
            </xs:sequence>
            <xs:attribute name="PassportNumber" use="required" type="xs:NMTOKEN"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="name" type="xs:string"/>
    <xs:element name="lastname" type="xs:string"/>
    <xs:element name="salary" type="xs:decimal"/>
</xs:schema>

CodePudding user response:

If you don't have XSD 1.1 you can probably do this with key/keyref.

On the department element, define a key with selector=".", field="@director", and a corresponding keyref with selector="employee", field="@PassportNumber".

UPDATE

With the additional information that it can be an employee in a different department, the key needs to be defined as follows:

On the departments element, define a key with selector="department", field="@director", and a corresponding keyref with selector=".//employee", field="@PassportNumber".

  • Related