如何配置XmlUnit/XmlUnit.Net比较XML时忽略声明差异?
嘿,我明白你遇到的问题了——用NodeFilter没法忽略XML声明差异很正常,因为XML声明压根不算标准DOM节点!让我给你讲清楚XmlUnit(Java)和XmlUnit.Net分别该怎么配置,解决你的测试用例问题。
你的测试用例很明确:
控制文档:
<?xml version="1.0" encoding="utf-8"?> <a><amount>1</amount></a>
待比较文档:<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <a><amount>1</amount></a>
期望:两份文档比较无差异
XmlUnit 2.x提供了直接忽略XML声明的API,你不需要用NodeFilter,只需要在构建Diff的时候调用ignoreDeclaration()方法即可,它会跳过整个XML声明部分的比较:
import org.xmlunit.builder.DiffBuilder; import org.xmlunit.diff.Diff; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; public class XmlComparisonTest { public void testIgnoreXmlDeclaration() { String controlXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?> <a><amount>1</amount></a>"; String testXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?> <a><amount>1</amount></a>"; // 构建Diff并忽略XML声明 Diff diff = DiffBuilder.compare(Input.fromString(controlXml)) .withTest(Input.fromString(testXml)) .ignoreDeclaration() // 关键配置:忽略XML声明的所有差异 .build(); // 断言无差异 assertThat(diff.hasDifferences(), is(false)); } }
这个方法会忽略XML声明里的版本号、编码(包括大小写差异)、standalone属性等所有内容,只比较文档的实际内容部分。
XmlUnit.Net里同样不能用NodeFilter处理XML声明,你需要使用CompareOptions.IgnoreDeclaration这个枚举值来配置比较规则,下面是两种常用的实现方式:
方式一:使用XmlComparer
using XmlUnit.Net; using Xunit; public class XmlComparisonTests { [Fact] public void IgnoreXmlDeclaration_ShouldMatch() { string controlXml = @"<?xml version=""1.0"" encoding=""utf-8""?> <a><amount>1</amount></a>"; string testXml = @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> <a><amount>1</amount></a>"; // 初始化XmlComparer时指定忽略XML声明 var comparer = new XmlComparer(CompareOptions.IgnoreDeclaration); var comparisonResult = comparer.Compare(controlXml, testXml); // 验证无差异 Assert.False(comparisonResult.HasDifferences); } }
方式二:使用DiffBuilder
如果你习惯用Builder模式构建比较规则,也可以这样写:
using XmlUnit.Net.Builder; using Xunit; public class XmlComparisonTests { [Fact] public void IgnoreXmlDeclaration_WithDiffBuilder() { string controlXml = @"<?xml version=""1.0"" encoding=""utf-8""?> <a><amount>1</amount></a>"; string testXml = @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> <a><amount>1</amount></a>"; var diff = DiffBuilder.Compare(Input.FromString(controlXml)) .WithTest(Input.FromString(testXml)) .WithCompareOptions(CompareOptions.IgnoreDeclaration) // 关键配置 .Build(); Assert.False(diff.HasDifferences); } }
你之前尝试的NodeFilter之所以无效,是因为XML声明不属于DOM树中的任何节点类型。DOM规范里,XML声明是文档的元数据,不是元素、属性、文本或处理指令节点,所以NodeFilter无法捕获到它,自然没法过滤掉这部分的比较。必须用XmlUnit专门提供的忽略声明的配置项才行。
内容的提问来源于stack exchange,提问作者RMo

