<?xml version="1.0" encoding="utf-8"?> <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="User"> <xs:complexType> <xs:sequence> <xs:element name="GivenName" /> <xs:element name="SurName" /> </xs:sequence> <xs:attribute name="ID" type="xs:unsignedByte" use="required" /> </xs:complexType> </xs:element> </xs:schema>
定义此文档的模式
<?xml version="1.0" encoding="utf-8" ?> <User ID="1"> <GivenName></GivenName> <SurName></SurName> </User>
如果您添加了另一个元素(例如EmailAddress)并混淆顺序,则无法验证
<?xml version="1.0" encoding="utf-8" ?> <User ID="1"> <SurName></SurName> <EmailAddress></EmailAddress> <GivenName></GivenName> </User>
我不想添加EmailAddress到文档,并将其标记为可选。
我只想要一个XSD来验证文档必须满足的最低要求。
有没有办法做到这一点?
编辑:
marc_s指出下面你可以使用xs:any里面的xs:sequence来允许更多的元素,不幸的是,你必须保持元素的顺序。
或者,我可以使用xs:all不强制元素的顺序,但唉,不允许我放置xs:any里面。
违反非确定性内容模型
你已经谈到了W3C XML Schema的灵魂。你所要求的 – 可变顺序和可变的未知元素 – 违反XSD的最难的,最基本的原则,非歧义的规则,或者更正式地,Unique Particle Attribution Constraint:
A content model must be formed such
that during validation [..] each item
in the sequence can be uniquely
determined without examining the
content or attributes of that item,
and without any information about the
items in the remainder of the
sequence.
在正常的英语中:当XML被验证并且XSD处理器遇到< SurName>它必须能够验证它而不首先检查它是否后面跟着< GivenName> ;,即,没有前瞻。在你的场景中,这是不可能的。这个规则允许通过有限状态机实现,这应该使实现更简单和快速。 这是最争议的问题之一,并且是SGML和DTD(内容模型必须是确定性的)和XML的遗产,其默认地定义元素的顺序是重要的(因此,尝试相反,使顺序不重要,很难)。 正如Marc_s已经提出的,Relax_NG是一种允许非确定性内容模型的替代方法。但是,如果你坚持使用W3C XML Schema,你能做什么? 非工作半有效解决方案 你已经注意到xs:all是非常限制性的。原因很简单:应用相同的非确定性规则,这就是为什么xs:any,min / maxOccurs大于1,不允许序列。 此外,你可能已经尝试过各种选择,序列和任何组合。 Microsoft XSD处理器在遇到此类无效情况时抛出的错误是:
Error: Multiple definition of element
‘07001’
causes the content model to become
ambiguous. A content model must be
formed such that during validation of
an element information item sequence,
the particle contained directly,
indirectly or implicitly therein with
which to attempt to validate each item
in the sequence in turn can be
uniquely determined without examining
the content or attributes of that
item,and without any information
about the items in the remainder of
the sequence.
在O’Reilly’s XML Schema(是的,这本书有它的缺点)这是极好的解释。幸运的是,这部分书可以在线获得。我强烈建议你阅读section 7.4.1.3 about the Unique Particle Attribution Rule,他们的解释和例子比我能得到它们更清晰。
一个工作解决方案
在大多数情况下,可以从不确定性设计转向确定性设计。这通常看起来不漂亮,但它是一个解决方案,如果你必须坚持使用W3C XML Schema和/或如果你绝对必须允许非严格的规则到你的XML。你的情况的噩梦是,你想强制执行一个事情(2个预定义的元素),同时希望它非常松散(顺序无所谓,任何事情之间,之前和之后)。如果我不尝试给你良好的建议,但只是直接带你到一个解决方案,它将看起来如下:
<xs:element name="User"> <xs:complexType> <xs:sequence> <xs:any minOccurs="0" processContents="lax" namespace="##other" /> <xs:choice> <xs:sequence> <xs:element name="GivenName" /> <xs:any minOccurs="0" processContents="lax" namespace="##other" /> <xs:element name="SurName" /> </xs:sequence> <xs:sequence> <xs:element name="SurName" /> <xs:any minOccurs="0" processContents="lax" namespace="##other" /> <xs:element name="GivenName" /> </xs:sequence> </xs:choice> <xs:any minOccurs="0" processContents="lax" namespace="##any" /> </xs:sequence> <xs:attribute name="ID" type="xs:unsignedByte" use="required" /> </xs:complexType> </xs:element>
上面的代码实际上只是工作。但有一些注意事项。第一个是xs:any,以## other作为其命名空间。你不能使用## any,除了最后一个,因为这将允许像GivenName这样的元素被使用的替代,这意味着User的定义变得模糊。
第二个警告是,如果你想使用这个技巧有两个或三个,你必须写下所有的组合。维修噩梦。这就是为什么我想出了以下:
更改您的定义。这具有为您的读者或用户更清晰的优点。它还具有变得更容易维护的优点。一整串解决方案are explained on XFront here,一个较不可读的链接,你可能已经从Oleg的帖子看到。这是一个很好的阅读,但大部分它没有考虑到你在变量内容容器中有两个元素的最低要求。
当前最适用于您情况的方法(比您想象的更频繁)是在必需和非必需字段之间分割数据。您可以添加元素< required>,或者相反,添加元素< ExtendedInfo> (或称为Properties,或OptionalData)。这看起来如下:
<xs:element name="User2"> <xs:complexType> <xs:sequence> <xs:element name="GivenName" /> <xs:element name="SurName" /> <xs:element name="ExtendedInfo" minOccurs="0"> <xs:complexType> <xs:sequence> <xs:any minOccurs="0" maxOccurs="unbounded" processContents="lax" namespace="##any" /> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element>
这可能看起来不太理想,但让它增长一点。有一个有序的固定元素集不是那么大。你不是唯一一个会抱怨W3C XML Schema的这个明显缺陷的人,但正如我之前所说,如果你必须使用它,你必须忍受它的局限性,或者接受开发负担围绕这些限制在更高的拥有成本。
替代解决方案
我相信你已经知道这一点,但属性的顺序是默认未确定的。如果所有内容都是简单类型,您也可以选择更丰富地使用属性。
最后一句话
无论你采取什么方法,你将失去你的数据的许多可验证性。通常最好允许内容提供商添加内容类型,但只有在可以验证时。这可以通过从lax切换到严格的处理,并通过使类型本身更严格。但是过于严格也不好,正确的平衡将取决于你判断你的使用案例的能力,并且权衡这些与某些实施策略的权衡。