XSD将XML元素值约束到现有的XML属性值?

时间:2016-11-12 23:25:32

标签: xml xsd xsd-validation xml-validation

目标是约束BEST_FRIEND_ID在此XML中具有现有FRIEND_ID属性的值:

friends.xml

<?xml version="1.0"?>
<FRIENDS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="friends.xsd">
    <FRIEND FRIEND_ID="1">
        <NAME>John</NAME>
        <BEST_FRIEND_ID>2</BEST_FRIEND_ID>
    </FRIEND>
    <FRIEND FRIEND_ID="2">
        <NAME>Kate</NAME>
        <BEST_FRIEND_ID>1</BEST_FRIEND_ID>
    </FRIEND>
</FRIENDS>

E.g。对于给定的XML,如果我将任何BEST_FRIEND_ID元素的值更改为3,验证将失败。

friends.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
    xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning">
    <xs:complexType name="FriendsType">
        <xs:sequence>
            <xs:element ref="FRIEND" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="FriendType">
        <xs:sequence>
            <xs:element ref="NAME"/>
            <xs:element ref="BEST_FRIEND_ID"/>
        </xs:sequence>
        <xs:attribute name="FRIEND_ID" type="xs:integer"/>
    </xs:complexType>

    <xs:element name="FRIENDS" type="FriendsType"/>
    <xs:element name="FRIEND" type="FriendType"/>
    <xs:element name="NAME" type="xs:string"/>
    <xs:element name="BEST_FRIEND_ID" type="xs:integer"/>
</xs:schema>

我的想法是使用断言的力量(XSD 1.1)。这是我到目前为止所知道的

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
    xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1">
    <xs:complexType name="FriendsType">
        <xs:sequence>
            <xs:element ref="FRIEND" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="FriendType">
        <xs:sequence>
            <xs:element ref="NAME"/>
            <xs:element ref="BEST_FRIEND_ID"/>
        </xs:sequence>
        <xs:attribute name="FRIEND_ID" type="xs:integer"/>
    </xs:complexType>
    <xs:complexType name="IdConstrain">
        <xs:simpleContent>
            <xs:extension base="xs:integer">
                <xs:assert test="$value = @FRIEND_ID"/>
            </xs:extension>
        </xs:simpleContent>
    </xs:complexType>

    <xs:element name="FRIENDS" type="FriendsType"/>
    <xs:element name="FRIEND" type="FriendType"/>
    <xs:element name="NAME" type="xs:string"/>
    <xs:element name="BEST_FRIEND_ID" type="IdConstrain"/>
</xs:schema>

并且验证失败:

  

严重性:错误说明:cvc-assertion:断言评估   ('$ value = @FRIEND_ID')对于架构类型的元素'BEST_FRIEND_ID'   'IdConstrain'没有成功。出发地点:6:10结束地点:   6:25网址:http://www.w3.org/TR/xmlschema11-1/#cvc-assertion

我也尝试了类似BEST_FRIEND_ID[contains(., @FRIEND_ID)]的内容,但它也不起作用。

1 个答案:

答案 0 :(得分:1)

您应该使用以下内容来检查每个最好的朋友ID是否是现有的朋友ID。您还应该检查最好的朋友ID不等于它自己:

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

    <xs:complexType name="FriendsType">
        <xs:sequence>
            <xs:element ref="FRIEND" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:assert test="every $bfid in FRIEND/BEST_FRIEND_ID
            satisfies $bfid = (FRIEND/@FRIEND_ID)"/>
        <!-- Optional check best friend is not equals to itself -->
        <xs:assert test="every $fr in FRIEND
            satisfies $fr/@FRIEND_ID != $fr/BEST_FRIEND_ID"/>
    </xs:complexType>

    <xs:complexType name="FriendType">
        <xs:sequence>
            <xs:element ref="NAME"/>
            <xs:element ref="BEST_FRIEND_ID"/>
        </xs:sequence>
        <xs:attribute name="FRIEND_ID" type="xs:integer"/>
    </xs:complexType>

    <xs:element name="FRIENDS" type="FriendsType"/>
    <xs:element name="FRIEND" type="FriendType"/>
    <xs:element name="NAME" type="xs:string"/>
    <xs:element name="BEST_FRIEND_ID" type="xs:integer"/>
</xs:schema>

你还可以检查最好的朋友ID是否与FRIEND标签内的朋友ID不同,而不是FRIENDS标签。

<xs:complexType name="FriendType">
    <xs:sequence>
        <xs:element ref="NAME"/>
        <xs:element ref="BEST_FRIEND_ID"/>
    </xs:sequence>
    <xs:attribute name="FRIEND_ID" type="xs:integer"/>
    <xs:assert test="@FRIEND_ID != BEST_FRIEND_ID"/>
</xs:complexType>