【问题标题】:XMLUnit compare XML not working where parent node contains multiple child nodes of same name and attributes list but different attribute valuesXMLUnit比较XML不起作用,其中父节点包含多个具有相同名称和属性列表但属性值不同的子节点
【发布时间】:2020-04-15 15:27:33
【问题描述】:

我正在使用 XMLUnit 比较两个 XML 以检测更新。我的 pom 是这样的:

<dependency>
    <groupId>xmlunit</groupId>
    <artifactId>xmlunit</artifactId>
    <version>1.6</version>
</dependency>

对于大多数情况,XMLUnit 工作正常,除了少数情况下给定的差异是错误的或意外的。让我们先来看一下 XMLUnit 正常工作的积极场景:

案例 1:

XML 原件:

<ClassHours>                          
    <Hours close="11:10" day="27" classname="sec-1" open="17:20" noOfStudent="23"/>
    <Hours close="11:10" day="28" classname="sec-2" open="17:20" noOfStudent="43"/>
    <Hours close="11:10" day="21" classname="sec-3" open="17:20" noOfStudent="12"/>
    <Hours close="11:10" day="1" classname="sec-4" open="17:20" noOfStudent="54"/>
    <Hours close="11:10" day="25" classname="sec-5" open="17:20" noOfStudent="22"/>
    <Hours close="11:10" day="1" classname="sec-6" open="17:20" noOfStudent="10"/>      s
</ClassHours>

XML 更新:

<ClassHours>                          
    <Hours close="18:00" day="27" classname="sec-1" open="10:00" noOfStudent="23"/>
    <Hours close="18:00" day="28" classname="sec-2" open="10:00" noOfStudent="43"/>
    <Hours close="18:00" day="21" classname="sec-3" open="10:00" noOfStudent="12"/>
    <Hours close="18:00" day="1" classname="sec-4" open="10:00" noOfStudent="54"/>
    <Hours close="18:00" day="25" classname="sec-5" open="10:00" noOfStudent="22"/>
    <Hours close="18:00" day="1" classname="sec-6" open="10:00" noOfStudent="10"/>      s
</ClassHours>

如您所见,父节点包含多个子节点。对于所有子节点,名称和属性都相同,唯一的区别是打开和关闭属性值。在这种情况下,输出是:

2019-12-24 19:53:28,093  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:53:28,093  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:53:28,093  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:53:28,093  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:53:28,093  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:53:28,095  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:53:28,096  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:53:28,096  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:53:28,096  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:53:28,096  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:53:28,097  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:53:28,097  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]

案例 2:

XML 原件:

<ClassHours>                          
    <Hours close="11:10" day="27" classname="sec-1" open="17:20" noOfStudent="23"/>
    <Hours close="11:10" day="28" classname="sec-2" open="17:20" noOfStudent="43"/>
    <Hours close="11:10" day="21" classname="sec-3" open="17:20" noOfStudent="12"/>
    <Hours close="11:10" day="1" classname="sec-4" open="17:20" noOfStudent="54"/>
    <Hours close="11:10" day="25" classname="sec-5" open="17:20" noOfStudent="22"/>
    <Hours close="11:10" day="1" classname="sec-6" open="17:20" noOfStudent="10"/>      s
</ClassHours>

XML 更新:

<ClassHours>    
    <Hours close="18:00" day="28" classname="sec-2" open="10:00" noOfStudent="43"/>
    <Hours close="18:00" day="21" classname="sec-3" open="10:00" noOfStudent="12"/>
    <Hours close="18:00" day="27" classname="sec-1" open="10:00" noOfStudent="23"/>
    <Hours close="18:00" day="1" classname="sec-4" open="10:00" noOfStudent="54"/>
    <Hours close="18:00" day="25" classname="sec-5" open="10:00" noOfStudent="22"/>
    <Hours close="18:00" day="1" classname="sec-6" open="10:00" noOfStudent="10"/>      s
</ClassHours>

