0

目前,我们正试图让模型对我们的 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

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

第一种方法

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

为了保持引用元素的存在,我们对所有项目以及所有项目中的所有元素都创建了一个唯一的约束。所以我们对元素的引用看起来像这样

Reference
  - ItemNo
  - ElementNo

通过这种方式,我们确保了项目和元素的存在。我知道这两个字段之间存在问题,因为引用的项目不一定在 elementno.xml 中隐式说明。例如 ItemNo=1,但 ElementNo=202。这样,模式验证至少会告诉我们这些元素是否确实存在。主要缺点是我们需要注意正确分配所有元素中的数字,这会立即杀死我们。

第二种方法

我们不会对 elementNo 使用约束,而是使用 itemNo。这样我们就可以在所有元素上使用简单的数字,但是在模式验证期间我们将失去对 elementNo 的引用完整性。这似乎是我们目前最好的方式。

问题:

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

4

1 回答 1

0

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

如果我理解您,您希望施加几个限制(此处编号以供参考):

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

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

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

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

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

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

以下模式强加了这些约束。由于您提到断言,我假设您能够使用 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>
于 2013-02-27T16:04:04.337 回答