仅使用 XML 模式无法完成所需的验证。
根据“XML 模式第 1 部分:结构”规范 http://www.w3.org/TR/xmlschema-1/#Model_Group_details ...
当模型组的 {article} 中直接或间接包含的两个或多个粒子具有相同名称的元素声明时
作为它们的 {term},这些声明的类型定义必须是
相同的。
这并不是说您无法构建可以验证正确文档的模式。这意味着,您无法构建无法验证某些不正确文档的模式。当我说“不正确”时,我指的是违反您用英语规定的限制的文件。
例如,假设您有一个包含三个 Street 元素的文档,如下所示:
<Address Field="Street" Value="123 Main"/>
<Address Field="Street" Value="456 Main"/>
<Address Field="Street" Value="789 Main"/>
<Address Field="SomeOtherCrazyValue" Value="Foo"/>
根据您的架构,该文档是一个有效的地址。可以添加一个xs:独特的 http://msdn.microsoft.com/en-us/library/ms256146.aspx对您的架构进行约束,以便它拒绝此类损坏的文档。但即使使用 xs:unique,针对这样的模式进行验证也会声明其他一些不正确的文档是有效的 - 例如包含三个的文档<Address>
元素,每个元素都有独特的Field
属性,但没有一个具有Field="Zip"
.
事实上,不可能生成一个 W3C XML 模式来正式编码您所声明的约束。这<xs:all> http://msdn.microsoft.com/en-us/library/ms256182.aspx元素almost可以让你做到这一点,但它仅适用于元素,不适用于属性。而且,它不能与扩展一起使用,因此在 W3C XML Schema 中,您不能说“所有这些元素以任何顺序排列,加上任何其他元素”。
为了执行您寻求的验证,您的选择是:
- 依赖于 XML Schema 以外的东西,
- 分多个步骤执行验证,第一步使用 XML 模式,第二步使用其他内容。
对于第一个选项,我认为你可以使用 Relax NG 来做到这一点。其缺点是,它不是一个标准,据我所知,它既没有得到广泛支持,也没有得到广泛发展。这就像学习盖尔语是为了表达思想一样。盖尔语没有什么问题,但它有点像语言的死胡同,而且我认为RelaxNG也是如此 https://stackoverflow.com/questions/2113137/is-there-a-relaxer-for-net-is-relaxer-alive-is-relaxng-viable.
对于第二个选项,一种方法是第一步验证您的架构,然后第二步:
A. 应用 XSL 转换来转换<Address>
元素转换为以其 Field 属性值命名的元素。该转换的输出如下所示:
<root>
<Street Value="101 Bellavista Drive"/>
<State Value="Confusion"/>
<Zip Value="10101"/>
</root>
B. 根据不同的模式验证该转换的输出,如下所示:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:element name="root">
<xs:complexType>
<xs:all>
<xs:element maxOccurs="1" minOccurs="1" ref="Street" />
<xs:element maxOccurs="1" minOccurs="1" ref="State" />
<xs:element maxOccurs="1" minOccurs="1" ref="Zip" />
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="Street">
<xs:complexType>
<xs:attribute name="Value" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="State">
<xs:complexType>
<xs:attribute name="Value" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="Zip">
<xs:complexType>
<xs:attribute name="Value" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:schema>
您需要扩展该架构来处理其他元素,例如<SomeOtherCrazyValue>
在变换的输出中。或者,您可以构造 xsl 转换,以不发出不属于 {State,Street,Zip} 之一的元素。
需要澄清的是,我知道您无法更改收到的 XML。这种方法不需要这样做。它只是使用了一种时髦的两步验证方法。第二个验证步骤完成后,您可以丢弃转换结果。
EDIT- 实际上,Sean,再考虑一下,您可以使用步骤 B。假设您的 XSL 转换只是Removes仅来自文档<Address>
Field 属性值不包含 State、Street 或 Zip 的元素。换句话说,就不会有<Address Field="SomeOtherCrazyValue"...>
。该转换的结果可以使用 maxOccurs="3"、minOccurs="3" 和 xs:unique 通过您的架构进行验证。