即使使用 ErrorHandler,为什么架构验证会在第一个错误后结束?

2023-12-03

我正在研究模式验证。目标是获取 XSD 文件并根据它验证传入文档。如果有错误,我想捕获所有错误。

我只在 ErrorHandler 中收到第一个错误,然后处理结束。互联网上有很多人们问同样问题的例子,答案似乎总是我正在做的事情(创建一个自定义错误处理程序)。

此外,ErrorHandler 接口的文档有这样的说明错误方法应该如何工作:

/**
 * <p>The SAX parser must continue to provide normal parsing
 * events after invoking this method: it should still be possible
 * for the application to process the document through to the end.
 * If the application cannot do so, then the parser should report
 * a fatal error even if the XML recommendation does not require
 * it to do so.</p>
 */

请注意,这是一个 Java 13 示例,但没有理由确实需要如此(除了简洁的 xml 文本定义)。

private String drugValidationSchema = """
                    <?xml version="1.0" encoding="UTF-8"?>
                    <schema xmlns="http://www.w3.org/2001/XMLSchema"
                    targetNamespace="https://www.company.com/Drug"
                    xmlns:apins="https://www.company.com/Drug" elementFormDefault="qualified">

                        <element name="drugRequest" type="apins:drugRequest"></element>

                        <element name="drugResponse" type="apins:drugResponse"></element>

                        <complexType name="drugRequest">
                            <sequence>
                                <element name="id" type="int"></element>
                            </sequence>
                        </complexType>

                        <complexType name="drugResponse">
                            <sequence>
                                <element name="id" type="int"></element>
                                <element name="drugClass" type="string"></element>
                                <element name="drugName" type="string"></element>
                            </sequence>
                        </complexType>
                    </schema>
                    """;

// This document has 3 errors in it based on the schema above:
// 1) idx instead of id
// 2) dugClass instead of drugClass
// 3) dugName instead of drugName
private String badDrugResponseXml = """
                    <?xml version="1.0" encoding="UTF-8"?>
                    <apins:drugResponse xmlns:apins="https://www.company.com/Drug" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.company.com/Drug Drug.xsd ">
                      <apins:idx>1</apins:idx>
                      <apins:dugClass>opioid</apins:dugClass>
                      <apins:dugName>Buprenorphine</apins:dugName>
                    </apins:drugResponse>
                    """;

/**
 * This test does nothing but send the desired files into the validation
 * process.  The goal is for the validation process to output 3 errors.
 * For reasons I don't understand, it will only output the first one and
 * stop the processing.
 */
@Test
void testWithValidator() {
    System.out.println("Test an entry with multiple errors: " + validateXMLSchema(drugValidationSchema, badDrugResponseXml));
    Assertions.assertTrue(true);
}


/**
 * This validator process seems to always stop after the first error is encountered.
 *
 * @param xsdPath   the actual XSD content as String
 * @param xmlPath   the actual xml document text as String.
 * @return          True if there are no errors, false otherwise. (planning to return details)
 */
static boolean validateXMLSchema(String xsdPath, String xmlPath){

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

        Schema schema = factory.newSchema(new StreamSource(new StringReader(xsdPath)));

        Validator validator = schema.newValidator();

        List<Exception> exceptions = new ArrayList<>();
        // Add a custom handler to the validator.  The goal is to continue processing
        // the document so that ALL errors are captured.
        validator.setErrorHandler(new ErrorHandler() {
            @Override
            public void warning(SAXParseException exception) {
                exceptions.add(exception);
            }

            @Override
            public void fatalError(SAXParseException exception) {
                exceptions.add(exception);
            }

            @Override
            public void error(SAXParseException exception) {
                exceptions.add(exception);
            }
        });

        validator.validate(new StreamSource(new StringReader(xmlPath)));

        if (exceptions.size() > 0) {
            for (Exception ex : exceptions) {
                System.out.println("Error found: " + ex.getMessage());
            }
        }else {
            System.out.println("No errors.");
        }
    } catch (SAXException | IOException e) {
        System.out.println("Exception: "+e.getMessage());
        return false;
    }
    return true;
}

