如何在XML模式中实现这一点?

时间:2010-01-15 15:00:09

标签: xsd

这是我想要的XML:

<root>
    <A>
        <C>asd</C>
        <D>asd</D>
        <E>asd</E>
    </A>
    <B>
        <C>asd</C>
        <D>asd</D>
        <E>asd</E>
        <F>asd</F>
    </B>
</root>

以下是一些限制:

  • 任何顺序都可以有多个A和B元素。
  • A和B具有完全相同的内容,但B也可以包含元素F;
  • C,D,E和F可以按任何顺序出现。
  • E可以多次出现;
  • C和D可以出现0或1次;
  • F必须恰好出现一次

这可能吗?并且在旁注 - 为什么XML模式在定义这样的简单场景时如此尴尬?

3 个答案:

答案 0 :(得分:0)

这解决了大部分条件,但是更难的是允许任何订单部分。由于您正在处理复杂类型,因此主要用法是Sequence命令。还有其他一些,但它们也不适用于您的场景。此外,虽然从纯xml的角度来看这似乎很简单,但它不是从验证的角度来看。需要注意的主要事项是,构建此doc的方式必须先将所有<A>条记录放在第一位,将所有<B>条记录放在第二位。以下是一些架构数据的链接:w3schools

可能有一些更复杂的方法可以做你想要的事情,但这至少为你提供了基本模式。

<xs:schema
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
     elementFormDefault="qualified" attributeFormDefault="unqualified">

<xs:complexType name="Avalue">
  <xs:sequence>
    <xs:element minOccurs="0" maxOccurs="1" name="C" type="xs:string"/>
    <xs:element minOccurs="0" maxOccurs="1" name="D" type="xs:string"/>
    <xs:element minOccurs="0" maxOccurs="unbounded" name="E" type="xs:string"/>
  </xs:sequence>
</xs:complexType>


<xs:complexType name="Bvalue">
  <xs:sequence>
    <xs:element minOccurs="0" maxOccurs="1" name="C" type="xs:string"/>
    <xs:element minOccurs="0" maxOccurs="1" name="D" type="xs:string"/>
    <xs:element minOccurs="0" maxOccurs="unbounded" name="E" type="xs:string"/>
    <xs:element minOccurs="1" maxOccurs="1" name="F" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

<xs:element name="root">
  <xs:complexType>
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="unbounded" name="A" type="Avalue"/>
      <xs:element minOccurs="0" maxOccurs="unbounded" name="B" type="Bvalue"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

</xs:schema>

答案 1 :(得分:0)

如果您只是在寻找代码完成(正如您在评论中提到的那样),那么只需将每种类型定义为可能的子代的无限选择。例如,对于B:

  <xs:choice minOccurs="0" maxOccurs="unbounded">
    <xs:element name="C" type="xs:string"/>
    <xs:element name="D" type="xs:string"/>
    <xs:element name="E" type="xs:string"/>
    <xs:element name="F" type="xs:string"/>
  </xs:choice>
  

并且旁注 - 为什么XML模式在定义这样的简单场景时如此尴尬?

部分原因是稀疏的XML / DTD通过将功能保持在最低限度并且对简单处理器友好而击败了丰富的SGML / DTD。因此,XML Schema希望与SGML保持更接近的XML。

答案 2 :(得分:0)

如果C,D,E和F孩子的顺序没有传达任何信息,那么实际上很容易为他们指定一个固定的顺序,正如OP在另一个答案的评论中所建议的那样。

在XSD 1.0中,允许C,D和E以指定基数约束的任何顺序出现,需要相当冗长的内容模型。使用正则表达式语法(并允许空格易读),A的内容模型将是

(C ((DE+)|(E+(DE*)?)) )
|
(D ((CE+)|(E+(CE*)?)) )
|
(E+ ((DE*(CE*)?)|(CE*(DE*)?))? )

由于B的内容模型为语言的有限状态自动机中的每个状态必须携带的信息量增加了一位(即“我们看过F还没有吗?”),这不足为奇了最小FSA的大小,使内容模型更大:

C ( (D ((E+FE*)|(FE+)) )
  | (E+ ((DE*FE*)|(FE*(DE*)?)))
  | (F ((DE+)|(E+DE*)))
  )    
D ( (C ((E+FE*)|(FE+)))
  | (E+ ((CE*FE*)|(FE*(CE*)?)))
  | (F ((CE+)|(E+CE*)))
  )    
E+ ( (CE* ((DE*FE*)|(FE*(DE*)?)))
  |  (DE* ((CE*FE*)|(FE*(CE*)?)))
  |  (FE* ((CE*(DE*)?)|(DE*(CE*)?))?)
  )    
F ( (C ((DE+)|(E+DE*)))
  | (D ((CE+)|(E+CE*)))
  | (E+ ((CE*(DE*)?)|(DE*(CE*)?))?) 
  )

这有点单调乏味,但它肯定是合法的XSD 1.0,并且它捕获了OP描述的约束;因此,它表明,XSD 1.0无法捕获约束是错误的。可以声称的最多是在XSD 1.0中不可能简洁地捕获OP的要求。这是XSD 1.0内容模型的属性与DTD内容模型,正则表达式以及XSD 1.0内容模型所基于的无上下文语法的常规符号共享。

其他模式语言可以更简洁地处理这个问题:在Relax NG中,交错运算符使得编码此类约束变得相对简单。在XSD 1.1中,放宽对all组的约束使得捕获要求变得非常简单:

<xs:complexType name="CDE">
  <xs:all>
    <xs:element ref="C" minOccurs="0" maxOccurs="1"/>
    <xs:element ref="D" minOccurs="0" maxOccurs="1"/>
    <xs:element ref="E" minOccurs="1" maxOccurs="unbounded"/>
  </xs:all>
</xs:complexType>

<xs:complexType name="CDEF">
  <xs:complexContent>
    <xs:extension base="CDE">
      <xs:all>
        <xs:element ref="F" minOccurs="1" maxOccurs="1"/>
      </xs:all>
    </xs:extension>
  </xs:complexContent>
</xs:complexType> 

这确实使验证器的工作复杂化(以最简单的方式放置:它意味着验证器作者不能使用标准的教科书算法,因为标准教科书不包括交错运算符),但是对于许多词汇设计者来说,无论好坏即使在订单没有传达任何信息而且不需要不受约束的情况下,也不愿限制秩序。