我正在尝试编写一个应用程序的自动测试,它基本上将自定义消息格式转换为XML消息并将其发送到另一端.我有一组很好的输入/输出消息对,所以我需要做的就是发送输入消息并监听XML消息从另一端出来.
当需要将实际输出与预期输出进行比较时,我遇到了一些问题.我的第一个想法就是对预期和实际消息进行字符串比较.这样做效果不好,因为我们拥有的示例数据并不总是一致地格式化,并且通常会有不同的别名用于XML命名空间(有时根本不使用命名空间.)
我知道我可以解析两个字符串,然后遍历每个元素并自己进行比较,这不会太困难,但我觉得有一个更好的方法或我可以利用的库.
所以,归结起来,问题是:
给定两个包含有效XML的Java字符串,您将如何确定它们在语义上是否等效?如果您有办法确定差异是什么,可以获得奖励积分.
听起来像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 } }
以下将使用标准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.
Xom有一个Canonicalizer实用程序,可以将您的DOM转换为常规形式,然后您可以进行字符串化和比较.因此,无论空白不规则或属性排序如何,您都可以对文档进行定期,可预测的比较.
这在具有专用可视字符串比较器(如Eclipse)的IDE中尤其有效.您可以直观地表示文档之间的语义差异.
最新版本的XMLUnit可以帮助断言两个XML的工作是相同的.也XMLUnit.setIgnoreWhitespace()
并XMLUnit.setIgnoreAttributeOrder()
可能有必要在问题的情况下.
请参阅下面的XML单元使用的简单示例的工作代码.
import org.custommonkey.xmlunit.DetailedDiff; import org.custommonkey.xmlunit.XMLUnit; import org.junit.Assert; public class TestXml { public static void main(String[] args) throws Exception { String result = ""; // will be ok assertXMLEquals(" ", result); } public static void assertXMLEquals(String expectedXML, String actualXML) throws Exception { XMLUnit.setIgnoreWhitespace(true); XMLUnit.setIgnoreAttributeOrder(true); DetailedDiff diff = new DetailedDiff(XMLUnit.compareXML(expectedXML, actualXML)); List> allDifferences = diff.getAllDifferences(); Assert.assertEquals("Differences found: "+ diff.toString(), 0, allDifferences.size()); } }
如果使用Maven,请将其添加到您的pom.xml
:
xmlunit xmlunit 1.4
谢谢,我扩展了这个,试试这个......
import java.io.ByteArrayInputStream; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; public class XmlDiff { private boolean nodeTypeDiff = true; private boolean nodeValueDiff = true; public boolean diff( String xml1, String xml2, Listdiffs ) throws Exception { 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 ByteArrayInputStream(xml1.getBytes())); Document doc2 = db.parse(new ByteArrayInputStream(xml2.getBytes())); doc1.normalizeDocument(); doc2.normalizeDocument(); return diff( doc1, doc2, diffs ); } /** * Diff 2 nodes and put the diffs in the list */ public boolean diff( Node node1, Node node2, List diffs ) throws Exception { if( diffNodeExists( node1, node2, diffs ) ) { return true; } if( nodeTypeDiff ) { diffNodeType(node1, node2, diffs ); } if( nodeValueDiff ) { diffNodeValue(node1, node2, diffs ); } System.out.println(node1.getNodeName() + "/" + node2.getNodeName()); diffAttributes( node1, node2, diffs ); diffNodes( node1, node2, diffs ); return diffs.size() > 0; } /** * Diff the nodes */ public boolean diffNodes( Node node1, Node node2, List diffs ) throws Exception { //Sort by Name Map children1 = new LinkedHashMap (); for( Node child1 = node1.getFirstChild(); child1 != null; child1 = child1.getNextSibling() ) { children1.put( child1.getNodeName(), child1 ); } //Sort by Name Map children2 = new LinkedHashMap (); for( Node child2 = node2.getFirstChild(); child2!= null; child2 = child2.getNextSibling() ) { children2.put( child2.getNodeName(), child2 ); } //Diff all the children1 for( Node child1 : children1.values() ) { Node child2 = children2.remove( child1.getNodeName() ); diff( child1, child2, diffs ); } //Diff all the children2 left over for( Node child2 : children2.values() ) { Node child1 = children1.get( child2.getNodeName() ); diff( child1, child2, diffs ); } return diffs.size() > 0; } /** * Diff the nodes */ public boolean diffAttributes( Node node1, Node node2, List diffs ) throws Exception { //Sort by Name NamedNodeMap nodeMap1 = node1.getAttributes(); Map attributes1 = new LinkedHashMap (); for( int index = 0; nodeMap1 != null && index < nodeMap1.getLength(); index++ ) { attributes1.put( nodeMap1.item(index).getNodeName(), nodeMap1.item(index) ); } //Sort by Name NamedNodeMap nodeMap2 = node2.getAttributes(); Map attributes2 = new LinkedHashMap (); for( int index = 0; nodeMap2 != null && index < nodeMap2.getLength(); index++ ) { attributes2.put( nodeMap2.item(index).getNodeName(), nodeMap2.item(index) ); } //Diff all the attributes1 for( Node attribute1 : attributes1.values() ) { Node attribute2 = attributes2.remove( attribute1.getNodeName() ); diff( attribute1, attribute2, diffs ); } //Diff all the attributes2 left over for( Node attribute2 : attributes2.values() ) { Node attribute1 = attributes1.get( attribute2.getNodeName() ); diff( attribute1, attribute2, diffs ); } return diffs.size() > 0; } /** * Check that the nodes exist */ public boolean diffNodeExists( Node node1, Node node2, List diffs ) throws Exception { if( node1 == null && node2 == null ) { diffs.add( getPath(node2) + ":node " + node1 + "!=" + node2 + "\n" ); return true; } if( node1 == null && node2 != null ) { diffs.add( getPath(node2) + ":node " + node1 + "!=" + node2.getNodeName() ); return true; } if( node1 != null && node2 == null ) { diffs.add( getPath(node1) + ":node " + node1.getNodeName() + "!=" + node2 ); return true; } return false; } /** * Diff the Node Type */ public boolean diffNodeType( Node node1, Node node2, List diffs ) throws Exception { if( node1.getNodeType() != node2.getNodeType() ) { diffs.add( getPath(node1) + ":type " + node1.getNodeType() + "!=" + node2.getNodeType() ); return true; } return false; } /** * Diff the Node Value */ public boolean diffNodeValue( Node node1, Node node2, List diffs ) throws Exception { if( node1.getNodeValue() == null && node2.getNodeValue() == null ) { return false; } if( node1.getNodeValue() == null && node2.getNodeValue() != null ) { diffs.add( getPath(node1) + ":type " + node1 + "!=" + node2.getNodeValue() ); return true; } if( node1.getNodeValue() != null && node2.getNodeValue() == null ) { diffs.add( getPath(node1) + ":type " + node1.getNodeValue() + "!=" + node2 ); return true; } if( !node1.getNodeValue().equals( node2.getNodeValue() ) ) { diffs.add( getPath(node1) + ":type " + node1.getNodeValue() + "!=" + node2.getNodeValue() ); return true; } return false; } /** * Get the node path */ public String getPath( Node node ) { StringBuilder path = new StringBuilder(); do { path.insert(0, node.getNodeName() ); path.insert( 0, "/" ); } while( ( node = node.getParentNode() ) != null ); return path.toString(); } }
在Tom的回答的基础上,这是一个使用XMLUnit v2的例子.
它使用这些maven依赖项
org.xmlunit xmlunit-core 2.0.0 test org.xmlunit xmlunit-matchers 2.0.0 test
..这是测试代码
import static org.junit.Assert.assertThat; import static org.xmlunit.matchers.CompareMatcher.isIdenticalTo; import org.xmlunit.builder.Input; import org.xmlunit.input.WhitespaceStrippedSource; public class SomeTest extends XMLTestCase { @Test public void test() { String result = ""; String expected = " "; // ignore whitespace differences // https://github.com/xmlunit/user-guide/wiki/Providing-Input-to-XMLUnit#whitespacestrippedsource assertThat(result, isIdenticalTo(new WhitespaceStrippedSource(Input.from(expected).build()))); assertThat(result, isIdenticalTo(Input.from(expected).build())); // will fail due to whitespace differences } }
概述这一点的文档是https://github.com/xmlunit/xmlunit#comparing-two-documents