1

我试图使用 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>
4

1 回答 1

3

类型替代构造中的条件测试只能访问相关元素的属性,不能访问子元素或后代元素。

在规范中实现这一点的方法是,定义 XPath 表达式是针对构建为被验证元素的浅表副本的数据模型实例进行评估的,其中浅表副本包括属性的副本,但不包括子项的副本。结果,尝试访问孩子不会出错,只会出错。

限制的原因是为了避免如果您必须查看无效数据以确定它是否无效时可能发生的问题:您很容易以骗子悖论告终。

对于此验证,您需要更通用的断言功能,而不是类型替代。

于 2017-01-03T16:12:03.370 回答