动态 XML 架构验证文档的子部分



我的情况类似于"XSD与来自其他命名空间的元素",其中我有2段XML。

一段 XML 充当另一段的包装器。 在一个简单的例子中 - 我们有一个 MESSAGES 包装器,至少包含一个 MESSAGE 元素。 每个 MESSAGE 元素都包含一个 PAYLOAD,该有效负载根据 XSD 进行验证。

给定消息父级中的每个有效负载都将针对相同的 XSD 进行验证。 但是,不同的消息可以包含针对整个 XSD 主机进行验证的有效负载。 我实际上有数百个XSD来验证不同类型的PAYLOAD。

我想拥有自己的 XSD 来验证 MESSAGES 包装器的结构,然后将验证 PAYLOAD 的责任移交给我拥有的众多库存 XSD 之一,具体取决于 PAYLOAD 类型。

重要的一点是我们不能将 PAYLOAD XSD 导入到 MESSAGE XSD 中 - 因为 PAYLOAD 模式类型在 XSD 级别不是固定的。 但它在 XML 级别是固定的。

<MESSAGES>
<MESSAGE>
<RECIPIENT>Foo</RECIPIENT>
<PAYLOAD>
<!-- Large message containing many possible elements -->
</PAYLOAD>
<MESSAGE>
<MESSAGE>
<RECIPIENT>Bar</RECIPIENT>
<PAYLOAD>
<!-- Large message containing many possible elements -->
</PAYLOAD>
<MESSAGE>
</MESSAGES>

到目前为止,我注意到了两件事。 如果我在父消息级别不提供架构,我可以在 PAYLOAD 级别提供架构,这将正确验证 PAYLOAD。 但是,没有对包装器进行验证。

<MESSAGES>
<MESSAGE>
<RECIPIENT>Foo</RECIPIENT>
<PAYLOAD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.payload.org"
xsi:schemaLocation="http://www.payload.org xsd/payload-type-a.xsd">
<!-- Large message containing many possible elements -->
</PAYLOAD>
<MESSAGE>
</MESSAGES>

我也可以做相反的事情,即验证消息包装器,但忽略有效载荷,在整个XML上使用以下XSD:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.message.org">
<xs:element name="MESSAGES">
<xs:complexType>
<xs:sequence>
<xs:element name="MESSAGE" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="RECIPIENT" type="xs:string"/>
<xs:any processContents="skip"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

使用 XML:

<MESSAGES xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.messages.org"
xsi:schemaLocation="http://www.messages.org xsd/messages.xsd">
<MESSAGE>
<RECIPIENT>Foo</RECIPIENT>
<PAYLOAD>
<!-- Large message containing many possible elements -->
</PAYLOAD>
<MESSAGE>
</MESSAGES>

但我不能做的是在 XML 中组合两个XSD:

<MESSAGES xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.messages.org"
xsi:schemaLocation="http://www.messages.org xsd/messages.xsd">
<MESSAGE>
<RECIPIENT>Foo</RECIPIENT>
<PAYLOAD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.payload.org"
xsi:schemaLocation="http://www.payload.org xsd/payload-type-a.xsd">
<!-- Large message containing many possible elements -->
</PAYLOAD>
<MESSAGE>
</MESSAGES>

我对XSD很陌生,所以我可以看到我正在尝试做的事情可能不符合XML/验证的精神,但它确实让我觉得这是一件合理的事情 - 如果我是第一个反对这个的人,我会感到惊讶!

我能想到的唯一理论解决方案是让生成消息的 XSLT 动态生成 XSD 本身。 也就是说,让 XSLT(为简洁起见省略)同时输出 XML 和架构以对其进行验证。 然后我可以使用 XSD import 语句,因为 XSLT 文档到 PAYLOAD 类型是一对一的映射。

然而,这将使事情大大复杂化!

我希望有一种方法可以使用不同的架构验证XML文件的不同部分,并从XML文件本身进行控制。

任何想法都非常赞赏!

我最终得到了这个工作。 现实情况是,我认为我做错了一些小事,这意味着我绕圈子。 最终,我能够产生以下内容 - 唯一缺少的是xs:schema属性中的elementFormDefault="qualified",并且如果架构正确验证,则应strictprocessContents

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.message.org"
elementFormDefault="qualified">
<xs:element name="MESSAGES">
<xs:complexType>
<xs:sequence>
<xs:element name="MESSAGE" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="RECIPIENT" type="xs:string"/>
<xs:any processContents="strict"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

有了这个XSD,我能够使以下XML工作:

<MESSAGES xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.messages.org"
xsi:schemaLocation="http://www.messages.org xsd/messages.xsd">
<MESSAGE>
<RECIPIENT>Foo</RECIPIENT>
<PAYLOAD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.payload.org"
xsi:schemaLocation="http://www.payload.org xsd/payload-type-a.xsd">
<!-- Large message containing many possible elements -->
</PAYLOAD>
<MESSAGE>
</MESSAGES>

最后值得注意的是,您可以在 XML 顶部添加多个架构,然后通过更改xmlns来选择它们,就像上面的示例一样:

<MESSAGES xsi:schemaLocation="http://www.messages.org xsd/messages.xsd
http://www.payload.org xsd/payload.xsd>"

最新更新