在Java中比较2个XML文档的最佳方法
我正在尝试编写一个应用程序的自动化测试,该测试基本上将自定义消息格式转换为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 。