XML定义限制而不影响唯一性

时间:2014-08-29 14:37:33

标签: xml xsd schema

下面是一个示例XML Schema。如您所见,我需要创建大量元素(elem001elem999),其中所有元素都引用另一个元素" param"。请注意,param的属性ID是一个键,因此必须是唯一的。

现在,我如何指定限制,以便对elem001,属性"数量"元素" param"只能采用一组给定的值。同样,elem002elem999也有自己的一组值。然而,所有" param"整个XML文档中的元素必须具有唯一的ID。

我想如果我使用类型派生限制而不是ref,那么唯一性约束将不再适用于所有" param"亚型。那我该怎么办?

<xsd:element name="param">
    <xsd:complexType>
        <xsd:simpleContent base="xsd:double">
            <xsd:extension>
                <xsd:attribute name="quantity" type="xsd:string">
                <xsd:attribute name="ID" type="xsd:int">
            </xsd:extension>
        </xsd:simpleContent>
    </xsd:complexType>
</xsd:element>

<xsd:root>
    <xsd:key name="paramkey">
        <xsd:selector xpath="param/">
        <xsd:field xpath="@ID">
    </xsd:key>

    <xsd:element name="elem001">
        <xsd:element ref="param">
        <xsd:element name="X" />
    </xsd:element>

    <xsd:element name="elem002">
        <xsd:element ref="param">
        <xsd:element name="Y" />
    </xsd:element>

    <!-- ... -->

    <xsd:element name="elem999">
        <xsd:element ref="param">
        <xsd:element name="Y" />
    </xsd:element>
</xsd:root>

--------------- EDIT ----------------

对不起,我应该提供一个我最终目标的示例XML文件,以使其更清晰。在下面的示例中,您可以看到我有几个对象(汽车,飞机,马)包含(除其他外)一些物理参数。属性&#34;数量&#34;定义我们所谈论的物理量:温度,燃料水平等。

现在,我有两个要求:

首先,我需要在我的架构中限制汽车允许的物理量,这显然不包括bloodPressure。同样,指定马的高度也没有意义(至少对我的应用来说......)。因此,我需要指定可以在汽车上测量的允许物理量。

其次,参数的id必须在所有参数中都是唯一的。例如,飞机高度的id不能为6,如果id为6(马的血压)的参数在&#34;数量&#34;

<car>
    <param id="1" quantity="fuelLevel">100</param>
    <param id="2" quantity="temperature">86</param>
</car>
<car>
    <param id="3" quantity="fuelLevel">99</param>
    <param id="4" quantity="temperature">77</param>
</car>
<horse>
    <param id="5" quantity="temperature">123</param>
    <param id="6" quantity="bloodPressure">26</param>
</horse>
<plane>
    <param id="7" quantity="altitude">1000</param>
    <param id="8" quantity="temperature">1050</param>
</plane>

实际上,如果我可以做类似下面的事情,它可能会更好,但我认为它更不可行。

<car>
    <params>
        <fuelLevel id="1">100</fuelLevel>
        <temperature id="2">86</temperature>
    </params>
</car>
<car>
    <params>
        <fuelLevel id="3">99</fuelLevel>
        <temperature id="4">77</temperature>
    </params>
</car>
<horse>
    <params>
        <temperature id="5">123</temperature>
        <bloodPressure id="6">26</bloodPressure>
    </params>
</horse>
<plane>
    <params>
        <temperature id="7">1000</temperature>
        <altitude id="8"></altitude>
    </params>
</plane>

另一个精度:我需要将唯一的id作为int,因此我不能使用与id和数量字段相关联的键。

顺便说一下,这个论坛不允许我提出一些问候或感谢表达,这令人非常不安。

1 个答案:

答案 0 :(得分:0)

你写我想如果我使用类型派生限制而不是ref,那么唯一性约束将不再适用于所有“param”子类型。为什么你猜? (并且不会检查规范或要求验证器比猜测更有用吗?)

伪架构中的键约束适用于名为param的范围元素的所有子元素,无论其类型如何;为什么会输入限制改变?

在任何情况下,不清楚类型限制和XSD身份约束在这里有任何关联:如果你想约束一组param元素,给定元素可以指向不通过名称指向的元素,或者它在文档中的位置,但是基于所指向的quantity元素的param属性的值,你已经远远超出了基本XSD的表达能力类型构造函数,也超出了XSD身份约束的表达能力。 (此外,它的价值超出了关系数据库系统中引用完整性约束的可比性。)

XSD标识约束确保在文档中给定元素实例的范围内,在非常简单,可清晰流化的XPath 1.0子集中可识别的值或值序列的唯一性。

XSD类型定义总是被构造为允许以无上下文的方式孤立地对类型进行元素验证。没有类型级约束可以依赖于被验证的元素或属性之外的值 - 如果可以,那么将元素插入特定上下文,或者检索它并从其上下文中提取它的操作可能会改变其类型。向你最近的数据库或编程语言理论家询问他们的喜好,但要准备好在他们晕倒时抓住它们。

你的设计听起来非常糟糕,不必要,毫无意义。你几乎肯定会扔掉它并重新开始。它作为使用XML的设计并不好。

最多,它可能是一种练习,一种展示如何处理XSD情况的方法,如果你需要自己蒙上眼睛,把手放在口袋里,然后哼着Marseillaise跳一条腿而房间里的其他人则在你的耳朵里喊着达达的诗歌,并在你的脚下滑动香蕉皮。