正如注释所示,在调试中很明显,第一个错误是通过自定义错误处理程序的结果报告的,但处理不会继续并找到后续的两个错误。


答案并不简单,但请耐心等待……

我与一个实现了完全兼容的验证 XML 解析器的团队合作。我向他们询问了这个功能。他们解释说,不正确/意外的标签名称(同一件事)可能由两种情况导致:

a) xsd 中正确位置的标签名称不正确

b) 纠正 xsd 中错误位置的标签名称

当人们要求此功能时,他们几乎总是想到场景 a)。 XSD 非常简单(XML 文档中的可变性非常有限),并且对于人类读者来说,意外的标签名称“显而易见”是一个拼写错误。不幸的是,XSD 规范允许多种类型的变化。您可以有 xs:any(通配符)、选择组、无序组、可选元素、具有各种类型限制的复杂类型扩展等。如果 XSD 非常“开放”,则根本不明显的是意外的标记名称是一个简单的错字。尝试继续将毫无意义在一般情况下因为 XML 解析器不知道从哪里继续解析。

只有一种情况 XML 处理器可以发出验证错误并且safely继续解析在所有情况下。当。。。的时候简单值标签/属性的内容不符合 xsd:facet 限制,可以报告错误并继续。解析器并没有丢失 XSD 中的“上下文”,因为元素的名称都已成功匹配。

您可能会想参考您的示例并说“但就我而言,解析可以安全地继续”。您是对的,但我不知道有任何 XML 解析器能够区分不匹配的标记名称的“安全继续”和“不安全继续”情况。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

