比较两个忽略元素顺序的XML字符串

支持我有两个xml字符串

 a b   b a  

如何编写一个比较这两个字符串并忽略元素顺序的测试?

我希望测试尽可能短,没有10行XML解析等的地方。我正在寻找一个简单的断言或smt类似。

我有这个(不起作用)

  Diff diff = XMLUnit.compareXML(expectedString, actualString); XMLAssert.assertXMLEqual("meh", diff, true); 

我原来的答案已经过时了。 如果我必须再次构建它,我将使用xmlunit 2和xmlunit-matchers。 请注意,对于xml单元,不同的顺序总是“相似”而不是等于。

 @Test public void testXmlUnit() { String myControlXML = "ab"; String expected = "ba"; assertThat(myControlXML, isSimilarTo(expected).withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))); //In case you wan't to ignore whitespaces add ignoreWhitespace().normalizeWhitespace() assertThat(myControlXML, isSimilarTo(expected).ignoreWhitespace().normalizeWhitespace().withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))); } 

如果有人仍然不想在这里使用纯Java实现。 此实现从xml中提取内容并比较列表忽略顺序。

 public static Document loadXMLFromString(String xml) throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); InputSource is = new InputSource(new StringReader(xml)); return builder.parse(is); } @Test public void test() throws Exception { Document doc = loadXMLFromString("\n" + " b\n" + " a\n" + ""); XPathFactory xPathfactory = XPathFactory.newInstance(); XPath xpath = xPathfactory.newXPath(); XPathExpression expr = xpath.compile("//test//elem"); NodeList all = (NodeList) expr.evaluate(doc, XPathConstants.NODESET); List values = new ArrayList<>(); if (all != null && all.getLength() > 0) { for (int i = 0; i < all.getLength(); i++) { values.add(all.item(i).getTextContent()); } } Set expected = new HashSet<>(Arrays.asList("a", "b")); assertThat("List equality without order", values, containsInAnyOrder(expected.toArray())); } 

XMLUnit将执行您想要的操作,但您必须指定elementQualifier。 如果未指定elementQualifier,则仅比较相同位置的节点。

对于您想要ElementNameAndTextQualifer的示例,如果存在与节点名称及其文本值匹配的节点,则会考虑类似的节点,如:

 Diff diff = new Diff(control, toTest); // we don't care about ordering diff.overrideElementQualifier(new ElementNameAndTextQualifier()); XMLAssert.assertXMLEqual(diff, true); 

你可以在这里阅读更多相关信息: http : //xmlunit.sourceforge.net/userguide/html/ar01s03.html#ElementQualifier

对于xmlunit 2.0(我一直在寻找这个),现在使用DefaultNodeMatcher完成了它

 Diff diff = Diffbuilder.compare(Input.fromFile(control)) .withTest(Input.fromFile(test)) .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText)) .build() 

希望这有助于这有助于其他人谷歌搜索…

选项1
如果XML代码很简单,请尝试以下方法:

  String testString = ... assertTrue(testString.matches("(?m)^(\\s*(a|b)\\s*){2}$")); 

方案2
如果XML更复杂,请使用XML解析器加载它,并将找到的实际节点与参考节点进行比较。

来自Compare XML的交叉发布忽略子元素的顺序

今天晚上我有类似的需求,找不到符合我要求的东西。

我的解决方法是对我想要的两个XML文件进行排序,按元素名称的字母顺序排序。 一旦它们处于一致的顺序,我就可以使用常规的可视化差异工具来区分两个已排序的文件。

如果这种方法听起来对其他人有用,我已经分享了我写的python脚本,可以在http://dalelane.co.uk/blog/?p=3225进行排序。

仅作为如何比较基于属性name相等的更复杂的xml元素匹配的示例。 例如:

     

     

使用以下自定义元素限定符:

 final Diff diff = XMLUnit.compareXML(controlXml, testXml); diff.overrideElementQualifier(new ElementNameAndTextQualifier() { @Override public boolean qualifyForComparison(final Element control, final Element test) { // this condition is copied from super.super class if (!(control != null && test != null && equalsNamespace(control, test) && getNonNamespacedNodeName(control).equals(getNonNamespacedNodeName(test)))) { return false; } // matching based on 'name' attribute if (control.hasAttribute("name") && test.hasAttribute("name")) { if (control.getAttribute("name").equals(test.getAttribute("name"))) { return true; } } return false; } }); XMLAssert.assertXMLEqual(diff, true); 

对我来说,我还需要在DiffBuilder上添加方法: checkForSimilar() 。 没有它,断言是错误的,说节点的顺序不一样(子列表中的位置不一样)

我的代码是:

  Diff diff = Diffbuilder.compare(Input.fromFile(control)) .withTest(Input.fromFile(test)) .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText)) .checkForSimilar() .build()