比较两个xml,如果顺序是一样的很好比对,用比对工具Beyond Compare 就可以,结果一目了然。但是如果是乱序的呢,那整个文档都是红色的。我知道有人用Python可以轻松写出这样的比对代码。但是Java就鲜有这样的资料,我是没找到。关于这个比对,我思考了很久,也挣扎了很久,今天终于是完成它的雏形。关键是思路,我一直没有想出好的办法去实现他,我也一直没动手,我知道不动手是写不出程序的,光靠想是想不出来的。
我简单描述下大体思路(我觉得思路很重要,代码可以千变万化,但需要思路指引方向):
1.主要辅助类: 我利用了dom4j xpath ,查看了官方文档中的 Fast Looping 。 把xml变成一个map。
循环遍历之后,我用了node.getParent().getUniquePath()获取每个路径,这个很神奇,他可以直达叶子节点。
2.之后,我做了处理,对list节点进行 去[] 处理。
如果list生成的路径是 :/a/b/c[1]/d 这种格式,我统一把他变成 /a/b/c,处理成一个传统的listmap。
3.开始比较。首先做一轮节点差异比较。有差异用StringBuilder接收
4.再进行值比较。
(1) 遍历map,比较list,判断map的value是不是list类型 用instanceof
如果是list类型,我先对两个list做一个消除操作,即先遍历两个list中的每一个map,检查是否有相同的map(key-value一致),如果一直就对list进行remove操作,如果两个xml一致,那么最后所有的list会全部消失,不再进行差异比较。
消除完以后,剩下有差异的list,进行比较:
三个循环(两个list和第2个list中的map),逻辑不好描述,大体就是遍历值相等就continue,如果不相等,别急着判断差异,因为是乱序的,所以可能是在第2个map中匹配上,因此要判断是否已经执行完第2个list循环,如果执行完了就是有差异。
不过之前我都做了消除的操作,这步其实也不用做,可以直接比差异了。
package com.service;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
public class CompareXMLService {
public static Document parse(File file) throws DocumentException {
SAXReader reader = new SAXReader();
Document document = reader.read(file);
return document;
}
public static Map treeWalk(Document document) {
Map map = new TreeMap();
treeWalk(map, document.getRootElement());
map = dealList(map);
return map;
}
/**
*
* @describe 遍历
* @date 2019-04-04
* @param map
* @param element
* @return
*/
public static Map treeWalk(Map map, Element element) {
for (int i = 0, size = element.nodeCount(); i < size; i++) {
Node node = element.node(i);
if (node instanceof Element) {
treeWalk(map, (Element) node);
} else {
// System.out.println(node.getParent().getUniquePath());
String path = node.getParent().getUniquePath();
if (path.indexOf("response/") != -1) {
map.put(path, node.getText());
}
}
}
return map;
}
/**
*
* @describe 处理xml中的list,转化为传统list
* @date 2019-04-04
* @param map
* @return
*/
public static Map dealList(Map map) {
Map newMap = new TreeMap<>();
// newMap.putAll(map);
List
因为我做成了swing界面,界面传String类型,所以再转了一次 doc.asXML();
xml:
1
d1
2
d1 另一个报文这边改一下数据
[该list 中存在值差异]:/a/response/b/d;value=d1/d1222