代码之家  ›  专栏  ›  技术社区  ›  Phil

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

  •  1
  • Phil  · 技术社区  · 6 年前

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

    XML的一部分充当另一部分的包装。在一个简单的示例中,我们有一个消息包装器,其中至少包含一个消息元素。每个消息元素都包含一个根据XSD验证的有效负载。

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

    我希望有自己的XSD来验证消息包装器的结构,然后根据负载类型将验证负载的责任移交给我拥有的众多库存XSD中的一个。

    重要的一点是,我们无法将有效负载XSD导入到消息XSD中,因为有效负载模式类型在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>
         <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/验证的精神,但它确实让我觉得这是一件合理的事情——如果我是第一个遇到这种情况的人,我会感到惊讶!

    我能想到的唯一理论解决方案是让XSD本身由生成消息的XSLT动态生成。也就是说,让XSLT(为简洁起见省略)同时输出XML和模式以验证它。然后我可以使用XSD import语句,因为XSLT文档与有效负载类型之间有一个1对1的映射。

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

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

    非常感谢您的任何想法!

    1 回复  |  直到 6 年前
        1
  •  1
  •   Phil    6 年前

    我最终还是成功了。事实是,我认为我做错了一些小事情,这意味着我在无圆圈中四处走动。最终,我能够制作以下内容-唯一缺少的是 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>"