比较两个相似的XML数据与Java中无序的元素/属性

时间:2019-03-26 18:12:40

标签: java xml unit-testing junit xmlunit

我正在寻找比较两个XML数据的API。我已经尝试过XMLUnit 2,但是找不到与我的示例兼容的方法。你能给我一个适合我需要的例子吗?

我的第一个XML数据xml1

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<urlset xmlns="http://www.sitemap.org/schemas/sitemap/0.9">
    <url>
        <loc>a1/</loc>
        <lastmod>a2</lastmod>
    </url>
    <url>
        <loc>b1</loc>
        <lastmod>b2</lastmod>
    </url>
    <url>
        <loc>c1</loc>
        <lastmod>c2</lastmod>
    </url>
</urlset>

我的第二个XML数据xml2

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<urlset xmlns="http://www.sitemap.org/schemas/sitemap/0.9">
    <url><lastmod>b2</lastmod><loc>b1</loc></url>
    <url>
        <lastmod>c2</lastmod>
        <loc>c1</loc>
    </url>
    <url>
        <loc>a1/</loc>
        <lastmod>a2</lastmod>
    </url>
</urlset>

注意:

  • 大小相同(这里是3个孩子)
  • urlset的子节点(url)可能未排序
  • url的元素(loclastmod)不能排序
  • 空格被忽略

寻找一个返回true的API,例如:

XMLUtils.isSimilar(xml1, xml2);

我对XMLUnit 2的尝试失败(尝试了多个“ NodeMatcher”):

// Attempt with XmlAssert.assertThat:
XmlAssert.assertThat(xml1)
    .and(xml2)
    .ignoreChildNodesOrder()
    .ignoreWhitespace()
    .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))
    .areSimilar();

// Attempt with Diff
Diff myDiff = DiffBuilder.compare(xml1)
    .withTest(xml2)
    .ignoreWhitespace()
    .checkForSimilar()
    .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))
     .build();
myDiff.getDifferences();

2 个答案:

答案 0 :(得分:1)

您可以尝试以下操作

public class XMLUtils {
    private static DocumentBuilderFactory documentBuilderFactory;
    private static DocumentBuilder documentBuilder;
    private static TransformerFactory transformerFactory;
    private static Transformer transformer;
    private static Document emptyDoc;

    public XMLUtils() {
    }

    public XMLCompareResult compare(File expectedFile, File actualFile, boolean ignoreWhiteSpace) throws FileNotFoundException, SAXException, IOException {
        FileInputStream expInpStream = new FileInputStream(expectedFile);
        FileInputStream actualInpStream = new FileInputStream(actualFile);
        Diff myDiff = null;
        if (ignoreWhiteSpace) {
            myDiff = DiffBuilder.compare(expInpStream).withTest(actualInpStream).checkForSimilar().ignoreWhitespace().withNodeMatcher(new DefaultNodeMatcher(new ElementSelector[]{ElementSelectors.byNameAndAllAttributes})).build();
        } else {
            myDiff = DiffBuilder.compare(expInpStream).withTest(actualInpStream).checkForSimilar().withNodeMatcher(new DefaultNodeMatcher(new ElementSelector[]{ElementSelectors.byNameAndAllAttributes})).build();
        }

        XMLResultUtil xmlr = new XMLResultUtil();
        XMLCompareResult xs = xmlr.prepareXMLCompareResult(myDiff.getDifferences());
        return xs;
    }  

    static {
        try {
            documentBuilderFactory = DocumentBuilderFactory.newInstance();
            documentBuilder = documentBuilderFactory.newDocumentBuilder();
            transformerFactory = TransformerFactory.newInstance();
            transformer = transformerFactory.newTransformer();
            emptyDoc = documentBuilder.newDocument();
        } catch (ParserConfigurationException var1) {
            var1.printStackTrace();
        } catch (TransformerConfigurationException var2) {
            var2.printStackTrace();
        }

    }
}

我在这里复制我们在项目中使用的方法。

您可以尝试一下,如果您遇到任何问题,请告诉我。我可以自己再试一次。

谢谢

答案 1 :(得分:0)

最大的问题可能是“匹配的url元素是什么?”。我只能猜测并假设url子元素中具有相同文本的loc是匹配元素-这就是您需要告诉XMLUnit的地方。

您的示例非常普遍,但仍然无法猜到(除了强制使用所有可能的排列并选择差异最小的排列之外)。这是https://github.com/xmlunit/user-guide/wiki/SelectingNodes的运行示例,您只需将tr替换为uri,将th替换为loc

使事情具体化。比较url元素时,您希望XMLUnit查看相应的loc子元素并比较它们的嵌套文本。在所有其他情况下,您很乐意按兄弟元素的名称进行选择(只有一个urlset,每对loclastmod兄弟姐妹均由其标签名称唯一决定)。

转换为条件ElementSelector

ElementSelectors.conditionalBuilder()
    .whenElementIsNamed("url").thenUse(ElementSelectors
        .byXPath("./loc", ElementSelectors.byNameAndText))
    .elseUse(ElementSelectors.byName)
    .build();

这样,您应该能够得出“相似”结果,其中发现的唯一区别是子顺序差异。