3

I'm having a problem comparing various elements in my xml document with XMLUnit (2.2.1). In my document there are several xml elements and I want to know, whether they differ from each other. However, I don't want to compare all xml elements the same way. Sometimes I just want to compare them by their name.In other cases I want to compare them by name and attribute or name and text.

Here is an example (see the comments)

Control

<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
   <LANGUAGES>
      <!-- Compare LANGUAGE by Name and Attribute -->
      <LANGUAGE VALUE="DE" />
      <LANGUAGE VALUE="EN" />
      <LANGUAGE VALUE="IT" />
      <LANGUAGE VALUE="FR" />
   </LANGUAGES>
   <CODES>
      <!-- Compare CODE by Name and Text -->
      <CODE>10000-1</CODE>
      <CODE>20000-2</CODE>
      <CODE>30000-3</CODE>
      <CODE>40000-4</CODE>
   </CODES>
   <CONTACT> <!-- Compare CONTACT and Children just by Name -->
      <FIRSTNAME>Max</FIRSTNAME>
      <SURNAME>Mustermann</SURNAME>
   </CONTACT>
</ROOT>

Test:

<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
   <LANGUAGES>
      <!-- Compare LANGUAGE by Name and Attribute -->
      <LANGUAGE VALUE="DE" />
      <LANGUAGE VALUE="FR" />
   </LANGUAGES>
   <CODES>
      <!-- Compare CODE by Name and Text -->
      <CODE>20000-2</CODE>
      <CODE>40000-4</CODE>
   </CODES>
   <CONTACT> <!-- Compare CONTACT and Children by Name -->
      <FIRSTNAME>Tim</FIRSTNAME>
      <SURNAME>Mustermann</SURNAME>
   </CONTACT>
</ROOT>

I tried ElementSelectors in combination with ElementSelectors.conditionalBuilder (https://github.com/xmlunit/user-guide/wiki/SelectingNodes#conditional-elementselectors) to only apply an ElementSelector on a specific element (whenElementIsNamed). Maybe this isn't the right approach for what I want to achieve.

This is my code I use for testing:

public void xmlDiff() {
    String control = getControlDocument(); //
    String test = getTestDocument(); //
    Diff myDiff = DiffBuilder.compare(control)//
            .withTest(test) //
            .ignoreWhitespace() //
            .ignoreComments() //
            .checkForSimilar() //
            .withNodeMatcher(new DefaultNodeMatcher(partialElementSelector("LANGUAGE", ElementSelectors.byNameAndAllAttributes), partialElementSelector("CODE",ElementSelectors.byNameAndText), ElementSelectors.byName)) //
            .build();
    assertThat(myDiff.hasDifferences()).isTrue(); // 
}

    private ElementSelector partialElementSelector(final String expectedName, final ElementSelector elementSelector) {
        return ElementSelectors.conditionalBuilder().whenElementIsNamed(expectedName).thenUse(elementSelector).build();
    }

What I actually need is the information, that two LANGUAGEs (EN,IT) and two CODEs (10000-1,30000-3) have been removed (not replaced) and FIRSTNAME changed.

How can I get those information, with or without XML Unit (DiffBuilder)?

Thank you for your help!

4

1 回答 1

3

ElementSelector在 of 的构造函数中使用三个 s 和在多个条件下DefaultNodeMatcher使用单个s之间存在细微差别。ElementSelector

你想用三个选择器实现的也可以写成

ElementSelectors.conditionalBuilder()
    .whenElementIsNamed("LANGUAGE")
    .thenUse(ElementSelectors.byNameAndAllAttributes)
    .whenElementIsNamed("CODE")
    .thenUse(ElementSelectors.byNameAndText)
    .elseUse(ElementSelectors.byName)
    .build();

乍一看,这似乎做同样的事情,但事实并非如此。事实上它会起作用。这是我从你的例子中得到的:

Expected child nodelist length '4' but was '2' - comparing <LANGUAGES...> at /ROOT[1]/LANGUAGES[1] to <LANGUAGES...> at /ROOT[1]/LANGUAGES[1] (DIFFERENT)
Expected child 'LANGUAGE' but was 'null' - comparing <LANGUAGE...> at /ROOT[1]/LANGUAGES[1]/LANGUAGE[2] to <NULL> (DIFFERENT)
Expected child 'LANGUAGE' but was 'null' - comparing <LANGUAGE...> at /ROOT[1]/LANGUAGES[1]/LANGUAGE[3] to <NULL> (DIFFERENT)
Expected child nodelist length '4' but was '2' - comparing <CODES...> at /ROOT[1]/CODES[1] to <CODES...> at /ROOT[1]/CODES[1] (DIFFERENT)
Expected child 'CODE' but was 'null' - comparing <CODE...> at /ROOT[1]/CODES[1]/CODE[1] to <NULL> (DIFFERENT)
Expected child 'CODE' but was 'null' - comparing <CODE...> at /ROOT[1]/CODES[1]/CODE[3] to <NULL> (DIFFERENT)
Expected text value 'Max' but was 'Tim' - comparing <FIRSTNAME ...>Max</FIRSTNAME> at /ROOT[1]/CONTACT[1]/FIRSTNAME[1]/text()[1] to <FIRSTNAME ...>Tim</FIRSTNAME> at /ROOT[1]/CONTACT[1]/FIRSTNAME[1]/text()[1] (DIFFERENT)

所以这就是发生的事情:当 XMLUnit 使用您构建的第一个条件查看时,LANGUAGE将返回VALUE en所有候选元素。ElementSelectorfalseLANGUAGE

使用多参数DefaultNodeMatcher构造函数时,ElementSelector将询问下一个 - 在您的情况下也会返回false,因为它只对CODE元素感兴趣。然后咨询第三个ElementSelector,它将愉快地接受任何名为LANGUAGE.

当使用ElementSelector我在上面设置的单曲时,组合选择器将永远不会在 aPredicate返回后立即咨询任何替代方案trueLANGUAGE这意味着一旦选择器返回,就不会再考虑元素了false

我将尝试使用您的示例更新https://github.com/xmlunit/user-guide/wiki/SelectingNodes#nodematcher,并希望在改进文档方面获得您的帮助。

于 2017-05-04T12:58:20.653 回答