xmllint:根据两个XSD模式(信封/有效载荷)验证XML文件。

22

我正在使用xmllint进行一些验证工作,我有一个XML实例文档需要根据两个模式进行验证:一个用于外部“信封”(其中包括一个任意的元素),另一个用于特定的有效负载。假设A.xsd是信封模式,B.xsd是有效负载模式(有不同的可能有效负载),ab.xml是有效的XML实例文档(我在帖子末尾提供了一个示例)。

我有三个文件都在同一个目录下,并使用xmllint执行验证,将外部(信封)模式的位置作为schema参数提供:

xmllint -schema A.xsd ab.xml

虽然我在实例文档中使用 xsi:schemaLocation 元素提供了 A.xsd 和 B.xsd 的位置,但 xmllint 仍无法找到它并抱怨:

ab.xml:8: element person: Schemas validity error : Element '{http://www.example.org/B}person': No matching global element declaration available, but demanded by the strict wildcard.
ab.xml fails to validate

显然,xmllint无法读取xsi:schemaLocation元素。我知道可以使用目录来配置xmllint,但我未能让xmllint找到两个模式。当验证实例文档时,我该如何使xmllint考虑到这两个模式?或者是否有其他命令行实用程序或图形工具可以代替使用?

SSCCE

A.xsd - 信封模式

<?xml version="1.0" encoding="UTF-8"?>
<schema elementFormDefault="qualified" 
        xmlns               ="http://www.w3.org/2001/XMLSchema"
        xmlns:a             ="http://www.example.org/A"
        targetNamespace ="http://www.example.org/A">

       <element name="someType" type="a:SomeType"></element>

        <complexType name="SomeType">
            <sequence>
                <any namespace="##other" processContents="strict"/>
            </sequence>
        </complexType>
</schema>

B.xsd - 负载模式

<?xml version="1.0" encoding="UTF-8"?>
<schema elementFormDefault="qualified"
    xmlns          ="http://www.w3.org/2001/XMLSchema"
    xmlns:b        ="http://www.example.org/B"
    targetNamespace="http://www.example.org/B"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <element name="person" type="b:PersonType"></element>
    <complexType name="PersonType">
        <sequence>
                <element name="firstName" type="string"/>
                <element name="lastName"  type="string"/>
        </sequence>
    </complexType>
  </schema>

ab.xml - 实例文档

<?xml version="1.0" encoding="UTF-8"?>
<a:someType xmlns:a="http://www.example.org/A"
        xmlns:b="http://www.example.org/B"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.example.org/A A.xsd
                            http://www.example.org/B B.xsd">

            <b:person>
                <b:firstName>Mary</b:firstName>
                <b:lastName>Bones</b:lastName>
            </b:person>

</a:someType>
3个回答

13

你可以创建一个包装架构并导入两个命名空间。AB.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<schema elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema">
    <import namespace="http://www.example.org/A" schemaLocation="A.xsd"/>
    <import namespace="http://www.example.org/B" schemaLocation="B.xsd"/>
</schema>

然后:

xmllint --schema AB.xsd ab.xml
<?xml version="1.0" encoding="UTF-8"?>
<a:someType xmlns:a="http://www.example.org/A" xmlns:b="http://www.example.org/B" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/A A.xsd                             http://www.example.org/B B.xsd">

            <b:person>
                <b:firstName>Mary</b:firstName>
                <b:lastName>Bones</b:lastName>
            </b:person>

</a:someType>
ab.xml validates

1
我喜欢这个答案,因为它允许我使用已经安装在任何地方的xmllint,而不需要更改XML或现有的模式文件。 - jnichols959

12

我放弃使用 xmllint,转而使用 Xerces

我下载了 Xerces tarball,并将其解压到本地文件夹后,基于这个建议(原链接已失效,来自网络档案馆)创建了以下validate脚本:

#!/bin/bash
XERCES_HOME=~/software-downloads/xerces-2_11_0/
echo $XERCES_HOME
java -classpath $XERCES_HOME/xercesImpl.jar:$XERCES_HOME/xml-apis.jar:$XERCES_HOME/xercesSamples.jar sax.Counter $*

接下来使用以下命令针对两个模式验证ab.xml文件:

 validate -v -n -np -s -f ab.xml

Xerces会从xsi:schemaLocation元素中读取ab.xml中的模式位置,因此不需要在命令行调用中提供它们。


这个XML文件已经通过验证,但是没有通过XSDs的验证。无论如何,以下是上述损坏链接的存档版本:http://web.archive.org/web/20120827060501/http://www.diggsml.com/using-xerces-j-parse-and-validate-xml-files - user323094
@user323094 它确定验证了XML格式的正确性和XSD句法的有效性。我在发布时尝试过它,现在在你的评论后我又尝试了一遍。例如,如果您在XML文件中将<b:firstName>Mary</b:firstName>重命名为<b:firstName3>Mary</b:firstName3>,则XML仍然是格式良好的,但不再是XSD有效的。脚本将准确地发现这一点:[Error] ab.xml:9:23: cvc-complex-type.2.4.a: Invalid content was found starting with element 'b:firstName3'. One of '{"http://www.example.org/B":firstName}' is expected. - Marcus Junius Brutus
你说得对,它通常会检查XSD。我刚刚对我的XML文件的根元素进行了这样的更改(xmllint捕获但xerces没有)。我现在尝试在同一文件中使用属性,错误被正确报告。我正在使用libxerces2-java 2.11.0-7。我想我会继续使用xmlllint。 - user323094
我收到/tmp/xerces/[致命错误]:-1:-1:文件过早结束。似乎xerces得到了一个空文件,但XML并不为空。不确定如何调试此问题。Xerces 2.12.0 - user323094

5
如果在打开schema标签后,您的A.xsd文件中有一个import元素。
<xsd:import namespace="http://www.example.org/B" schemaLocation="B.xsd"/>

你可以将A.xsd传递给xmllint,然后它就能正常工作:

xmllint -schema A.xsd ab.xml

我并不想修改模式。A.xsd是“信封”模式,因此对于各种有效载荷的可能模式(其中B.xsd只是一种可能性)是不可知的。 - Marcus Junius Brutus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接