XMLUnit比较忽略元素的顺序

时间:2018-03-08 09:23:48

标签: java xsd xmlunit xmlunit-2

我有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>

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

XMLUnit抱怨没有第二个序列中名为city的元素。它采用了有序的元素。我尝试覆盖 ELementNameAndAttributeQualifier ,但没有产生所需的结果。另外,覆盖 RecursiveElemenNameAndTextQualifier 也没有帮助。 RecursiveElemenNameAndTextQualifier 的原因不起作用,因为theres与第一个序列不匹配。我将如何处理并确保

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

1 个答案:

答案 0 :(得分:1)

这实际上比&#34;忽略元素顺序&#34;更复杂,不是吗? : - )

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

如果您的自定义元素选择器执行了您的评论所说的内容,则您根本不会选择要比较的xs:sequence元素。 &#34;测试&#34;序列没有包含&#34; street&#34; 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();

喂食差异引擎时。