1

我搜索了这个,但找不到我的问题的解决方案,所以请不要垃圾这个问题。

我们有一个由 XSD 描述的具有非常复杂的 XML 配置的服务。为了让事情顺利进行,必须遵守许多规则。XSD 描述了配置的结构,但不是我们现在必须做的规则。在创建了一些全局规则之后,我们现在必须做一些更复杂的事情,我们遇到了一个问题。它看起来像验证器只使用来自根元素的 key/keyref/unique。我创建了小型 XSD 和 XML 文件来说明:

XSD:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://test.org/XMLSchema.xsd"
    elementFormDefault="qualified"
    xmlns="http://test.org/XMLSchema.xsd"
    xmlns:t="http://test.org/XMLSchema.xsd"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Orders" type="t:OrdersList">
    <xs:key name="OrderNo">
      <xs:selector xpath="./t:Order" />
      <xs:field xpath="@Number" />
    </xs:key>
  </xs:element>

  <xs:complexType name="OrdersList">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="unbounded" name="Order" nillable="false" type="t:Order" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Order">
    <xs:sequence>
      <xs:element minOccurs="1" maxOccurs="1" name="Lines" nillable="false" type="t:OrdersLinesList" />
    </xs:sequence>
    <xs:attribute name="Number" use="optional" type="xs:string" />
    <xs:attribute name="ClientId" use="optional" type="xs:int" />
  </xs:complexType>

  <xs:complexType name="OrdersLinesList">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="unbounded" name="Line" nillable="false" type="t:OrderLine">
        <!-- THE PROBLEM -->
        <xs:key name="LineNoKey">
          <xs:selector xpath="./t:Line" />
          <xs:field xpath="@LineNumber" />
        </xs:key>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="OrderLine">
    <xs:attribute name="LineNumber" use="optional" type="xs:string" />
    <xs:attribute name="ProductId" use="optional" type="xs:int" />
    <xs:attribute name="Amount" use="optional" type="xs:decimal" />
  </xs:complexType>
</xs:schema>

XML:

<?xml version="1.0" encoding="utf-8"?>
<Orders xmlns="http://test.org/XMLSchema.xsd">
  <Order Number="0001/5/13" ClientId="123">
    <Lines>
      <Line LineNumber="1" ProductId="123" Amount="4" />
      <Line LineNumber="2" ProductId="124" Amount="4" />
    </Lines>
  </Order>
  <Order Number="0002/5/13" ClientId="123">
    <Lines>
      <Line LineNumber="1" ProductId="123" Amount="4" />
      <!-- Duplicate number - it DOES validate as expected. -->
      <Line LineNumber="1" ProductId="124" Amount="4" />
    </Lines>
  </Order>
  <!-- Duplicate number - it doesn't validate as expected. -->
  <Order Number="0002/5/13" ClientId="123">
    <Lines>
      <Line LineNumber="1" ProductId="123" Amount="4" />
      <Line LineNumber="2" ProductId="124" Amount="4" />
    </Lines>
  </Order>
</Orders>

我有几个问题我找不到任何明智的答案:

  1. 如何解决以上问题。LineNumber 必须是唯一的,但仅在 Order/Lines 内。
  2. 是否可以允许 keyref 包含不存在的虚拟值(我们的服务使用一些预定义的......让我们说一下。自定义的在 XML 中定义以允许扩展功能,但在大多数情况下,用户将使用预定义的)
  3. 有没有办法确定标签中的元素列表(类似于上面的行)是否至少有一个标签,其属性设置为某个值。一个很好的例子是将其描述为具有唯一名称的表列表,该列表具有具有唯一名称的列列表,并且至少其中一个列是主键。
4

1 回答 1

1

这是 Lines/Line 的更正约束:

<xs:complexType name="Order">
    <xs:sequence>
        <xs:element minOccurs="1" maxOccurs="1" name="Lines" nillable="false" type="t:OrdersLinesList">
            <!-- THE PROBLEM SOLVED -->
            <xs:key name="LineNoKey">
                <xs:selector xpath="t:Line"/>
                <xs:field xpath="@LineNumber"/>
            </xs:key>               
        </xs:element>
    </xs:sequence>
    <xs:attribute name="Number" use="optional" type="xs:string"/>
    <xs:attribute name="ClientId" use="optional" type="xs:int"/>
</xs:complexType>

如果您可以可视化您的约束,如果总是有帮助,以了解它们的作用范围:

正确示意图:

在此处输入图像描述

与原来的相比:

在此处输入图像描述

你可以看到根元素Line的选择器正在寻找另一个 Line ( ./t:Line ); 即使你修复了选择器,它也总是最多匹配一个属性。键的想法是选择器应该匹配一组节点,其中字段必须存在且唯一。

以上应注意1。

  1. 不。
  2. 不基于属性。为了坚持你的并行,对于 XSD 1.0,我可能会强制执行一个名为PrimaryKey的元素,它应该包含一个或多个对其他列名称的引用;好像不是在列定义中使用 PRIMARY KEY 约束子句,而是在表级别强制使用相同的约束子句。
于 2013-05-11T01:44:25.577 回答