我尝试使用 XSD 1.0 描述以下类型的结构:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:element name="root">
<xs:complexType>
<xs:all>
<xs:element name="A" minOccurs="1" maxOccurs="1">
<xs:element name="B" minOccurs="1" maxOccurs="1">
<xs:element name="C" minOccurs="1" maxOccurs="1">
<xs:element name="D" minOccurs="0" maxOccurs="unbounded">
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
以下最小示例文档:
<?xml version="1.0" encoding="utf-8"?>
<root><D/><D/><D/><C/><D/><D/><A/><B/><D/></root>
这不起作用,因为 XSD 1.0 不允许元素在 <xs:all>
内无限次出现。 。因为这对应于正则表达式,例如 (D*AD*BD*CD*|D*AD*CD*BD*|D*BD*AD*CD*|D*CD*AD*BD*|D*BD*CD*AD*|D*CD*BD*AD*)
,我尝试更换内部<xs:all> … </xs:all>
具有以下内容:
<xs:choice>
<xs:sequence>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="A" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="B" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="C" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:sequence>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="A" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="C" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="B" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:sequence>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="B" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="A" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="C" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:sequence>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="C" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="A" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="B" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:sequence>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="B" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="C" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="A" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:sequence>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="C" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="B" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="A" minOccurs="1" maxOccurs="1"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:choice>
但是当使用 xmllint
检查时,该工具(非常正确)提示内容模型不是确定性的。有办法吗?
最佳答案
这里我们有一些解决方案:
选项 1:让您的正则表达式解决方案成为决定论
以下是您的正则表达式转换为确定性正则表达式(请允许我使用此正则表达式滥用符号):
d*
(
ad*(bd*c|cd*b)
|
bd*(ad*c|cd*a)
|
cd*(ad*b|bd*a)
)
d*
转换为 XSD:
<xs:sequence>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:choice>
<xs:sequence>
<xs:element name="A"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:choice>
<xs:sequence>
<xs:element name="B"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="C"/>
</xs:sequence>
<xs:sequence>
<xs:element name="C"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="A"/>
</xs:sequence>
</xs:choice>
</xs:sequence>
<xs:sequence>
<xs:element name="B"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:choice>
<xs:sequence>
<xs:element name="A"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="C"/>
</xs:sequence>
<xs:sequence>
<xs:element name="C"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="A"/>
</xs:sequence>
</xs:choice>
</xs:sequence>
<xs:sequence>
<xs:element name="C"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:choice>
<xs:sequence>
<xs:element name="A"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="B"/>
</xs:sequence>
<xs:sequence>
<xs:element name="B"/>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="A"/>
</xs:sequence>
</xs:choice>
</xs:sequence>
</xs:choice>
<xs:element name="D" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
选项2:使用xs:key(仅对简单内容或简单类型有效)
键应该是唯一的、始终存在(并且不可为空)。如果 xs:key
字段选择多个值,则文档无效,因此您可以使用:
<xs:element name="root">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="A" type="xs:string"/>
<xs:element name="B" type="xs:string"/>
<xs:element name="C" type="xs:string"/>
<xs:element name="D" type="xs:string"/>
</xs:choice>
</xs:complexType>
<xs:key name="oneABC">
<xs:selector xpath="."/>
<xs:field xpath="A"/>
<xs:field xpath="B"/>
<xs:field xpath="C"/>
</xs:key>
</xs:element>
选项 3:更改 XML 模型以强制执行顺序
这不完全是一个解决方案,因为这不会验证相同的文档。如果您只接受给定的订单,这会容易得多。仅当您是定义 XML 文档实例结构的人时,这才可能实现。示例:ABCD*
<xs:sequence>
<xs:element name="A">
<xs:element name="B">
<xs:element name="C">
<xs:element name="D" minOccurs="0" maxOccurs="unbounded">
</xs:sequence>
选项 4:最佳解决方案,使用 XSD 1.1 和 xs:assert
这不是一个真正的选择,正如您所说,您需要 XSD 1.0,但以防万一有人可以使用 XSD 1.1。 使用 XSD 1.1 和 xs:assert 非常简单:
<xs:element name="root">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="A"/>
<xs:element name="B"/>
<xs:element name="C"/>
<xs:element name="D"/>
</xs:choice>
<xs:assert test="count(A)=1 and count(B)=1 and count(C)=1"/>
</xs:complexType>
</xs:element>
关于regex - 通过 XSD 1.0 描述具有不同出现范围的未排序元素组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36197964/