我试图使用XSD 1.1框架来测试当前范围元素的子元素是否包含属性。如果为true,我想要对元素进行一次模式验证,如果为false我想要另一个。
示例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>
答案 0 :(得分:2)
类型替代构造中的条件测试只能访问相关元素的属性,而不能访问子元素或后代。
在规范中实现这一点的方法是定义XPath表达式是针对构造为被验证元素的浅表副本的数据模型实例进行评估的,其中浅表副本包含属性的副本,但不包括子元素的副本。因此,尝试访问孩子并不会给出错误,只会给出错误。
限制的原因是为了避免在您必须查看无效数据以确定其是否无效时可能出现的问题:您可以轻松地结束骗子的悖论。
对于此验证,您需要更一般的断言功能,而不是键入替代。