XMLUnit 比较忽略元素的顺序



我有 2 个 XML。我一直在使用XMLUnit来比较2个xml字符串。问题是我无法忽略元素出现的顺序。我尝试覆盖ElementQualifier和DifferenceListener,但这对这种情况没有帮助。

控件 XML

<xs:complexType>
    <xs:anotation>
        <xs:description>
            <Description>Country</Description>
        </xs:description>
    </xs:anotation>
    <xs:sequence>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="address" type="xs:string"/>
        <xs:element name="city" type="xs:string"/>
        <xs:element name="country" type="xs:string"/>
    </xs:sequence>
</xs:complexType>

测试XML

<xs:complexType>
    <xs:anotation>
        <xs:description>
            <Description>Country</Description>
        </xs:description>
    </xs:anotation>
    <xs:sequence>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="address" type="xs:string"/>
    </xs:sequence>
    <xs:sequence>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="address" type="xs:string"/>
        <xs:element name="city" type="xs:string"/>
        <xs:element name="street" type="xs:string"/>
    </xs:sequence>
</xs:complexType>

请注意,在测试 XML 中,添加了另一个序列,并删除了第一个序列的最后一个元素(国家/地区(。

XMLUnit抱怨没有名为city的元素,该元素位于第二个序列中。它按顺序获取元素。我尝试覆盖ELementName和AttributeQualifier,但没有产生预期的结果。此外,覆盖RecursiveElemenNameAndTextQualifier也无济于事。RecursiveElemenNameAndTextQualifier不起作用的原因是因为第一个序列不匹配。我将如何处理并确保

public boolean qualifyForComparison(Element element, Element element1) 
{
       // should return true only when **element 1** has all elements of  **element**
 }

真的比"忽略元素顺序"复杂一点,不是吗? :-(

ElementNameAndAttributeQualifier对于xs:element元素来说很好,但您真正的问题是让 XMLUnit 选择正确的xs:sequence元素。我真的建议您使用 XMLUnit 2.x,因为它的条件元素选择器构建器是您需要的,并且在 XMLUnit 1.x 中复制它有点痛苦。

如果您的自定义元素选择器按照您的评论进行操作,那么您根本不会选择要比较xs:sequence元素。"测试"序列不包含"街道"xs:elementElementNameQualifier将返回false

我不太确定你想要的确切逻辑是什么样子的。您在评论中描述的内容是这样的(使用 XMLUnit 2.x,未经测试(

public boolean canBeCompared(Element e1, Element e2) {
    NodeList e1Children = e1.getChildNodes();
    NodeList e2Children = e2.getChildNodes();
    Iterable<Map.Entry<Node, Node>> matches =
        new DefaultNodeMatcher(ElementSelectors.byNameAndAllAttributes)
        .match(new IterableNodeList(e1Children), new IterableNodeList(e2Children));
    for (Map.Entry<Node, Node> m : matches) {
        if (m.getKey() == null // test child with no matching control child
            || m.getValue() == null // control child with no matching test child
        ) {
            return false;
        }
    }
    return true;
}

没有内置的方法可以做到这一点,你真的需要自己对抗 DOM。

最后你会使用类似的东西

ElementSelectors.conditionalBuilder()
    .whenElementIsNamed(new QName("sequence", XMLConstants.W3C_XML_SCHEMA_NS_URI))
    .thenUse(the element selector built above)
    .elseUse(ElementSelectors.byNameAndAllAttributes)
    .build();

当为差分发动机供电时。