在Java中比较2个XML文档的最佳方法

时间:2020-03-06 14:48:33  来源:igfitidea点击:

我正在尝试编写一个应用程序的自动化测试,该测试基本上将自定义消息格式转换为XML消息并将其发送到另一端。我有一组不错的输入/输出消息对,所以我要做的就是将输入消息发送进来,并听XML消息传到另一端。

当需要将实际输出与预期输出进行比较时,我遇到了一些问题。我的第一个想法就是对预期消息和实际消息进行字符串比较。这不能很好地工作,因为我们拥有的示例数据并不总是保持一致的格式,并且常常为XML名称空间使用不同的别名(有时根本不使用名称空间)。

我知道我可以解析两个字符串,然后遍历每个元素并自己比较它们,这并不是很难做到的,但是我感到有一种更好的方法或者可以利用的库。

因此,归根结底,问题是:

给定两个都包含有效XML的Java字符串,我们将如何确定它们在语义上是否等效?如果我们有办法确定差异是多少,我们将获得加分。

解决方案

Xom具有Canonicalizer实用程序,可将DOM转换为常规形式,然后我们可以对其进行字符串化和比较。因此,无论空白不规则或者属性排序如何,我们都可以对文档进行定期的,可预测的比较。

在具有专用可视化字符串比较器的IDE(例如Eclipse)中,这种方法特别有效。我们可以直观地看到文档之间的语义差异。

听起来像XMLUnit的工作

  • http://www.xmlunit.org/
  • https://github.com/xmlunit

例子:

public class SomeTest extends XMLTestCase {
  @Test
  public void test() {
    String xml1 = ...
    String xml2 = ...

    XMLUnit.setIgnoreWhitespace(true); // ignore whitespace differences

    // can also compare xml Documents, InputSources, Readers, Diffs
    assertXMLEquals(xml1, xml2);  // assertXMLEquals comes from XMLTestCase
  }
}

skaffman似乎给出了很好的答案。

另一种方法可能是使用诸如xmlstarlet(http://xmlstar.sourceforge.net/)之类的命令行实用程序来格式化XML,然后格式化两个字符串,然后使用任何diff实用程序(库)来对结果输出文件进行差异化。当名称空间出现问题时,我不知道这是否是一个好的解决方案。

因为我们说的是"语义上等效",所以我假设意思是我们要做的不只是从字面上验证xml输出是否等于(字符串),而且还需要类似

<foo>这里的一些东西</ foo> </ code>

<foo>一些东西</ foo> </ code>

等同阅读。最终,与要从其重构消息的任何对象上定义"语义等效"的问题有关。只需根据消息构建该对象,然后使用自定义的equals()定义我们要查找的内容。

我正在使用Altova DiffDog,它具有用于在结构上比较XML文件的选项(忽略字符串数据)。

这意味着(如果选中"忽略文本"选项):

<foo a="xxx" b="xxx">xxx</foo>

<foo b="yyy" a="yyy">yyy</foo>

就结构上的平等而言,它们是平等的。如果示例文件的数据不同,但结构不同,这将很方便!

下面将使用标准JDK库检查文档是否相等。

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setCoalescing(true);
dbf.setIgnoringElementContentWhitespace(true);
dbf.setIgnoringComments(true);
DocumentBuilder db = dbf.newDocumentBuilder();

Document doc1 = db.parse(new File("file1.xml"));
doc1.normalizeDocument();

Document doc2 = db.parse(new File("file2.xml"));
doc2.normalizeDocument();

Assert.assertTrue(doc1.isEqualNode(doc2));

normalize()可以确保没有周期(从技术上讲不会有周期)

上面的代码将要求元素中的空格必须相同,因为它保留并评估了空格。 Java随附的标准XML解析器不允许我们设置功能以提供规范的版本或者理解xml:space,如果这将是一个问题,那么我们可能需要替换的XML解析器(例如xerces)或者使用JDOM 。