如何验证 xpath 模式在 Wiremock 中不匹配?

问题描述 投票:0回答:1

我正在开发一个测试用例,该用例断言 Wiremock 存根的 xml 请求正文没有

xmlns
属性。 到目前为止,我已经尝试使用
equalToXml
匹配器,但据我所知,这是忽略属性。

String customerXml = "<customer xmlns=\"http://example.com\"><name>Jon Doe</name><age>39</age></customer>";
WireMock.stubFor(
    WireMock.get(urlEqualTo("/someservice/customers/123"))
        .willReturn(
            WireMock.aResponse()
                .withStatus(HttpStatus.OK.value())
                .withBody(customerXml)));
Customer customer = customersService.getCustomer(123);

WireMock.stubFor(
    WireMock.post(urlEqualTo(
        "/otherservice/customers/123"))
        .willReturn(
            WireMock.aResponse()
                .withStatus(HttpStatus.CREATED.value())));

Customer customerInSecondSystem = customersService.createCustomer(customer);

String expectedRequestBody = "<customer><name>Jon Doe</name><age>39</age></customer>";
verify(WireMock.postRequestedFor(urlEqualTo("/otherservice/customers/123"))
    .withRequestBody(equalToXml(expectedRequestBody))); // this will pass even though
                                                        // the xmlns attribute is present in the xml

然后我尝试想出一个可以使用的 XPath 表达式:

String expectedRequestBody = "<customer><name>Jon Doe</name><age>39</age></customer>";
verify(WireMock.postRequestedFor(urlEqualTo("/otherservice/customers/123"))
    .withRequestBody(equalToXml(expectedRequestBody))
    .withRequestBody(matchingXPath("*[@xmlns='http://example.com']")));

这将积极匹配 xml 中的

xmlns
属性。 现在,我必须如何制定 XPath 来否定匹配
xmlns
属性(以确保它不存在)?

java xpath wiremock
1个回答
0
投票

虽然命名空间声明具有属性的语法形式,但它们在 XPath 1.0 数据模型中不被视为属性。所以实际上对于以下 XML 文档,

<customer xmlns="http://example.com"/>

...以下 XPath 表达式不应返回任何内容:

/customer/@xmlns

相反,名称空间声明在 XPath 的数据模型中显示为“名称空间节点”。每个命名空间节点都有一个前缀(可以为空)和一个 URI。

如果命名空间声明的形式为

xmlns="http://example.com/"
,那么这将设置一个所谓的“默认命名空间”,其命名空间前缀为空。如果声明的形式为
xmlns:foo="http://example.com/"
,则命名空间前缀为“foo”,但在这两种情况下,命名空间 URI(实际上是声明的重要部分)为
http://example.com/

对于给定元素,您可以使用

namespace-uri()
函数访问其命名空间 URI;使用 local-name() 函数计算其名称
不带前缀
,使用 name() 函数计算其名称
包括任何前缀

注意,在下面的两个文档中,根元素的名称被认为是相同的(!)。 XML 元素的名称是由两个值组成的 pair:“本地”部分(在这两种情况下都是

customer
)和名称空间 URI(在这两种情况下都是
http://example.com/
)。命名空间前缀(分别为“”和“
foo
”)并不重要。

<foo:customer xmlns:foo="http://example.com/"/>
<customer xmlns="http://example.com/"/>

您可以使用

namespace
轴访问 XPath 中的命名空间节点。例如以下表达式将返回根
customer
元素范围内的命名空间节点:

/customer/namespace::node()

您可以在命名空间节点上使用

local-name()
函数来读取其前缀,并使用
string()
函数来读取其命名空间 URI。

从你的问题中不清楚你真正打算施加什么限制。从表面上看,听起来您想要检查根元素上是否没有默认命名空间的声明,但我猜测您可能想要的是检查根元素的命名空间 URI 是否为空(即根元素的名称不属于命名空间):

namespace-uri(/*) = ''

如果事实上您确实想检查根元素是否没有声明“默认”命名空间,那么您可以使用这个布尔 XPath 表达式:

not(/*/namespace::node()[local-name(.)=''])

(意思是“根元素有一个名称空间前缀为空的名称空间节点”)。

© www.soinside.com 2019 - 2024. All rights reserved.