xmlunit:错误 ElementSelectors.conditionalBuilder

xmlunit: Error with ElementSelectors.conditionalBuilder

所以我有以下输入、预期输出和实际输出xml:

input.xml

<Request>
  <EmailSubjectLine>Main Contact &amp; 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>

预期-output.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>

实际-output.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)]

我不明白为什么我的元素选择器不起作用,是我使用不当吗?我的目并且无法预测(为了稍后创建更复杂的选择器,例如通过名称和属性比较 ProductRq,因为将名称空间添加到此)。有没有我遗漏的东西,我能否将 2 个 XPath 选择器组合在一起而不是几个 when/then 行和默认大小写?

注意:xml 是通过 xslt 转换的。 PRoductRq 上的命名空间在源文档中不存在;源被复制,命名空间被添加到 ProductRq,然后与一些元素一起被发送输出 removals/modifications/additions

XML单元表示 NotificationRq 中的 RqUID 元素不匹配,当然它们是不同的。

.whenElementIsNamed("NotificationRq")
.thenUse(ElementSelectors.byXPath("./RqUID", ElementSelectors.byName))

意味着:当 XMLUnit 尝试为 NotificationRq 元素寻找伙伴时,它必须搜索具有 RqUID [=87 的 NotificationRq =] - 并且只使用 RqUID 元素。

它没有为任何其他元素设置任何规则,特别是 RqUID 本身。对于 RqUID 个元素,默认规则适用并且

.elseUse(ElementSelectors.byNameAndText)

说:XMLUnit 只接受两个成对的元素,前提是它们的名称和嵌套文本匹配。对于有问题的 RqUID 个元素,情况并非如此。

你的整个ElementSelector

  • 匹配 Audits 如果他们有 TransID children 任意内容。
  • 匹配 NotificationRq 个,如果它们有 RqUID 个任意内容。
  • 否则使用元素名称和嵌套文本

这不符合您的示例。看看你的 XML 你可能想要

  • 通过元素名称和嵌套文本匹配几乎所有内容(尽管从示例中元素名称就足够了)
  • 忽略 TransId children of Audits
  • 的嵌套文本
  • 忽略 RqUID children 的 NotificationRq
  • 的嵌套文本

"element named foo if it is a child of an element named bar" 没有 built-in 谓词,它可能类似于

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.

的结构

这本身不足以忽略匹配的 TransIdRqUID 元素的嵌套文本,它只会确保 XMLUnit 将选择您想要的节点使用。对于嵌套文本,您需要 DifferenceEvaluator.

鉴于您默认使用 ElementSelectors.byNameAndText,您知道嵌套文本对于所有匹配的节点都是相同的,除了您想忽略内容的两个特定元素。所以DifferenceEvaluator喜欢

DifferenceEvaluators.chain(DifferenceEvaluators.Default,
    DifferenceEvaluators.downgradeDifferencesToEqual(ComparisonType.TEXT_VALUE))

应该可以。