【问题标题】:Java XSD validation depends on order XSDs are providedJava XSD 验证取决于提供 XSD 的顺序
【发布时间】:2020-07-28 05:48:50
【问题描述】:

给定两个 XSD 架构文件:

a.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:include schemaLocation="b.xsd"/>
    <xs:element name="TestMessage">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="TestSubItem"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

b.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="TestSubItem">
        <xs:complexType>
            <xs:attribute name="name" use="required">
                <xs:simpleType>
                    <xs:restriction base="xs:string">
                        <xs:enumeration value="test"/>
                    </xs:restriction>
                </xs:simpleType>
            </xs:attribute>
        </xs:complexType>
    </xs:element>
</xs:schema>

以下 java 代码成功验证了架构:

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.xml.XMLConstants;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.commons.io.FileUtils;
import org.xml.sax.SAXException;

try
{
    String xsdDirectory = "C:\\XSDFiles";
    String xmlString = "<TestMessage xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> <TestSubItem name=\"test\"/> </TestMessage>";

     Collection<File> xsdFiles = FileUtils.listFiles(new File(xsdDirectory), new String[] { "xsd", "XSD" }, false);
    List<Source> sourceList = new ArrayList<>();
    for (File xsdFile: xsdFiles) {
        sourceList.add(new StreamSource(xsdFile));
    }
    SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

    // 0 then 1, so add a.xsd then b.xsd (alphabetical)
    Schema schema = factory.newSchema(new Source[] {sourceList.get(0), sourceList.get(1)});
    Validator validator = schema.newValidator();
    validator.validate(new StreamSource(new StringReader(xmlString)));
    System.out.println("valid");
}
catch (SAXException e)
{
    System.out.println(e.toString());
}

但是,如果您交换模式添加到 Source 数组的顺序,那么 XSD 会以相反的顺序添加(b 在 a 之前):

Schema schema = factory.newSchema(new Source[] {sourceList.get(1), sourceList.get(0)});

然后你会得到以下异常:

org.xml.sax.SAXParseException;行号:1;列号:68; cvc-elt.1.a:找不到元素“TestMessage”的声明。

这很好,因为这是一个任意示例 - 但如果我从目录加载文件并且不知道“正确的排序顺序”,那么我如何获取代码来查找根元素跨越所有文件,而不仅仅是找到的第一个文件?

【问题讨论】:

    标签: java xml validation xsd


    【解决方案1】:

    newSchema(Source[] schemas)的Javadoc:

    解析器可以选择忽略给定命名空间的除第一个 &lt;import&gt; 之外的所有内容

    阅读 javadoc 中的完整描述以获取更多上下文信息。

    所以只使用列出的第一个文件。

    因为a.xsd 有一个&lt;xs:include&gt; 对应b.xsd,所以当a.xsd 是第一个时,它们都会被加载。

    如果b.xsd是第一个,那么只有b.xsd被加载,这意味着&lt;xs:element name="TestMessage"&gt;丢失,因此错误。

    【讨论】:

    • 感谢您的解释。有没有办法强制它使用所有提供的导入?
    • 不可以,因为不允许同一命名空间有多个不同的架构文件。命名空间和 XSD 文件之间存在一对一的关系(不考虑版本控制)。这就是为什么解析器会忽略同一命名空间的辅助导入,即使它们引用不同的 XSD 文件,因为它们可以安全地假设其他文件具有相同的内容。请参阅 XML 模式规范中的规则 1.2 here
    猜你喜欢
    • 1970-01-01
    • 2010-09-24
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-18
    相关资源
    最近更新 更多