Java:比较XPath结构

时间:2013-05-23 11:15:53

标签: java xml xpath functional-testing

我正在编写一些功能测试,它们应该比较两个XML文档的XML 结构。这意味着标签顺序和命名是重要的,而标签内容则无关紧要。

例如,以下调用:

致电1:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book category="COOKING">
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
  </book>
</bookstore>

致电2:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book category="CHILDREN">
    <title lang="en">Harry Potter</title>
    <author>J K. Rowling</author>
  </book>
</bookstore>

具有相同的标记结构,但是:

致电3:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book category="WEB">
    <title lang="en">Learning XML</title>
    <author>Erik T. Ray</author>
    <year>2003</year>
  </book>
</bookstore>

不同,因为它在<year>之后有一个<author>标记,而且调用1和2缺少该标记。

比较XML结构的Java方法是什么?

2 个答案:

答案 0 :(得分:1)

您可以在两个文档上调用简单的XSLT转换,删除所有文本节点和属性内容,然后在两个结果上调用XPath deep-equal()。

答案 1 :(得分:0)

我编写了一个扁平化XML的类,并提供了一个人类可读的String来进行比较。

为了进行比较,我创建了两个XPathFlattener个对象,并比较了它们的toString()表示。

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Node;

public class XPathFlattener {

    private Node root;

    public XPathFlattener(Node root) {
        this.root = root;
    }

    /**
     * Flattens a XPath tree to a list of nodes, in pre-order traversal.
     */
    public List<Node> flatten() {
        List<Node> nodes = flattenTreeToList(this.root, new ArrayList<Node>());
        return nodes; 
    }

    /**
     * Flattens a XPath tree to a list of Strings, each representing the name
     * of the node, but not its contents. 
     * The list is created using pre-order traversal.
     */
    @Override
    public String toString() {
        List<String> nodesStrings = new ArrayList<>();
        for (Node n:this.flatten()) {
            nodesStrings.add(stringRepresentation(n));
        }
        return StringUtils.join(nodesStrings, ", ");
    }

    /**
     * Recursively flattens a Node tree to a list, in pre-order traversal.
     * @param node
     * @param nodes
     * @return
     */
    private static List<Node> flattenTreeToList(Node node, List<Node> nodes) {
        nodes.add(node);
        for (int i=0; i< node.getChildNodes().getLength(); i++) {
            Node childNode = node.getChildNodes().item(i);
            flattenTreeToList(childNode, nodes);
        }
        return nodes;
    }

    /**
     * A String representation of the node structure, without its contents.
     * @param node
     * @return
     */
    private static String stringRepresentation(Node node) {
        return String.format("[%s, (type %d)]", node.getNodeName(), node.getNodeType());
    }

}