XML单元比较 XML 在父节点包含多个名称和属性列表相同但属性值不同的子节点时不起作用

XMLUnit compare XML not working where parent node contains multiple child nodes of same name and attributes list but different attribute values

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

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

对于大多数情况,XMLUnit 工作正常,除了少数情况下给定的差异是错误的或意外的。让我们首先考虑 XML 单元正常工作的积极情况:

案例一:

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>

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

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]]

案例二:

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 不工作的唯一情况。对于所有其他情况,它按预期工作。

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

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

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