针对 XSD 的 Java XML 验证在第一次错误时失败,即使使用自定义错误处理程序也无法验证完整的 XML

Java XML validation against XSD fails at first error does not validate complete XML even with custom error handler

提问人:BATMAN_2008 提问时间:12/13/2022 最后编辑:BATMAN_2008 更新时间:12/13/2022 访问量:258

问:

有没有办法完全针对我的 XSD 验证我的 XML,这意味着我希望文件即使在发现错误后也能继续验证,以便我可以获得完整的错误消息,而不仅仅是 1 条或第一条错误消息?

目前,执行在发现第一个错误并打印它时停止,并且不再继续。我想知道是否有可能实现这一目标。我尝试了这里提到的方法并做了同样的事情,但它仍然没有按预期工作并且执行停止。

以下是我拥有的代码:XsdErrorHandler.class

import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXParseException;

public class XsdErrorHandler implements ErrorHandler {
   @lombok.Getter
    private java.util.List<SAXParseException> exceptions;

    public XsdErrorHandler() {
        this.exceptions = new java.util.ArrayList<>();
    }

    @Override
    public void warning(final SAXParseException exception) throws org.xml.sax.SAXException {
       handleError(exception);
    }

    @Override
    public void error(final SAXParseException exception) throws org.xml.sax.SAXException {
        handleError(exception);
    }

    @Override
    public void fatalError(final SAXParseException exception) throws org.xml.sax.SAXException  {
        handleError(exception);
    }

    public void handleError(SAXParseException e) throws org.xml.sax.SAXException  {
        // Do nothing. This will allow the validation to continue even if there are errors.
        this.exceptions.add(e);
    }
}

以下是我的架构验证器:Main.class

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 java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestMain {
    public static void main(String[] args) throws SAXException, IOException {
        final String xsdPath = "/xsd/myXSD.xsd";
        final String xmlPath = "/myXml.xml";
        listParsingExceptions(xsdPath, xmlPath);
    }

    private static Validator initValidator(final String xsdPath) throws SAXException {
        final SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        final Source schemaFile = new StreamSource(TestMain.class.getResourceAsStream(xsdPath));
        final Schema schema = factory.newSchema(schemaFile);
        return schema.newValidator();
    }

    public static List<SAXParseException> listParsingExceptions(final String xsdPath, final String xmlPath) throws IOException, SAXException {
        final InputStream inputStream = TestMain.class.getResourceAsStream(xmlPath);
        final XsdErrorHandler xsdErrorHandler = new XsdErrorHandler();
        final Validator validator = initValidator(xsdPath);
        validator.setErrorHandler(xsdErrorHandler);

        try {
            validator.validate(new StreamSource(inputStream));
        } catch (SAXParseException e)
        {
            // ...
        }

        System.out.println("ERRORS : ");
        xsdErrorHandler.getExceptions().forEach(e -> System.out.println(e.getMessage()));
        return xsdErrorHandler.getExceptions();
    }
}

问题:

  1. 我对我还需要做些什么才能让它继续工作有点困惑。有人可以提供一些建议吗?

  2. 此外,我的 XSD 包含许多对其他 XSD 的导入和引用。当我给出一个相对路径时,它不会起作用,但是当我给出一个绝对路径时,它就会起作用。有没有办法让它与相对路径一起工作?

以下失败:

<xsd:import namespace="urn:global:xsd:1" schemaLocation="./global.xsd"/>

以下作品:


<xsd:import namespace="urn:global:xsd:1" schemaLocation="/Users/username/project/validation/src/main/resources/xsd/global.xsd"/>

我试图使用这样的东西提供XSD文件的路径,但这对我也不起作用maven-jaxb2-plugin

    <build>
        <plugins>
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.14.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <schemaDirectory>${basedir}/src/main/resources/xsd</schemaDirectory>
                </configuration>
            </plugin>
        </plugins>
    </build>

我试图通过引用这里来编写我自己的,并添加到我的使用中,但这对我也没有用。ClasspathResourceResolverschemaFactoryschemaFactory.setResourceResolver(new ClasspathResourceResolver());

我的所有文件都存在于 XSD 文件夹中,我想使用类似这样的相对路径进行引用./xsdName.xsd

Java XSD XML 解析 saxparser

评论

0赞 Simon Martinelli 12/13/2022
您是否尝试过这样指定它?schemaLocation=“global.xsd”
0赞 BATMAN_2008 12/13/2022
@SimonMartinelli 感谢您的回复。是的,我试过了,即使这对我不起作用,所以我发现我们需要提供我们自己的解析器,也尝试了,这也对我不起作用。我什至试图为我所有的 XSD 文件提供一个路径,即使它对我不起作用。<xsd:import namespace="urn:global:xsd:1" schemaLocation="global.xsd"/>schemaFactory.setResourceResolver()maven-jaxb2-plugin
0赞 Martin Honnen 12/14/2022
您是否没有超越任何架构中的第一个错误,或者没有超越示例实例文档中的任何错误?如果你想输出架构中的所有错误,我认为你还需要在架构工厂上设置一个错误处理程序。
0赞 Martin Honnen 12/15/2022
值得一提的是:我根据您链接到的原始示例设置了一个示例项目,首先使用内置的 JRE 8 Validator github.com/martin-honnen/ValidationHandlerTest1,然后使用 Apache Xerces 2.12 github.com/martin-honnen/ValidationHandlerTest1/tree/...,最后使用 Saxon EE 11.4 github.com/martin-honnen/ValidationHandlerTest1/tree/UseSaxon,这三个都发现了示例实例文档中的两个错误,并且没有放弃在第一个错误之后。
0赞 BATMAN_2008 12/15/2022
@MartinHonnen 非常感谢您的回复并花时间创建 3 个项目。但我有一个小小的怀疑。也许由于缺乏理解,我无法在 3 个创建的项目之间做出任何差异。所有 3 个项目似乎都具有相同的 ErrorHandler 和 TestMain 类,并且都具有相同的代码并来自同一个库。有什么区别吗?另外,我正在考虑使用,因为它已在其中一个依赖项目中使用。Moxy

答: 暂无答案