如何使用带有包含的 XSD 的 Java 验证 XML 文件?

新手上路,请多包涵

我正在使用 Java 5 javax.xml.validation.Validator 来验证 XML 文件。我已经为一个仅使用导入的模式完成了它,并且一切正常。现在我正在尝试使用另一个使用导入和一个包含的模式进行验证。我遇到的问题是主模式中的元素被忽略了,验证说它找不到它们的声明。

这是我构建架构的方式:

 InputStream includeInputStream = getClass().getClassLoader().getResource("include.xsd").openStream();
InputStream importInputStream = getClass().getClassLoader().getResource("import.xsd").openStream();
InputStream mainInputStream = getClass().getClassLoader().getResource("main.xsd").openStream();
Source[] sourceSchema = new SAXSource[]{includeInputStream , importInputStream,
mainInputStream };
Schema schema = factory.newSchema(sourceSchema);

现在这里是 main.xsd 中声明的摘录

<xsd:schema xmlns="http://schema.omg.org/spec/BPMN/2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:import="http://www.foo.com/import" targetNamespace="http://main/namespace" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xsd:import namespace="http://www.foo.com/import" schemaLocation="import.xsd"/>
    <xsd:include schemaLocation="include.xsd"/>
    <xsd:element name="element" type="tElement"/>
    <...>
</xsd:schema>

如果我在 main.xsd 中复制我包含的 XSD 的代码,它工作正常。如果我不这样做,验证就不会找到“元素”的声明。

原文由 Melanie 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 698
2 个回答

您需要使用 LSResourceResolver 才能使其正常工作。请查看下面的示例代码。

验证方法:

 // note that if your XML already declares the XSD to which it has to conform, then there's no need to declare the schemaName here
void validate(String xml, String schemaName) throws Exception {

    DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
    builderFactory.setNamespaceAware(true);

    DocumentBuilder parser = builderFactory
            .newDocumentBuilder();

    // parse the XML into a document object
    Document document = parser.parse(new StringInputStream(xml));

    SchemaFactory factory = SchemaFactory
            .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

    // associate the schema factory with the resource resolver, which is responsible for resolving the imported XSD's
    factory.setResourceResolver(new ResourceResolver());

            // note that if your XML already declares the XSD to which it has to conform, then there's no need to create a validator from a Schema object
    Source schemaFile = new StreamSource(getClass().getClassLoader()
            .getResourceAsStream(schemaName));
    Schema schema = factory.newSchema(schemaFile);

    Validator validator = schema.newValidator();
    validator.validate(new DOMSource(document));
}

资源解析器实现:

 public class ResourceResolver  implements LSResourceResolver {

public LSInput resolveResource(String type, String namespaceURI,
        String publicId, String systemId, String baseURI) {

     // note: in this sample, the XSD's are expected to be in the root of the classpath
    InputStream resourceAsStream = this.getClass().getClassLoader()
            .getResourceAsStream(systemId);
    return new Input(publicId, systemId, resourceAsStream);
}

 }

资源解析器返回的输入实现:

 public class Input implements LSInput {

private String publicId;

private String systemId;

public String getPublicId() {
    return publicId;
}

public void setPublicId(String publicId) {
    this.publicId = publicId;
}

public String getBaseURI() {
    return null;
}

public InputStream getByteStream() {
    return null;
}

public boolean getCertifiedText() {
    return false;
}

public Reader getCharacterStream() {
    return null;
}

public String getEncoding() {
    return null;
}

public String getStringData() {
    synchronized (inputStream) {
        try {
            byte[] input = new byte[inputStream.available()];
            inputStream.read(input);
            String contents = new String(input);
            return contents;
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Exception " + e);
            return null;
        }
    }
}

public void setBaseURI(String baseURI) {
}

public void setByteStream(InputStream byteStream) {
}

public void setCertifiedText(boolean certifiedText) {
}

public void setCharacterStream(Reader characterStream) {
}

public void setEncoding(String encoding) {
}

public void setStringData(String stringData) {
}

public String getSystemId() {
    return systemId;
}

public void setSystemId(String systemId) {
    this.systemId = systemId;
}

public BufferedInputStream getInputStream() {
    return inputStream;
}

public void setInputStream(BufferedInputStream inputStream) {
    this.inputStream = inputStream;
}

private BufferedInputStream inputStream;

public Input(String publicId, String sysId, InputStream input) {
    this.publicId = publicId;
    this.systemId = sysId;
    this.inputStream = new BufferedInputStream(input);
}
}

原文由 Stefan De Boey 发布,翻译遵循 CC BY-SA 2.5 许可协议

正如用户“ulab”在对另一个答案的评论中指出的那样, 这个答案 中描述的解决方案(针对一个单独的 stackoverflow 问题)将适用于许多人。这是该方法的粗略概述:

 SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
URL xsdURL = this.getResource("/xsd/my-schema.xsd");
Schema schema = schemaFactory.newSchema(xsdURL);

这种方法的关键是避免将流交给模式工厂,而是给它一个 URL。通过这种方式,它可以获得有关 XSD 文件位置的信息。

这里要记住的一件事是,当您在中使用简单文件路径时,包含和/或导入元素上的“schemaLocation”属性将被视为相对于您已将其 URL 交给验证器的 XSD 文件的类路径位置形式“my-common.xsd”或“common/some-concept.xsd”。

注意: - 在上面的示例中,我将模式文件放入“xsd”文件夹下的 jar 文件中。 - “getResource”参数中的前导斜杠告诉 Java 从类加载器的根目录开始,而不是从“this”对象的包名开始。

原文由 Gordon Daugherty 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题