这里,对于所有的子节点,名称和属性都是相同的,区别在于OpenClose属性值。这次节点的顺序也随着类名 sec-3 行在 sec-2 之后移动而更新。在这种情况下,输出是:

2019-12-24 19:54:31,737  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [classname], Before value : [sec-1], After value : [sec-2]]
2019-12-24 19:54:31,738  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:54:31,738  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [day], Before value : [27], After value : [28]]
2019-12-24 19:54:31,738  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [noOfStudent], Before value : [23], After value : [43]]
2019-12-24 19:54:31,738  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:54:31,740  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [classname], Before value : [sec-2], After value : [sec-3]]
2019-12-24 19:54:31,740  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:54:31,740  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [day], Before value : [28], After value : [21]]
2019-12-24 19:54:31,741  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [noOfStudent], Before value : [43], After value : [12]]
2019-12-24 19:54:31,741  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:54:31,741  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [classname], Before value : [sec-3], After value : [sec-1]]
2019-12-24 19:54:31,741  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:54:31,741  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [day], Before value : [21], After value : [27]]
2019-12-24 19:54:31,741  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [noOfStudent], Before value : [12], After value : [23]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]

这里的输出是错误的,因为差异仅在于值,但 XMLUnit 也在考虑节点的顺序并给出这样的输出。

我的代码是:

    LOGGER.debug("Comparing Actual and Expected XMLs");
    XMLUnit.setIgnoreWhitespace(true);
    XMLUnit.setIgnoreAttributeOrder(true);
    XMLUnit.setIgnoreComments(true);
    DetailedDiff diff = new DetailedDiff(XMLUnit.compareXML(expectedXML, actualXML));
    diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());

    return diff.getAllDifferences();

谁能告诉我如何解决这个问题?我也试过添加

diff.overrideDifferenceListener(new IgnoreTextAndAttributeValuesDifferenceListener());
diff.overrideElementQualifier(new RecursiveElementNameAndTextQualifier());

并且仍然得到相同的结果。此外,我无法控制 XML 节点的顺序,因为它来自其他一些外部系统。我需要修复以在比较节点属性时忽略序列。

另外,我已经提到这是 XMLUnit 不工作的唯一情况。对于所有其他情况,它都按预期工作。

【问题讨论】:

  • 恕我直言 XmlUnit 是正确的;如果您在文本中切换段落,您也不会认为它们相同,对吗?经验法则:如果一个父元素中有多个相同类型的元素,那么顺序很重要;如果父元素中有不同的元素,顺序无关紧要。

标签: java xmlunit


【解决方案1】:

您正在使用ElementNameAndAttributeQualifier 的无参数构造函数,这意味着如果两个元素的名称相同并且它们的所有属性具有相同的值,则它们有资格进行比较。这对于您示例中的任何一对元素都不是这样,因为 close 属性都是不同的。所以根本没有匹配项。

在 XMLUnit 1.x 中,默认行为是将没有匹配伙伴的元素按照文档顺序与测试文档中没有匹配伙伴的元素进行匹配。所以实际上你是在按顺序比较元素。

您可以做的一件事是通过列出您希望在构造函数中保持相同值的属性来使ElementNameAndAttributeQualifier 更加具体。您可能还想将XMLUnit.setCompareUnmatched 设置为false,这样您就不会因错误的默认值而绊倒——或者更好的是,切换到XMLUnit 2.x,它与1.x 不同,它得到了积极维护,并且永远不会将不匹配的节点与彼此。

【讨论】:

  • 感谢@Stefan 的回答。在我的场景中,它在进行更改后现在可以工作,diff.overrideElementQualifier(new ElementNameAndAttributeQualifier("classname")); 即我告诉它比较考虑 classname 属性作为参考的节点比较。这将忽略节点的顺序。到目前为止,我的问题已经解决,因为我正在保存自己以跳转到 HTMLUnit 2 并修改代码。无论如何还是非常感谢... :)
猜你喜欢
  • 1970-01-01
  • 2020-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多