本着这种精神,考虑以下XSD 1.1模式,该模式定义了一个符合您在散文中描述的要求的词汇表(并忽略了您的伪代码,因为我无法弄清楚它想要做什么)。

我们将元素rootparamelem001定义为elem005,将其他994定义为读者的练习。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://example.com/jacques"
  xmlns:tns="http://example.com/jacques"
  elementFormDefault="qualified"> 

  <xs:element name="root" type="tns:root">
    <xs:key name="parameter-uniqueness">
      <xs:selector xpath=".//tns:param"/>
      <xs:field xpath="@ID"/>
    </xs:key>    
  </xs:element>

如您所见,根元素强制执行param/@ID值的唯一性。

  <xs:element name="param" type="tns:param"/>
  <xs:element name="elem001" type="tns:elemNNN"/>
  <xs:element name="elem002" type="tns:elemNNN"/>
  <xs:element name="elem003" type="tns:elemNNN"/>
  <xs:element name="elem004" type="tns:elemNNN"/>
  <xs:element name="elem005" type="tns:elemNNN"/>

paramelemNNN元素不是很有趣。请注意,elem001elem005都属于同一类型。类型限制在这里不是不可能的,但它也无助于达到你想要的效果。

  <xs:complexType name="param">
    <xs:simpleContent>
      <xs:extension base="xs:double">
        <xs:attribute name="quantity" type="xs:integer"/>
        <xs:attribute name="ID" type="xs:int"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>

  <xs:complexType name="elemNNN" mixed="false">
    <xs:sequence>
      <!--* Whatever common structure we want here *-->
      <xs:any minOccurs="0" maxOccurs="unbounded" 
              processContents="lax"/>
    </xs:sequence>    
    <xs:attribute name="param" type="xs:int" use="required"/>    
    <!--* Whatever common attributes we want ... *-->
    <xs:attribute name="color"/>    
    <xs:attribute name="shape"/>
    <xs:attribute name="height"/>
    <xs:attribute name="postal-code"/>
    <!--* ... *-->
  </xs:complexType>

所有有趣的动作都是根元素的类型。它的内容模型很简单:一些参数然后是elemNNN元素:

  <xs:complexType name="root">
    <xs:sequence>
      <xs:element ref="tns:param" minOccurs="0"
                  maxOccurs="unbounded"/>      
      <xs:element ref="tns:elem001"/>  
      <xs:element ref="tns:elem002"/>  
      <xs:element ref="tns:elem003"/>  
      <xs:element ref="tns:elem004"/>  
      <xs:element ref="tns:elem005"/>
    </xs:sequence>

由于param元素位于指向元素之外,因此无法在指向元素的类型上表达给定元素可指向的param元素的约束。 (如果它们是嵌入的,正如你的伪模式似乎暗示的那样,事情将会非常不同,但是不会涉及任何指向。)所以它们必须在一些具有指向元素和参数的祖先元素的声明中表达出来。元素作为后代。在这里,我们在根元素上进行。

我们允许elem001仅指向param属性介于-323和+2387之间的quantity元素,包括:

    <xs:assert test="for $e in .//tns:elem001, 
      $pref in $e/@param,
      $p in .//tns:param[@ID = $pref],
      $q in $p/@quantity
      return 
      ($q gt -324 and $q le 2387) (: in range -323 to 2398 :) "/>

允许元素elem002仅指向其param属性为小于15的正素数的quantity元素:

    <xs:assert test="for $e in .//tns:elem002,  
      $pref in $e/@param,
      $p in .//tns:param[@ID = $pref],
      $q in $p/@quantity
      return 
      ($q  = (2, 3, 5, 7, 11, 13)) (: prime lt 15 :) "/>

elem003上的约束是其param元素的quantity值必须等于0,1,7,8,14,15 ......:

    <xs:assert test="for $e in .//tns:elem003,
      $pref in $e/@param,
      $p in .//tns:param[@ID = $pref],
      $q in $p/@quantity
      return 
      ($q mod 7 lt 2) "/>

等等。

    <xs:assert test="for $e in .//tns:elem004,  
      $pref in $e/@param,
      $p in .//tns:param[@ID = $pref],
      $q in $p/@quantity
      return  
      ($q gt 2387)  "/>

    <xs:assert test="for $e in .//tns:elem005,
      $pref in $e/@param,
      $p in .//tns:param[@ID = $pref],
      $q in $p/@quantity
      return 
      ($q le -324)

      "/>
  </xs:complexType>

</xs:schema>

此架构接受以下输入为有效;通过使指针指向具有不适当param属性的quantity,或通过更改实际指向的quantity元素上的param值,很容易使其无效到。

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://example.com/jacques jacques.xsd" 
  xmlns="http://example.com/jacques">
  <param ID="1" quantity="23">2</param>
  <param ID="14" quantity="3">876.4</param>
  <param ID="31" quantity="44423">833838</param>
  <param ID="-44" quantity="23">111</param>
  <param ID="-127" quantity="-0333">22223.33</param>
  <param ID="22" quantity="8">2</param>
  <param ID="12" quantity="23">1</param>
  <elem001 param="1">
    <p>This is some sample data.</p>
  </elem001>
  <elem002 param="14">
    <p>Just hanging around here.</p>
  </elem002>
  <elem003 param="22">
    <p>No worries.</p>
  </elem003>
  <elem004 param="31">
    <p>How you doin', bro?</p>
  </elem004>
  <elem005 param="-127">
    <p>Hasta la vista, baby.</p>
  </elem005>
</root>