简体   繁体   中英

Specify XSD such that an XML element must have the value of another XML element

I'm not sure if this is possible with XML/XSD, and haven't had much luck searching for it.

Can you specify an XSD, so that when you're writing your XML, you can have an element that must reference one of the values contained in another XML element?

For example, if you had this XML:

<car>Audi</car>
<car>Ford</car>
<car>Honda</car>

<person>
  <drives>Audi</drives>
</person>

How do you specify the XSD for drives so that it must be one of the values entered for car?

XSD 1.0 would work. Ideally you should use a combination of same schema type and referential integrity.

An XSD:

<?xml version="1.0" encoding="utf-8"?>
<!--XML Schema generated by QTAssistant/XML Schema Refactoring (XSR) Module (http://www.paschidev.com)-->
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="sample">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element maxOccurs="unbounded" name="car" type="car"/>
                <xsd:element name="person">
                    <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="drives" type="car"/>
                        </xsd:sequence>
                    </xsd:complexType>
                </xsd:element>
            </xsd:sequence>
        </xsd:complexType>
        <xsd:key name="PKCars">
            <xsd:selector xpath="car"/>
            <xsd:field xpath="."/>
        </xsd:key>
        <xsd:keyref name="FKPersonCar" refer="PKCars">
            <xsd:selector xpath="person/drives"/>
            <xsd:field xpath="."/>
        </xsd:keyref>
    </xsd:element>
    <xsd:simpleType name="car">
        <xsd:restriction base="xsd:string">
            <xsd:enumeration value="Audi"/>
            <xsd:enumeration value="Ford"/>
            <xsd:enumeration value="Honda"/>
        </xsd:restriction>
    </xsd:simpleType>
</xsd:schema>

Diagram:

在此处输入图片说明

Invalid XML:

<sample>
    <car>Audi</car>
    <car>Ford</car>
    <car>Honda</car>

    <person>
        <drives>Aud</drives>
    </person>
</sample>

Error:

Error occurred while loading [], line 7 position 16
The 'drives' element is invalid - The value 'Aud' is invalid according to its datatype 'car' - The Enumeration constraint failed.
specify-xsd-such-that-an-xml-element-must-have-the-value-of-another-xml-element.xml is invalid.

This error tells you that using an enumerated value makes key/keyref superfluous - you'll not get to trigger it.

However, if you cannot have a list of enumerated values in your XSD, you should at least enforce a mininum length for the type, to avoid empty values creating havoc. Of course, while it is recommended to share the type, you don't have to.

Modified XSD:

<?xml version="1.0" encoding="utf-8"?>
<!--XML Schema generated by QTAssistant/XML Schema Refactoring (XSR) Module (http://www.paschidev.com)-->
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="sample">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element maxOccurs="unbounded" name="car" type="car"/>
                <xsd:element name="person">
                    <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="drives" type="car"/>
                        </xsd:sequence>
                    </xsd:complexType>
                </xsd:element>
            </xsd:sequence>
        </xsd:complexType>
        <xsd:key name="PKCars">
            <xsd:selector xpath="car"/>
            <xsd:field xpath="."/>
        </xsd:key>
        <xsd:keyref name="FKPersonCar" refer="PKCars">
            <xsd:selector xpath="person/drives"/>
            <xsd:field xpath="."/>
        </xsd:keyref>
    </xsd:element>
    <xsd:simpleType name="car">
        <xsd:restriction base="xsd:normalizedString">
            <xsd:minLength value="1"/>
        </xsd:restriction>
    </xsd:simpleType>
</xsd:schema>

Error message:

Error occurred while loading [], line 9 position 4
The key sequence 'Aud' in Keyref fails to refer to some key.
specify-xsd-such-that-an-xml-element-must-have-the-value-of-another-xml-element.xml is invalid.

With XSD 1.1 you can use assertions .

Assertion components constrain the existence and values of related elements and attributes.

You can use XPath 2.0 expressions to perform the validation/test in the assertion.

This example schema has an assertion for the /doc element that ensures that the /doc/person/drives value is equal to one of it's /doc/car elements:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.1" elementFormDefault="qualified">

    <xs:element name="car" type="xs:string" />  
    <xs:element name="drives" type="xs:string" />

    <xs:element name="person">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="drives"/>
            </xs:sequence>     
        </xs:complexType>
    </xs:element>

    <xs:element name="doc">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="car" maxOccurs="unbounded"/> 
                <xs:element ref="person"/>
            </xs:sequence> 
            <xs:assert test="person/drives = car"/>
        </xs:complexType>
    </xs:element>

</xs:schema>

That looks like an enumeration and your example happens to very similar to the w3schools example.

<xs:element name="car" type="carType"/>

<xs:simpleType name="carType">
    <xs:restriction base="xs:string">
        <xs:enumeration value="Audi"/>
        <xs:enumeration value="Golf"/>
        <xs:enumeration value="BMW"/>
    </xs:restriction>
</xs:simpleType>

<xs:element name="person">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="drives" type="carType"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>

If not you probably want Pangeas answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM