使用XMLUnit比较XSD时忽略属性顺序无效的问题求助
问题:XMLUnit忽略XSD属性组内元素顺序差异的解决方案
我有两个XML文件,本质是两个XSD Schema,仅rowattr属性组中的object_level_ind属性顺序不同,希望对比时忽略该差异,但XMLUnit未将它们判定为“相似”。
第一个XSD文件
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="my_export_file"> <xsd:complexType> <xsd:sequence minOccurs="0" maxOccurs="unbounded"> <xsd:element name="row"> <xsd:complexType> <xsd:attributeGroup ref="rowattr" /> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attributeGroup ref="docelattr" /> </xsd:complexType> </xsd:element> <xsd:attributeGroup name="rowattr"> <xsd:attribute name="subject_level_ind" type="Str.1" use="optional" /> <xsd:attribute name="object_level_ind" type="Str.1" use="optional" /> <xsd:attribute name="src_system_id" type="Str.80" use="required" /> </xsd:attributeGroup> <xsd:attributeGroup name="docelattr"> <xsd:attribute name="reporting_date" type="xsd:string" /> <xsd:attribute name="interface_type" type="xsd:string" /> </xsd:attributeGroup> <xsd:simpleType name="Str.1"> <xsd:restriction base="xsd:string"> <xsd:maxLength value="1" /> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="Str.80"> <xsd:restriction base="xsd:string"> <xsd:maxLength value="80" /> </xsd:restriction> </xsd:simpleType> </xsd:schema>
第二个XSD文件
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="my_export_file"> <xsd:complexType> <xsd:sequence minOccurs="0" maxOccurs="unbounded"> <xsd:element name="row"> <xsd:complexType> <xsd:attributeGroup ref="rowattr" /> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attributeGroup ref="docelattr" /> </xsd:complexType> </xsd:element> <xsd:attributeGroup name="rowattr"> <xsd:attribute name="subject_level_ind" type="Str.1" use="optional" /> <xsd:attribute name="src_system_id" type="Str.80" use="required" /> <xsd:attribute name="object_level_ind" type="Str.1" use="optional" /> </xsd:attributeGroup> <xsd:attributeGroup name="docelattr"> <xsd:attribute name="reporting_date" type="xsd:string" /> <xsd:attribute name="interface_type" type="xsd:string" /> </xsd:attributeGroup> <xsd:simpleType name="Str.1"> <xsd:restriction base="xsd:string"> <xsd:maxLength value="1" /> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="Str.80"> <xsd:restriction base="xsd:string"> <xsd:maxLength value="80" /> </xsd:restriction> </xsd:simpleType> </xsd:schema>
已尝试的代码
第一种尝试
var fis1 = new FileReader("C:\Users\test1.xsd "); var fis2 = new FileReader("C:\Users\test2.xsd"); XMLUnit.setIgnoreWhitespace(true); XMLUnit.setIgnoreAttributeOrder(true); DetailedDiff diff = new DetailedDiff(XMLUnit.compareXML(fis1,fis2)); diff.overrideElementQualifier(new ElementNameAndTextQualifier()); List<?> allDifferences = diff.getAllDifferences(); System.out.println(allDifferences);
第二种尝试
DifferenceEvaluator evaluator = DifferenceEvaluators .downgradeDifferencesToEqual(ComparisonType.CHILD_NODELIST_SEQUENCE); Diff diff = DiffBuilder.compare(fis1) .withTest(fis2).ignoreComments() .ignoreWhitespace() .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byName)) .withDifferenceEvaluator(evaluator) .checkForSimilar() .build(); System.out.println("Differences: " + diff);
上述尝试后结果均显示:
identical: false 相似 : false
解决思路
核心问题说明:
xsd:attribute是XSD中的元素节点,而非XML元素的属性,所以setIgnoreAttributeOrder(true)只对XML元素的属性顺序生效,无法处理XSD里xsd:attribute元素的顺序差异。自定义节点匹配规则:针对
xsd:attributeGroup下的xsd:attribute元素,使用byNameAndAllAttributes规则匹配——只要元素名、name/type/use等属性完全一致,就视为匹配节点,忽略它们在属性组中的顺序。修改后的代码如下:Diff diff = DiffBuilder.compare(fis1) .withTest(fis2) .ignoreWhitespace() .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.conditionalBuilder() .whenElementIsNamed("xsd:attribute").thenUse(ElementSelectors.byNameAndAllAttributes()) .elseUse(ElementSelectors.byName()) .build())) .withDifferenceEvaluator(DifferenceEvaluators.downgradeDifferencesToEqual(ComparisonType.CHILD_NODELIST_SEQUENCE)) .checkForSimilar() .build();版本检查:确保使用XMLUnit 2.x版本,1.x版本的API灵活性不足,建议升级到2.x以获得更完善的节点匹配和差异评估能力。
调试验证:可以添加对比监听器打印详细对比过程,确认节点匹配情况,进一步调整规则:
diff.addListener(new ComparisonListener() { @Override public void comparisonPerformed(Comparison comparison, ComparisonResult outcome) { System.out.println(comparison.getDescription() + " - " + outcome); } });
内容的提问来源于stack exchange,提问作者Abhi
相关产品推荐
相关产品推荐

