唯一粒子错误,希望以任何顺序允许多个子元素

时间:2017-01-23 21:10:59

标签: xml xsd xsd-validation xml-validation

我正在尝试验证项目中的一些现有XML文件。示例结构如下所示:

<resources>
    <file name="one" path="C:\test\one.txt" />
    <cache path="C:\test\cache\" />
    <file name="two" path="C:\test\two.txt" />
    <bundle name="myFolder">
        <file name="three" path="C:\test\three.txt" />
        <file name="four" path="C:\test\four.txt" />
    </bundle>
    <file name="one" path="C:\test\one.txt" />
    <bundle name="myFolder">
        <file name="three" path="C:\test\three.txt" />
        <file name="four" path="C:\test\four.txt" />
    </bundle>
    <file name="one" path="C:\test\one.txt" />
</resources>

用语言来说,我想要的是一个具有根元素resources的结构,它有子元素

  • 最多一个cache元素,按任意顺序
  • 任意数量的filebundle元素,按任意顺序
  • bundle包含任意数量的file元素

这是我当前的XSD(来自this answer):

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:complexType name="cache">
        <xs:attribute name="path" type="xs:string" />
    </xs:complexType>

    <xs:complexType name="file">
        <xs:attribute name="name" type="xs:string" />
        <xs:attribute name="path" type="xs:string" />
    </xs:complexType>

    <xs:complexType name="bundle">
        <xs:choice maxOccurs="unbounded">
            <xs:element name="file" type="file" maxOccurs="unbounded" />
        </xs:choice>
        <xs:attribute name="type" />
        <xs:attribute name="name" />
    </xs:complexType>

    <xs:group name="unboundednoncache">
        <xs:choice>
            <xs:element name="file" type="file" />
            <xs:element name="bundle" type="bundle" />
        </xs:choice>
    </xs:group>

    <xs:element name="resources">
        <xs:complexType>
            <xs:sequence>
                <!-- Validates if this next line is removed,
                and the cache element is moved to first -->
                <xs:group ref="unboundednoncache" minOccurs="0" maxOccurs="unbounded" />
                <xs:element name="cache" type="cache" minOccurs="0" maxOccurs="1" />
                <xs:group ref="unboundednoncache" minOccurs="0" maxOccurs="unbounded" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

这给了我错误:

  

Cos-nonambig:文件和文件(或来自其替换组的元素)违反&#34;独特的粒子归因&#34;。在针对此模式进行验证期间,将为这两个粒子创建歧义。

我可以获得第一个XSD来验证我是否删除了XSD中的第一个<xs:group>并将cache元素移动为XML中的第一个子元素,但我希望缓存元素是在任何地方有效。

(在此版本之前我使用:

<xs:choice maxOccurs="unbounded">
    <xs:element name="cache" type="cache" minOccurs="0" maxOccurs="1" />
    <xs:element name="file" type="file" minOccurs="0" maxOccurs="unbounded" />
    <xs:element name="bundle" type="bundle" minOccurs="0" maxOccurs="unbounded" />
</xs:choice>

..但是它允许多个缓存元素,我也不想要。)

为什么我的XSD违反了&#34;独特的粒子归因&#34;,以及如何解决?

1 个答案:

答案 0 :(得分:2)

在架构文档中,您已将resources的内容模型编写为

的等效内容
((file | bundle)*, cache?, (file | bundle)*)

这在语义上是正确的,但初始file元素可以匹配内容模型中第二次出现file的第一个元素。由于最好的理由,XSD不允许这样做。

所以你需要一个确定性的等效内容模型。并非所有非确定性内容模型都具有确定性等价物,但您的确如此:

((file | bundle)*, (cache, (file | bundle)*)?)

或者,在XSD语法中(重用unboundednoncache的定义):

<xs:group name="cache-plus-noncache">
  <xs:sequence>
    <xs:element name="cache" type="cache" 
                minOccurs="1" maxOccurs="1" />
    <xs:group ref="unboundednoncache" 
              minOccurs="0" maxOccurs="unbounded" />
  </xs:sequence>
</xs:group>

<xs:element name="resources">
  <xs:complexType>
    <xs:sequence>
      <xs:group ref="unboundednoncache" 
                minOccurs="0" maxOccurs="unbounded" />
      <xs:group ref="cache-plus-noncache" 
                minOccurs="0" maxOccurs="1" />
    </xs:sequence>
  </xs:complexType>
</xs:element>

使用工具读取内容模型,检测到违反确定性(又称“独特粒子归因”)规则,并提出确定性等价物或打破内容模型没有确定性等价物的坏消息可能会很方便。 AnneBrüggemann-Klein对这个理论进行了很清晰的研究。但到目前为止,我还没有意识到这样一种工具,而且我的定期决议一直没有结出果实。