我试图使用 XSD 1.1 框架来测试当前范围元素的子元素是否包含属性。如果为真,我想要一个元素的模式验证,如果为假,我想要另一个。
示例 XML
<!-- XML 1 -->
<GrandParent name="Sam">
<Parent name="Kevin">
<Child name="Kyle" id="10" dob="1989-05-02"/>
</Parent>
</GrandParent>
<!-- XML 2 -->
<GrandParent name="Sam">
<Parent name="Kevin" id="10" dob="1975-10-11"/>
</GrandParent>
XSD 1.1 用于上述 xml 示例
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="GrandParent">
<xs:complexType>
<xs:sequence>
<xs:element ref="Parent" />
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
<xs:element name="Parent">
<xs:alternative test="./Child/@id" type="ParentType1" />
<xs:alternative type="ParentType2" />
</xs:element>
<xs:element name="Child">
<xs:complexType>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="id" type="xs:integer" use="required" />
<xs:attribute name="dob" type="xs:date" use="required" />
</xs:complexType>
</xs:element>
<xs:complexType name="ParentType1">
<xs:sequence>
<xs:element ref="Child" />
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType>
<xs:complexType name="ParentType2">
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="id" type="xs:integer" use="required" />
<xs:attribute name="dob" type="xs:date" use="required" />
</xs:complexType>
</xs:schema>
我正在使用 Xerces xsd 1.1 验证功能 XSD 验证错误
XML 1
[Error] 1:46: cvc-complex-type.4: Attribute 'id' must appear on element 'Parent'.
[Error] 1:46: cvc-complex-type.4: Attribute 'dob' must appear on element 'Parent'.
[Error] 1:100: cvc-complex-type.2.1: Element 'Parent' must have no character or element information item [children], because the type's content type is empty.
XML 2
Validates
Xpath 对我来说似乎没有错,我尝试了一些变化//Child/@id
, 包括boolean(Child/@id)
但没有快乐。我不关心属性的值是什么,只关心它存在于子元素中。
更新
感谢 Michael Kay 提供的以下答案,我重写了我的模式使用断言而不是替代方案。这是更新的架构:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="GrandParent">
<xs:complexType>
<xs:choice>
<xs:element ref="Parent" />
</xs:choice>
<xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
<xs:element name="Child">
<xs:complexType>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="id" type="xs:integer" use="required" />
<xs:attribute name="dob" type="xs:date" use="required" />
</xs:complexType>
</xs:element>
<xs:element name="Parent">
<xs:complexType>
<xs:sequence>
<xs:element ref="Child" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="id" type="xs:integer" use="optional" />
<xs:attribute name="dob" type="xs:date" use="optional" />
<xs:assert test="if (Child/@id) then not(@id or @dob) else (@id and @dob and not(Child))"/>
</xs:complexType>
</xs:element>
</xs:schema>
该模式似乎工作得更好,我使用以下 XML 对其进行了测试,所有这些都按预期通过或失败
PASS <GrandParent name="Sam"><Parent name="Kevin"><Child name="Kyle" id="10" dob="1989-05-02"/></Parent></GrandParent>
PASS <GrandParent name="Sam"><Parent name="Kevin" id="10" dob="1975-10-11"/></GrandParent>
FAIL <GrandParent name="Sam"><Parent name="Kevin" id="10"/></GrandParent>
FAIL <GrandParent name="Sam"><Parent name="Kevin" dob="1975-10-11"/></GrandParent>
FAIL <GrandParent name="Sam"><Parent name="Kevin"/></GrandParent>