如何将这种不确定的XML Schema重写为确定性?

时间:2009-12-23 13:52:28

标签: xsd ambiguity deterministic

为什么这是不确定的以及如何解决它?

 <xs:element name="activeyears">
        <xs:complexType>
            <xs:sequence minOccurs="0" maxOccurs="1">
                <xs:sequence minOccurs="0" maxOccurs="unbounded">
                    <xs:element ref="from" minOccurs="1" maxOccurs="1"/>
                    <xs:element ref="till" minOccurs="1" maxOccurs="1"/>
                </xs:sequence>
                <xs:element ref="from" minOccurs="0" maxOccurs="1"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

这应该是指<activeyears>为空或包含<from><till>的序列,该序列以<from>开头,但可以以其中任何一个结尾。

2 个答案:

答案 0 :(得分:7)

当有两个以相同元素开头的分支时,模式是非确定性的 - 因此,如果不在该元素之后向前看,则无法分辨哪个分支。一个简单的示例是ab|ac - 当您看到a时,您不知道要采用哪个分支。对于循环,“分支”是重复循环,还是继续循环。一个例子是a*a - 一旦你进入循环,你读了一个a,你不知道是重复循环,还是继续。

查看您的示例模式,假设它刚刚解析了<till>,现在需要解析<from>。您可以使用<from><till>循环解析最终<from>。您只能通过查看<from>来判断使用哪个分支。你只能进一步展望未来。


坏消息:我认为您的示例架构非常罕见,确定性地表达不可能

以下是您要接受的XML文档(我为每个元素使用一个字母,其中a = <from>...</from>b = <to>...</to>:< / p>

*empty*
a
ab
aba
abab
ababa
ababab
...

...你明白了。问题是任何字母都可以是序列中的最后一个字母,它可以是循环的一部分。没有办法告诉它会是什么,除非通过查看以下信件。由于“确定性”意味着你没有这样做(根据定义),你想要的语言无法确定性地表达。

简化您的架构,它会尝试类似于(ab)*a?的方法 - 但两个分支都以a开头。另一种方法是a(ba)*b? - 现在两个分支都以b开头。我们不能赢!

从技术上讲,架构将接受的所有文档集称为架构的语言。如果不存在可以表达语言的确定性模式,则语言称为“一个模糊的”。

有关理论讨论,请参阅Bruggemann-Klein撰写的一系列论文(例如 Deterministic Regular Languages One-Unambiguous Regular Languages )。 她包括对一种明确的语言的正式测试。

答案 1 :(得分:0)

这是对代码的简单编辑;我没有尝试过:

 <xs:element name="activeyears">
        <xs:complexType>
            <xs:sequence minOccurs="0" maxOccurs="1">
                <xs:element ref="from" minOccurs="1" maxOccurs="1"/>
                <xs:sequence minOccurs="0" maxOccurs="unbounded">
                    <xs:element ref="till" minOccurs="1" maxOccurs="1"/>
                    <xs:element ref="from" minOccurs="0" maxOccurs="1"/>
                </xs:sequence>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

一些背景知识:XML模式是一种非常简单的语法,模式处理器是一种解析器,它尝试将此语法的规则应用于输入文件。然而,与传统编译器使用的解析器不同,XML模式没有前瞻性。因此,您不能拥有两个共享相同初始令牌集(规则名称)的规则。

所以,我做了具体的改变:

  • 我把你的外sequence保持不变;它控制“空或具有特定内容”的要求。
  • 如果有内容,则必须以“from”开头;所以我做了序列中的第一个element,显式出现次数
  • 由于我使用“from”作为显式元素,我不得不颠倒子序列的顺序。
  • 除非您想指定每个“until”必须后跟“from”,否则您需要放松子序列中的minOccurs
  • 子序列还处理单个from / until的情况 - 正如评论者指出的那样,我使用minOccurs='0'进行的第二次编辑允许两个“直到”的终止序列。