多级XSD​​约束

时间:2013-02-27 14:22:07

标签: xml xsd

我们正试图让模型对我们的XSD有利。这是问题所在:

List
 I-> Item1
       I->Element1
       I->Element2
       I->Element3       
 I-> Item2
       I->Element1
       I->Element2
       I->Element3
 I-> Item3
       I->Element1
       I->Element2
       I->Element3

ReferenceToElement
 I-> Item1/Element1

我们有一个模型,我们需要两个嵌套列表。因此,列表中包含“项目”,每个项目都有一个包含元素的列表。所以我们想要引用这些元素。

第一种方法

每个item /元素都有一个数字属性。 number属性在所有项目中都是唯一的。此外,number属性在所有元素中是唯一的,父元素的编号用其编号进行编码。例如,对于item.no = 2,所有元素看起来都像这个2xx,所以201,202等。这个元素会将元素限制为100,这对我们来说很好。

为了保持所引用元素的存在,我们为所有项目创建了一个约束,以及所有项目中的所有元素。所以我们对元素的引用将如下所示

Reference
  - ItemNo
  - ElementNo

这样我们确保了项目以及元素的存在。我知道这两个fiels之间存在一个问题,因为引用的项目不一定在elementno中隐式声明。例如ItemNo = 1,但ElementNo = 202。这样,模式验证将告诉我们至少这些元素是否存在。主要的缺点是,我们需要在现在杀死我们的所有元素中正确分配数字。

第二种方法

我们不会在elementNo上使用约束,而是使用itemNo。这样我们就可以在所有元素上使用简单数字,但是我们将在模式验证期间松开elementNo上的引用迭代。这对我们来说似乎是最好的方式。

问题:

有没有办法用XSD功能建模两阶段参考?我读了一些关于断言的内容,但在这种情况下似乎没有帮助我们。

1 个答案:

答案 0 :(得分:0)

[请注意,如果您真的展示了一些XML,那么理解您的问题会更容易一些。事实上,任何答案都必须部分基于对您的散文描述旨在描述的XML构造的猜测;然后带上一粒盐。]

