使用WireMock虚拟化XML API时XPath提取请求值失败求助
WireMock中通过XPath提取XML请求字段生成JSON响应问题
问题背景
使用WireMock独立jar包虚拟化XML格式的API,需要将请求XML中的特定标签值通过XPath提取,填充到JSON响应中。但尝试的XPath表达式均无法正常工作,还触发了UncheckedExecutionException。
请求示例(XML)
<Envelope xmlns="http://www.example.com/Envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Header> <SourceID>SOURCE_ID</SourceID> <Timestamp>2024-07-01T16:27:26Z</Timestamp> </Header> <Body> <Record> <Metadata> <Key> <Name>RequestNumber</Name> <Value>REQ12345</Value> </Key> </Metadata> </Record> </Body> </Envelope>
期望响应示例(JSON)
{ "event": { "source": "example", "type": "example_event", "timestamp": "2024-07-01T16:27:26Z", "payload": { "requestNumber": "REQ12345" } } }
尝试过的XPath表达式
{{{xpath request.body '//Key[Name="RequestNumber"]/Value/text()'}}}{{{xpath request.body '//*[local-name()="Key"]//*[local-name()="Name" and text()="RequestNumber"]/*[local-name()="Value"]/text()'}}}{{{xpath request.body '/*[local-name()="Envelope"]/*[local-name()="Body"]/*[local-name()="Record"]/*[local-name()="Metadata"]/*[local-name()="Key"]/*[local-name()="Name"][text()="RequestNumber"]/following-sibling::*[local-name()="Value"]/text()'}}}
解决方案
核心问题是XML命名空间未正确处理:请求XML的根节点带有默认命名空间xmlns="http://www.example.com/Envelope",所有子节点都属于该命名空间,直接用标签名或简单的local-name写法会匹配失败。
方法1:绑定命名空间(推荐,可读性更高)
WireMock的XPath支持通过namespaceContext参数绑定命名空间前缀,示例如下:
{{{xpath request.body '//env:Key[env:Name="RequestNumber"]/env:Value/text()' namespaceContext='{"env": "http://www.example.com/Envelope"}'}}}
方法2:修正local-name表达式
如果不想绑定命名空间,需要确保每个节点的local-name判断覆盖完整路径,同时处理文本节点的可能空格问题(比如normalize-space()避免空白字符干扰):
{{{xpath request.body '//*[local-name()="Key"][*[local-name()="Name" and normalize-space(text())="RequestNumber"]]/*[local-name()="Value"]/text()'}}}
完整WireMock映射示例
将上述XPath整合到响应模板中,完整的映射配置如下:
{ "request": { "method": "POST", "url": "/your-api-endpoint", "bodyPatterns": [ { "matchesXml": "//*[local-name()='Envelope']" } ] }, "response": { "status": 200, "headers": { "Content-Type": "application/json" }, "body": "{ \"event\": { \"source\": \"example\", \"type\": \"example_event\", \"timestamp\": \"{{{xpath request.body '//env:Timestamp/text()' namespaceContext='{\"env\": \"http://www.example.com/Envelope\"}'}}}\", \"payload\": { \"requestNumber\": \"{{{xpath request.body '//env:Key[env:Name=\"RequestNumber\"]/env:Value/text()' namespaceContext='{\"env\": \"http://www.example.com/Envelope\"}'}}}\" } } }", "transformers": ["response-template"] } }
注意事项
- 确保WireMock启用了
response-template转换器,启动命令需添加--extensions com.github.tomakehurst.wiremock.extension.responsetemplating - XPath中的引号需要正确转义,在JSON映射文件中,双引号需用
\"转义 - 使用
normalize-space()处理文本节点的空白字符,避免因XML格式化空格导致匹配失败
内容的提问来源于stack exchange,提问作者ANZAR AHSAN
相关产品推荐
相关产品推荐

