java - 如何使用 XMLUnit DiffBuilder 检测属性和元素列表的差异
问题描述
我需要比较两个 XML 字符串,其中标记内的任意属性可能会发生变化,以及任意插入到标记序列或从标记序列中删除的标记。
我发现如果我使用ElementSelectors.byNameAndText,我会得到适当的属性更改差异,除非有序列插入或删除。
我发现,如果我使用ElementSelectors.byNameAndAllAttributes,我会为插入到一系列标签或从中删除的标签获得适当的差异,但不会获得适当的属性更改详细信息。
如何结合这两种差异生成机制?
控制 XML
String myControlXML =
"<?xml version='1.0' encoding='UTF-8'?>" +
"<ns2:policy xmlns:ns2='com.xyz' version='2' id='ABCD'>" +
"<ns2:widgets>" +
"<ns2:widget name='foo' id='17'>" +
"<ns2:desc text='Does foo widget stuff' version='2'/>" +
"</ns2:widget>" +
"<ns2:widget name='bar' id='19'>" +
"<ns2:desc text='Does bar widget stuff' version='4'/>" +
"</ns2:widget>" +
"</ns2:widgets>" +
"</ns2:policy>";
测试 XML
String myTestXML1 =
"<?xml version='1.0' encoding='UTF-8'?>" +
"<ns2:policy xmlns:ns2='com.xyz' version='13' id='ABCD'>" +
"<ns2:widgets>" +
"<ns2:widget name='foo' id='17'>" +
"<ns2:desc text='Does foo widget stuff' version='2'/>" +
"</ns2:widget>" +
"<ns2:widget name='bzz' id='15'>" +
"<ns2:desc text='Does bzz widget stuff' version='6'/>" +
"</ns2:widget>" +
"<ns2:widget name='bar' id='19'>" +
"<ns2:desc text='Does bar widget stuff' version='4'/>" +
"</ns2:widget>" +
"</ns2:widgets>" +
"</ns2:policy>";
差异代码
Diff myDiff7 = DiffBuilder.compare(myControlXML)
.withTest(myTestXML1)
.withNodeMatcher(new
DefaultNodeMatcher(ElementSelectors.byNameAndAllAttributes))
.build();
不同的结果 1
2 diffs
- type = child
- message = ns2:policy:Expected child '{com.xyz}policy' but was 'null' - comparing <ns2:policy...> at /policy[1] to <NULL>
- type = child
- message = ns2:policy:Expected child 'null' but was '{com.xyz}policy' - comparing <NULL> to <ns2:policy...> at /policy[1]
这似乎是在说“某些属性不同”
与 ns2:policy 行匹配,
不同的结果 2
2 diffs
- type = child nodelist sequence
- message = widget:Expected child nodelist sequence '1' but was '2' - comparing <ns2:widget...> at /policy[1]/widgets[1]/widget[2] to <ns2:widget...> at /policy[1]/widgets[1]/widget[3]
- type = child
- message = widget:Expected child 'null' but was '{com.xyz}widget' - comparing <NULL> to <ns2:widget...> at /policy[1]/widgets[1]/widget[2]
这似乎是正确的说小部件 [2] 被移动到小部件 [3] 并添加了一个新的小部件 [2]。
使用初始 XML 值,但使用 ElementSelectors.byNameAndText 而不是 ElementSelectors.byNameAndAllAttributes
不同的结果 3
6 diffs
- type = attribute value
- message = Expected attribute value '2' but was '13' - comparing <ns2:policy version="2"...> at /policy[1]/@version to <ns2:policy version="13"...> at /policy[1]/@version
- type = attribute value
- message = Expected attribute value '19' but was '15' - comparing <ns2:widget id="19"...> at /policy[1]/widgets[1]/widget[2]/@id to <ns2:widget id="15"...> at /policy[1]/widgets[1]/widget[2]/@id
- type = attribute value
- message = Expected attribute value 'bar' but was 'bzz' - comparing <ns2:widget name="bar"...> at /policy[1]/widgets[1]/widget[2]/@name to <ns2:widget name="bzz"...> at /policy[1]/widgets[1]/widget[2]/@name
- type = attribute value
- message = Expected attribute value 'Does bar widget stuff' but was 'Does bzz widget stuff' - comparing <ns2:desc text="Does bar widget stuff"...> at /policy[1]/widgets[1]/widget[2]/desc[1]/@text to <ns2:desc text="Does bzz widget stuff"...> at /policy[1]/widgets[1]/widget[2]/desc[1]/@text
- type = attribute value
- message = Expected attribute value '4' but was '6' - comparing <ns2:desc version="4"...> at /policy[1]/widgets[1]/widget[2]/desc[1]/@version to <ns2:desc version="6"...> at /policy[1]/widgets[1]/widget[2]/desc[1]/@version
- type = child
- message = Expected child 'null' but was '{com.xyz}widget' - comparing <NULL> to <ns2:widget...> at /policy[1]/widgets[1]/widget[3]
这似乎正确地比较了 ns2:policy 行,但错误地将旧的小部件 2 与新的小部件 2 进行了比较,并表明添加了一个新的小部件 [3]。
提前感谢您能给我的任何帮助。
编辑:
我在这里找到了部分答案XMLUnit-2.0 xpath doesn't ignoring the XML node order
Diff myDiff7a = DiffBuilder.compare(myControlXML)
.withTest(myTestXML1)
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.conditionalBuilder()
.whenElementIsNamed("widget").thenUse(
(e1, e2) -> StringUtils.equals(e1.getAttribute("name"), e2.getAttribute("name")))
.elseUse(ElementSelectors.byName)
.build()))
.build();
将 'bar' 小部件的 'id' 属性修改为 21
这会产生结果:
3 diffs
- type = child nodelist sequence
- message = Expected child nodelist sequence '1' but was '2' - comparing <ns2:widget...> at /policy[1]/widgets[1]/widget[2] to <ns2:widget...> at /policy[1]/widgets[1]/widget[3]
- type = attribute value
- message = Expected attribute value '19' but was '21' - comparing <ns2:widget id="19"...> at /policy[1]/widgets[1]/widget[2]/@id to <ns2:widget id="21"...> at /policy[1]/widgets[1]/widget[3]/@id
- type = child
- message = Expected child 'null' but was '{com.xyz}widget' - comparing <NULL> to <ns2:widget...> at /policy[1]/widgets[1]/widget[2]
这似乎正确地说“小部件 2 已移至小部件 3,小部件 2 的 id 从 19 更改为小部件 3 的 id 值为 21,并添加了新的小部件 2。”
唯一仍然缺少的是如何对任意标签和属性执行此操作。
解决方案
推荐阅读
- python - 在pdf视图中执行js
- python - 适合数据点的角臂
- xamarin - MvvmCross 和使用 MvxContentView 导航
- spring-boot - Spring @transactional 在存储库中不起作用
- php - 我需要将文件另存为 name_01,name_02
- javascript - 检查特定无线电输入时激活禁用文本
- docker - Docker Registry API 2.0 查找重复标签
- google-apps-script - Google Script - 将数据从一个工作簿复制到另一个 - importrange() 替代方案
- r - 使用拟合模型或 nls 函数约束 coef 输出
- mysql - 完成批量插入后如何启动MYSQL触发器?