如果我理解你,你希望施加一些限制(编号在这里作为参考):

  1. 每个<element>元素都显示为<item>元素的子元素。

  2. 每个<element><item>元素都有一个number属性,其值为标识号;每个number属性的值是十进制数字的有限序列。

  3. 每个<item>元素的标识号在某些已标识的容器元素(例如文档元素)中的所有<item>元素中都是唯一的。

  4. 每个<element>元素的标识号在同一容器元素中的所有<element>元素中都是唯一的。 (或者你的意思是它在包含项目中的所有<element>元素中是唯一的?我无法从你的描述中看出来。)

  5. 每个<element>元素的标识号将具有父<item>元素的标识号作为前缀。

  6. 每个<element>元素的标识号将比父<item>元素的标识号长两位数。

  7. 以下架构强加了这些约束。由于您提到断言,我假设您能够使用XSD 1.1。 (如果你没有1.1,你就没有断言。)

    <xs:schema 
        targetNamespace="http://example.com/elements-and-items"
        xmlns:tns="http://example.com/elements-and-items"
        elementFormDefault="qualified"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">
    
      <xs:element name="test" type="tns:test">
        <xs:unique name="item-unique">
          <xs:annotation>
            <xs:documentation>
              Ensure that the number attribute on each
              item is unique within the 'test' element.
              (Enforces constraint 3.)
            </xs:documentation>
          </xs:annotation>
          <xs:selector xpath=".//tns:item"/>
          <xs:field xpath="@number"/>
        </xs:unique>
        <xs:unique name="element-unique">
          <xs:annotation>
            <xs:documentation>
              Ensure that the number attribute on each
              item is unique within the 'test' element.
              (Enforces constraint 4.  If 'element' elements
              are only supposed to be unique within 'item'
              elements, then move this to the declaration of
              the 'item' element, and forget constraint
              5.)                    
            </xs:documentation>
          </xs:annotation>
          <xs:selector xpath=".//tns:item/tns:element"/>
          <xs:field xpath="@number"/>
        </xs:unique>
    
      </xs:element>
    
      <xs:element name="item" type="tns:item"/>
    
      <xs:element name="element" type="tns:element"/>
    
      <xs:complexType name="test">
        <xs:annotation>
          <xs:documentation>
            Each 'test' element contains a sequence of
            'item' elements.
            (Helps enforce constraint 1.)
          </xs:documentation>
        </xs:annotation>
        <xs:sequence>
          <xs:element ref="tns:item" maxOccurs="unbounded"/>
        </xs:sequence>        
      </xs:complexType>
    
      <xs:complexType name="item">
        <xs:annotation>
          <xs:documentation>
            Each 'item' element contains a sequence of
            'element' elements.
            (Helps enforce constraint 1.)
            Each 'item' element has a 'number' attribute,
            of type 'tns:number'.
            (Enforces constraint 2 for 'item' elements.)
          </xs:documentation>
        </xs:annotation>
        <xs:sequence>
          <xs:element ref="tns:element" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="number" type="tns:number"/>
        <xs:assert test="
            every $id in ./@number satisfies
            every $e in .//tns:element/@number satisfies
            starts-with($e,$id)">
          <xs:annotation>
            <xs:documentation>
              Each element-identifying number has the
              item-identifying number of the containing item
              as a prefix.
              Enforces constraint 5.
            </xs:documentation>
          </xs:annotation>
        </xs:assert>
        <xs:assert test="
            every $id in ./@number satisfies
            every $e in .//tns:element/@number satisfies
            string-length($e) = string-length($id) + 2">
          <xs:annotation>
            <xs:documentation>
              Each element-identifying number is two
              digits longer than the item-identifying
              number of the containing item.
              Enforces constraint 6.
            </xs:documentation>
          </xs:annotation>
        </xs:assert>
      </xs:complexType>
    
      <xs:complexType name="element" mixed="true">
        <xs:annotation>
          <xs:documentation>
            Each 'element' element has a 'number' attribute,
            of type 'tns:number'.
            (Enforces constraint 2 for 'element' elements.)
          </xs:documentation>
        </xs:annotation>
        <xs:sequence/>
        <xs:attribute name="number" type="tns:number"/>
      </xs:complexType>
    
      <xs:simpleType name="number">
        <xs:restriction base="xs:string">
          <xs:pattern value="\d+"/>
        </xs:restriction>
      </xs:simpleType>
    </xs:schema>
    

    请注意,每个XSD 1.1处理器都需要在断言中支持相当小的XPath 2.0子集;我没有努力尝试在这个子集中编写断言(但我没有做出任何努力来决定它们是否可以在该子集中编写)。

    一个有效的实例,在结构上与我的非XML示例相同(据我所知):

    <test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="
        http://example.com/elements-and-items 
        uniqueness.xsd"
     xmlns="http://example.com/elements-and-items">
    
      <item number="1">
        <element number="101"/>
        <element number="102"/>
        <element number="103"/>
      </item>
      <item number="2">
        <element number="201"/>
        <element number="205"/>
        <element number="206"/>
      </item>
      <item number="3">
        <element number="303"/>
        <element number="301"/>
        <element number="302"/>
      </item>
    
    </test>
    

    通过违反每个约束来说明无效实例;如果模式正在执行其工作,则应检测每个违规,并且应使相应的元素或项无效:

    <test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="
        http://example.com/elements-and-items
        uniqueness.xsd"
     xmlns="http://example.com/elements-and-items">
    
      <item number="1">
        <element number="101"/>
        <element number="102"/>
        <element number="103"/>
      </item>
      <item number="1">
        <!--* duplicate item number, invalid
            * (violates constraint 3) 
            *-->
        <element number="104"/>
        <element number="105"/>
        <element number="106"/>
      </item>
      <item number="2">
        <element number="107">
          element number unique but doesn't match item number 
          (violates constraint 5)
        </element>
        <element number="202"/>
        <element number="202">
          item number not unique
          (violates constraint 4)
        </element>
      </item>
      <item number="3">
        <element number="303"/>
        <element number="301"/>
        <element number="3141592">
          item number unique and matches item number
          but more than two digits longer 
          (violates constraint 6)</element>
      </item>
    
    </test>