Как использовать 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].

Заранее спасибо за любую помощь, которую вы можете мне оказать.

Редактировать:

Я нашел здесь частичный ответ игнорирование порядка узлов XML

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

Атрибут id виджета bar изменен на 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 изменился с 19 на значение идентификатора виджета 3, равное 21, и был добавлен новый виджет 2».

Единственное, чего еще не хватает, так это того, как это сделать для произвольных тегов и атрибутов.


person shifflettd    schedule 12.11.2020    source источник