0

我有一个 XML 文件及其 XSD 架构。我能够验证 XML 文件并实现自定义 org.xml.sax.ErrorHandler,如下所示:

class MyErrorHandler implements ErrorHandler{
  ...
  @Override
  public void warning(SAXParseException exception) throws SAXException {
    System.out.println("Line: " + exception.getLineNumber() + ") " + exception.getMessage() + exception);
    warnings++;
  }
...
}

是否可以实际操作导致异常的元素,例如通过从 XML 文件中删除它?

两个注意事项:

  • XML 操作不需要就地进行,即我可以生成一个删除失败元素的新文件;
  • 最好的办法是能够获得导致异常的父元素,以便我可以决定是否完全删除父元素。

也只是一个关于遵循哪个方向以解决问题的建议表示赞赏。谢谢!

4

2 回答 2

4

在一般情况下,无法自动修复 XML 文档。

只有在非常有限的情况下,使 XML 文档有效所需的修复才能与任何给定的验证错误自动区分。验证错误与补救方法之间没有一对一的映射关系。

考虑r带有a直通e子元素的元素:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <xsd:element name="r">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="a"/>
        <xsd:element name="b"/>
        <xsd:element name="c"/>
        <xsd:element name="d"/>
        <xsd:element name="e"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

</xsd:schema>

像这样的一个 XML 文档,

<r>
  <a/>
  <x/>
  <b/>
  <c/>
  <d/>
  <e/>
</r>

Xerces-J 会产生如下验证消息:

[错误] try.xml:5:7: cvc-complex-type.2.4.a: 发现以元素“x”开头的无效内容。预期为“{b}”之一。

您可能会在这里自动删除x,一切都会好起来的。(或者,您可能会插入一个b,这不会很好。)

然而,对于同一个 XSD,考虑这个 XML 文档,

<r>
  <a/>
  <c/>
  <d/>
  <e/>
</r>

Xerces-J 会产生如下验证消息:

[错误] try.xml:5:7: cvc-complex-type.2.4.a: 发现以元素“c”开头的无效内容。预期为“{b}”之一。

如果您自动删除c,您的文档仍然无效,并且您会收到一条关于d意外的类似消息。这将一直持续到您的文档看起来像这样,

<r>
  <a/>
</r>

此时您的错误消息将返回原始消息,

[错误] try.xml:5:5: cvc-complex-type.2.4.b: 元素“r”的内容不完整。预期为“{b}”之一。

如您所见,在给定的验证错误中没有足够的信息来了解如何修复一般的 XML 文档。

您可以通过咨询 XSD 做得更好,但这非常复杂,并且仍然不能保证唯一地确定创作者或系统所犯的确切错误。在一般情况下,即使给定 XSD,也无法自动修复 XML 文档。

于 2016-12-05T13:43:26.213 回答
0

kjhughes 所说的一切都是正确的。

但是,如果您的输入中有特定的验证错误模式,则可以创建修复这些错误的规则。

在许多情况下,最简单的方法可能是编写 XSLT 代码来检测不正确的模式并修复它,甚至无需应用模式验证。例如,如果您的 EEE 元素长期存在问题,其中子 XXX 元素应该在子 YYY 之前,但它们的顺序通常是错误的,那么您可以使用模板规则修复它

<xsl:template match="EEE[XXX >> YYY]">
  <xsl:copy>
    <xsl:copy-of select="XXX/preceding-sibling::*, XXX, YYY, YYY/following-sibling::*"/>
  </xsl:copy>
</xsl:template>

XML Schema 中的理论是,当您验证一个文档时,输出不仅仅是一个是/否的答案,甚至也不是一组错误消息,而是一个文档,其中单个节点被标记为有效或无效,如果无效,以及导致它们被视为无效的错误条件。理论上,您可以浏览此文档,找到无效性并以适当的方式处理它们。但是,我认为没有很多工具可以实现这一点,至少不是完整的。

Saxon 模式处理器的最新版本引入了 InvalidityHandler,调用它以提供有关每个有效性错误的完整信息,以及此接口的实现,它生成 XML 格式的验证错误报告。这样做的目的是使工具能够对错误信息做更多的事情,而不是简单地将其放在用户面前进行思考。肯定有一类验证错误,可以获取错误报告并生成 XSLT 代码来纠正错误,例如,如果输入是一组要处理的事务,那么您可以创建一个忽略这些事务的事务文件验证失败。

(话虽如此,对于这个特定的用例,最好编写一个 XSLT 或 XQuery 应用程序来逐一验证事务,并使用 try/catch 仅复制有效事务。)

于 2016-12-05T15:43:06.590 回答