所以我有以下输入,预期输出和实际输出xml:
input.xml
<Request>
<EmailSubjectLine>Main Contact & No Reported To</EmailSubjectLine>
<ProductRq>
<Signon>
<ClientDt>1/6/2017 11:25:45 AM</ClientDt>
<CustLangPref>en-US</CustLangPref>
</Signon>
<SvcRq>
<RqUID>xxxxxxxx-2802-xxxx-xxxx-bf8361xxxxxx</RqUID>
<NotificationRq>
<TransactionRequestDt>2017-01-06</TransactionRequestDt>
<Currency>USD</Currency>
</NotificationRq>
</SvcRq>
</ProductRq>
<!-- rest of input -->
</Request>
预期输出.xml
<ProductRq xmlns="http://test.org/standards/intake">
<Audit>
<TransID>Test</TransID>
</Audit>
<Signon>
<ClientDt>1/6/2017 11:25:45 AM</ClientDt>
<CustLangPref>en-US</CustLangPref>
</Signon>
<SvcRq>
<RqUID>xxxxxxxx-2802-xxxx-xxxx-bf8361xxxxxx</RqUID>
<NotificationRq>
<RqUID>Test</RqUID>
<TransactionRequestDt>2017-01-06</TransactionRequestDt>
<Currency>USD</Currency>
</NotificationRq>
</SvcRq>
<!-- rest of expected-output -->
</ProductRq>
实际输出.xml
<ProductRq xmlns="http://test.org/standards/intake">
<Audit>
<TransID>123534Abwe-asdcv-1258qw-asd</TransID>
</Audit>
<Signon>
<ClientDt>1/6/2017 11:25:45 AM</ClientDt>
<CustLangPref>en-US</CustLangPref>
</Signon>
<SvcRq>
<RqUID>xxxxxxxx-2802-xxxx-xxxx-bf8361xxxxxx</RqUID>
<NotificationRq>
<RqUID>CG-17Dawe-12354-Hw35Sf</RqUID>
<TransactionRequestDt>2017-01-06</TransactionRequestDt>
<Currency>USD</Currency>
</NotificationRq>
</SvcRq>
<!-- rest of actual-output -->
</ProductRq>
我将它们与以下Diff设置进行比较:
MyTest.java
Diff diff = DiffBuilder
.compare(xmlExpectedOutput)
.withTest(xmlOutput)
.normalizeWhitespace()
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.conditionalBuilder()
.whenElementIsNamed("Audit")
.thenUse(ElementSelectors.byXPath("./TransID", ElementSelectors.byName))
.whenElementIsNamed("NotificationRq")
.thenUse(ElementSelectors.byXPath("./RqUID", ElementSelectors.byName))
.elseUse(ElementSelectors.byNameAndText)
.build()
))
.checkForSimilar()
.build();
当我运行上述输入并将其与Expected-output.xml进行比较时,我得到以下区别:
[Expected child '{http://test.org/standards/intake}RqUID' but was 'null' - comparing <RqUID...> at /ProductRq[1]/SvcRq[1]/NotificationRq[1]/RqUID[1] to <NULL> (DIFFERENT), Expected child 'null' but was '{http://test.org/standards/intake}RqUID' - comparing <NULL> to <RqUID...> at /ProductRq[1]/SvcRq[1]/NotificationRq[1]/RqUID[1] (DIFFERENT)]
我不明白为什么我的Element选择器不起作用,我使用不正确吗?我的目标是在找到TransmissionId或NotificationRq / RqUID时,仅通过名称将它们与预期的输出版本匹配,否则将名称和文本用于其他元素,因为这些元素包含唯一的生成的ID,这些ID会更改每次测试运行并且无法预测(以期以后创建一个更复杂的选择器,例如,通过名称和属性比较ProductRq来添加名称空间)。我缺少什么吗,我是否可以将两个XPath选择器组合在一起,而不是将多个when / then行和默认情况组合在一起?
注意:xml是通过xslt转换的。源文件上没有PRoductRq上的名称空间;复制源,将名称空间添加到ProductRq,然后与一些元素删除/修改/添加一起发送以进行输出
最佳答案
XMLUnit表示RqUID
中的NotificationRq
元素不匹配,当然它们是不同的。
.whenElementIsNamed("NotificationRq")
.thenUse(ElementSelectors.byXPath("./RqUID", ElementSelectors.byName))
意思是:当XMLUnit尝试为
NotificationRq
元素寻找伙伴时,它必须搜索具有NotificationRq
子元素的RqUID
-仅使用RqUID
元素。它没有为任何其他元素设置任何规则,尤其是
RqUID
本身。对于RqUID
元素,默认规则适用,.elseUse(ElementSelectors.byNameAndText)
说:XMLUnit只接受两个元素作为对,如果它们的名称和嵌套文本匹配。所讨论的
RqUID
元素不是这种情况。您整个
ElementSelector
说如果
Audit
的子元素具有任意内容,则匹配TransID
。如果
NotificationRq
具有任意内容,则匹配RqUID
。否则使用元素名称和嵌套文本
这不适合您的示例。查看您可能想要的XML
通过元素名称和嵌套文本匹配几乎所有内容(尽管从示例中,元素名称就足够了)
忽略
TransId
个子元素的Audit
个嵌套文本忽略
RqUID
的NotificationRq
子级的嵌套文本对于“名为
foo
的元素,如果它是名为bar
的元素的子元素”,则没有内置谓词,它可能类似于Predicate<Element> transIdInAudit = e -> {
if (e == null || e.getParentNode() == null) {
return false;
}
return "TransID".equals(e.getLocalName()) && "Audit".equals(e.getParentNode().getLocalName());
};
您可能想使它泛化:-)
这样你会用
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.conditionalBuilder()
.when(transIdInAudit)
.thenUse(ElementSelectors.byName)
.when(rqUIDInNotificationRq) // similar to transIdInAudit
.thenUse(ElementSelectors.byName)
.elseUse(ElementSelectors.byNameAndText)
.build())
如果它们具有匹配的
SvcRq
,也许您真的想匹配RqUID
,也许没有。如果是这样,您将使用当前用于NotificationRq
的结构。这本身不足以忽略匹配的
TransId
和RqUID
元素的嵌套文本,只能确保XMLUnit选择您要使用的节点。对于嵌套文本,您将需要DifferenceEvaluator
。假设默认情况下使用的是
ElementSelectors.byNameAndText
,则您知道所有匹配节点的嵌套文本都相同,除了您要忽略内容的两个特定元素之外。所以像DifferenceEvaluator
DifferenceEvaluators.chain(DifferenceEvaluators.Default,
DifferenceEvaluators.downgradeDifferencesToEqual(ComparisonType.TEXT_VALUE))
应该管用。