动态XML模式验证文档的子部分

时间:2018-03-08 14:03:07

标签: xml xsd xsd-validation xml-validation

我的情况类似于“XSD with elements from other namespace”,其中我有2个XML。

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

给定MESSAGES父级中的每个PAYLOAD将针对相同的XSD进行验证。但是,不同的MESSAGES可以包含针对整个XSD进行验证的PAYLOAD。我确实有数百个XSD来验证不同类型的PAYLOAD。

我希望拥有自己的XSD来验证MESSAGES包装器的结构,然后根据PAYLOAD类型,将PAYLOAD验证到我拥有的许多库存XSD之一的负责人。

重要的是我们无法将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>

到目前为止,我注意到了两件事。如果我在父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>

我也可以反过来,即验证MESSAGES包装器,但忽略PAYLOAD,在整个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 /验证的精神,但它确实让我觉得这是一个合理的想法 - 我如果我是第一个提出反对意见的人,我会感到惊讶!

我能想到的唯一理论解决方案是让XSD本身由生成MESSAGES的XSLT动态生成。也就是说,使用XSLT(为简洁起见省略),输出XML和Schema来验证它。然后我可以使用XSD import语句,因为XSLT文档与PAYLOAD类型之间存在一对一的映射。

然而,这会使事情变得非常复杂!

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

任何想法都非常有用!

1 个答案:

答案 0 :(得分:1)

我最终得到了这个。现实情况是,我认为我做了一些小错误的事情,这意味着我无所事事。最终我能够生成以下内容 - 唯一缺少的是elementFormDefault="qualified"属性中的xs:schema,如果模式正确验证,则processContents应为strict

<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>"