You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XSD 1.1含xsi:type谓词的XPath断言验证失败问题排查

问题:XSD 1.1断言无法正确验证genreRef指向Mystery类型genre的约束

实例XML文档

<books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <book>
        <genreRef>ID000</genreRef>
    </book>
    <genres>
        <genre xsi:type="Mystery" referenceId="ID000"/>
        <genre xsi:type="Action"  referenceId="ID001"/>
        <genre xsi:type="Fantasy" referenceId="ID002"/>
    </genres>
</books>

需求说明

需要约束<genreRef>元素仅指向类型为Mystery的<genre>元素,若指向Action或Fantasy类型的<genre>则视为错误,要求通过XSD 1.1的断言实现该校验。

编写的XSD 1.1 Schema

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    
    <xs:element name="books">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="book" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="genreRef" type="xs:IDREF"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <xs:element name="genres">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="genre" type="Genre" maxOccurs="unbounded"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
            <xs:assert test="every $i in book satisfies some $j in genres/genre[@xsi:type = 'Mystery'] satisfies $i/genreRef eq $j/@referenceId" />
        </xs:complexType>
    </xs:element>
    
    <xs:complexType name="Genre" abstract="true">
        <xs:sequence>
        </xs:sequence>
        <xs:attribute name="referenceId" use="required" type="xs:ID"/>
    </xs:complexType>
    
    <xs:complexType name="Mystery">
        <xs:complexContent>
            <xs:extension base="Genre"/>
        </xs:complexContent>
    </xs:complexType>
    
    <xs:complexType name="Action">
        <xs:complexContent>
            <xs:extension base="Genre"/>
        </xs:complexContent>
    </xs:complexType>
    
    <xs:complexType name="Fantasy">
        <xs:complexContent>
            <xs:extension base="Genre"/>
        </xs:complexContent>
    </xs:complexType>

</xs:schema>

遇到的错误

Element books does not satisfy assertion every $i in book satisfies some $j in genres/genre[@xsi:type = 'Mystery'] satisfies $i/genreRef eq $j/@referenceId

问题原因与修复方案

原因分析

直接通过@xsi:type = 'Mystery'匹配元素类型的方式存在两个问题:

  1. xsi:type属性的类型是xs:QName,直接与字符串'Mystery'比较时,SAXON的类型处理逻辑可能导致匹配失败;
  2. 依赖属性值判断类型不够可靠,若属性被篡改,校验会失效,正确的做法是直接判断元素的实际类型。

修复步骤

将<xs:assert>的test表达式修改为使用XPath的instance of语法直接校验<genre>元素的实际类型:

<xs:assert test="every $i in book satisfies some $j in genres/genre satisfies $j instance of element(*, Mystery) and $i/genreRef eq $j/@referenceId" />

或者更简洁的过滤写法:

<xs:assert test="every $i in book satisfies some $j in genres/genre[. instance of element(*, Mystery)] satisfies $i/genreRef eq $j/@referenceId" />

修复后的完整XSD

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    
    <xs:element name="books">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="book" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="genreRef" type="xs:IDREF"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <xs:element name="genres">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="genre" type="Genre" maxOccurs="unbounded"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
            <xs:assert test="every $i in book satisfies some $j in genres/genre satisfies $j instance of element(*, Mystery) and $i/genreRef eq $j/@referenceId" />
        </xs:complexType>
    </xs:element>
    
    <xs:complexType name="Genre" abstract="true">
        <xs:sequence>
        </xs:sequence>
        <xs:attribute name="referenceId" use="required" type="xs:ID"/>
    </xs:complexType>
    
    <xs:complexType name="Mystery">
        <xs:complexContent>
            <xs:extension base="Genre"/>
        </xs:complexContent>
    </xs:complexType>
    
    <xs:complexType name="Action">
        <xs:complexContent>
            <xs:extension base="Genre"/>
        </xs:complexContent>
    </xs:complexType>
    
    <xs:complexType name="Fantasy">
        <xs:complexContent>
            <xs:extension base="Genre"/>
        </xs:complexContent>
    </xs:complexType>

</xs:schema>

这个修改通过instance of element(*, Mystery)直接判断<genre>元素的实际类型为Mystery,再结合IDREF与ID的匹配校验,能准确实现你需要的约束,且在SAXON中可以正常生效。

内容的提问来源于stack exchange,提问作者Roger Costello

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 15:19:50