即使使用 ErrorHandler,为什么架构验证会在第一个错误后结束? 的相关文章

  • 如何添加对嵌入消息的反应 JDA

    当我执行命令 verify 时 我尝试发送和嵌入消息 然后它发送嵌入消息 但我找不到如何添加反应 我已经嵌入了消息并发送了它 但可以添加反应 import Main Bot import net dv8tion jda core Embed
  • 如何在JNA中填充结构体数组?

    我正在尝试在 JNA 中使用以下 Windows API UINT WINAPI GetRawInputDeviceList Out opt PRAWINPUTDEVICELIST pRawInputDeviceList Inout PUI
  • 模块化应用程序堆栈中的虚拟数据和单元测试策略

    如何管理用于测试的虚拟数据 将它们保留在各自的实体中 在一个单独的测试项目中 使用外部资源的序列化程序加载它们 或者只是在需要的地方重新创建它们 我们有一个应用程序堆栈 其中包含多个模块 这些模块依赖于另一个模块 每个模块都包含实体 每个模
  • 查找 Maven 使用的 Java 选项

    如何找到 Maven 正在使用哪些 Java 选项 Xmx Xms Xss 等 我发现有一种方法set它们是通过环境 MAVEN OPTS 实现的 现在我想要一种方法来确保它获得正确的设置 编辑 我相信它有所不同这个问题 https sta
  • 使用 ThreadCount TestNG 限制并行测试的数量

    我在这里很头疼 我不知道如何处理这个问题 我有几个通过 xml 运行的测试类 约90个测试班 每个班约10 Test进入其中 我配置了一个硒网格 带有maxSession 5因此 单个节点上最多可以并行运行 5 个并行浏览器实例 这是我不明
  • 创建用于软件分发的多平台 CD

    这与编程无关 但我希望仍然相关 我正在开发一个用 Java 编写的项目 旨在用于 PC 和 Mac 它将以 CD 形式发行 最终可能还会以 DVD 形式发行 我们的目标受众显然是非技术性的 因此 CD 在加载时 正常工作 非常重要 这本身并
  • 您使用什么来进行复杂的构建过程? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在尝试改进我们的构建过程 目前它是一个巨大的 Ant build xml 它调用其他 ant 构建
  • 什么是运行时绑定?

    根据 Android 开发者指南 Intent 是一个提供运行时绑定独立组件之间 例如两个活动 什么是 运行时绑定 继承创建类型兼容性 它允许超类引用 引用子类的对象 反过来则不然 超类引用 指的是 子类的对象 只能用于 访问继承的和重写的
  • Java 让物体在按住按钮时移动

    如何使 JPanel 在按住按钮时移动并在释放按钮时停止 我尝试过将 thread start 与 Runnable 一起使用以及类似的方式 我总是遇到错误 有人可以帮助我吗 您需要考虑许多重要的因素 按钮的设计初衷并非如此 它们被设计为在
  • 关于final关键字的java基础知识

    方法中可以使用final关键字吗 绝对地 这final关键字几乎可以应用于任何事物 在每种情况下都意味着 您无法再更改它 这就是它应用于时的含义 一个变量 您根本无法为变量分配新值 将其呈现为constant 当然 a method 您不能
  • 从 android 将用户注册到 QuickBlox 用户

    我正在尝试在我的 Android 应用程序中使用 QuickBlox 我阅读了指南并导入了示例 一切正常 我更改了一些用户可以使用 EditText 作为用户名和另一个密码登录的内容 并且效果很好 但现在我想添加一个注册按钮 使用户能够注册
  • JPA 多对多关系创建两个联接表

    我正在尝试在之间创建多对多关系User and FileObject假设用户可以访问许多文件对象的类 并且文件对象可以由许多用户和一对多关系访问 因为一个用户可以拥有许多文件 但一个文件只能由一个用户拥有 这是我的代码 Entity pub
  • 您可以链接两个 JFormattedTextField 的值吗?

    我有一个带有 2 个 JFormattedTextFields 的界面 我需要它们的值 不仅仅是显示的文本 相同 理想情况下 它们都应该是可编辑的 其中一个的更改会反映在另一个中 我一开始只是在两者之间共享一个文档 但很快就遇到了一个问题
  • 在 onClick 处理程序的活动类 [...] 中找不到方法 [...](View)

    当我按下按钮时fragment main xml 出现这个错误 java lang IllegalStateException Could not find a method sendMessage View in the activity
  • 如何使用 Spring 使用注释执行基于构造函数的依赖注入?

    好的 如果我需要在构造函数中放入一些原始值 我该怎么做 Autowired public CustomBean String name Qualifier SuperBean SuperBean superBean super this s
  • 隧道多部分文件

    我有一个spring接受名为的类的控制器FileUploadBean on POST 控制器方法如下所示 第一控制员 RequestMapping value upload method RequestMethod POST Respons
  • 如何为所有测试初始化​​一次 Spring applicationContext

    我有一组基于需要 spring 上下文的测试 为了快速执行测试 我想确保 Spring 上下文仅初始化一次 然后所有测试都应该针对该上下文运行 然后应该关闭 我已经尝试过以下方法 Use RunWith SpringJUnit4ClassR
  • EasyMock - 由于无法访问父类私有对象(i18n)而引发 NullPointerException

    A Class Parent4 private I18nUtils i18n Here Nullpointerexception occur public Parent4 SetText i18n getText HELLO B Class
  • Java双精度求和问题

    我想知道为什么我会收到此错误 这是Eclipse调试的显示日志 var double 2 8 tot getIva java lang Double 0 17 var tot get double 2 9699999999999998 我不
  • CodenameOne 在构建后停止工作

    我对 codenameone 有一个奇怪的问题 我什至不确定出了什么问题 我尝试过 发送 Windows Phone 版本 并且从那时起我认为我没有更改任何其他内容 然而 在我这样做之后 模拟器无法启动并一直说我的导入是错误的 事实并非如此

随机推荐