Java 如何使用XMLUnit DiffBuilder检测属性和元素列表中的差异

Java 如何使用XMLUnit DiffBuilder检测属性和元素列表中的差异,java,xmlunit,Java,Xmlunit,我需要比较两个XML字符串,其中标记中的任意属性可能会发生更改,以及任意插入或删除标记序列中的标记 我发现如果我使用元素选择器.byname和text我会得到属性更改的适当差异,除非有序列插入或删除 我发现,如果我使用元素选择器.byname和allattributes我可以为插入或删除标签序列的标签获得适当的差异,但没有适当的属性可以更改细节 如何组合这两种差异生成机制 控制XML String myControlXML = "<?xml version='1.0' e

我需要比较两个XML字符串,其中标记中的任意属性可能会发生更改,以及任意插入或删除标记序列中的标记

我发现如果我使用元素选择器.byname和text我会得到属性更改的适当差异,除非有序列插入或删除

我发现,如果我使用元素选择器.byname和allattributes我可以为插入或删除标签序列的标签获得适当的差异,但没有适当的属性可以更改细节

如何组合这两种差异生成机制

控制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>";
差异结果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]
将“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]
3个差异
-类型=子节点列表序列
-message=应为子节点列表序列“1”,但为“2”-将at/policy[1]/widgets[1]/widget[2]与at/policy[1]/widgets[1]/widget[3]进行比较
-类型=属性值
-message=预期属性值“19”,但为“21”-将at/policy[1]/widgets[1]/widget[2]/@id与at/policy[1]/widgets[1]/widget[3]/@id进行比较
-类型=子类型
-message=应为子项“null”,但为“{com.xyz}widget”-与at/policy[1]/widgets[1]/widget[2]相比
这似乎是正确的说法:“小部件2被移动到小部件3,小部件2的id从19更改为小部件3的id值21,并添加了一个新的小部件2。”

唯一仍然缺少的是如何对任意标记和属性执行此操作

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]
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]
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]
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();
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]