如何从soap响应中解析xpath以检索键值对

How to parse xpath from soap response to retrieve key value pair

提问人:Ranjeet 提问时间:9/9/2023 最后编辑:CyrusRanjeet 更新时间:9/9/2023 访问量:58

问:

使用 bash 我试图从下面的 soap 响应中提取 id 和 name 作为键值对,并希望将此对存储在 csv 文件中。 下面的 xmllint 命令返回不需要的值,因为我无法提供过滤器。 任何人都可以帮忙。 我愿意使用 xmllint 和 xmlstarlet。

我尝试过的xmllint命令:

xmllint --xpath "//*[local-name()='getAllUserApplicationsResponse']/*[local-name()='return']/*[local-name()='name']/text()" request.xml

要提取的元素:

    <ax2159:id>396112</ax2159:id>
    <ax2159:name>com.example.app.name</ax2159:name>

请注意,<ns:return></ns:return> 是一个重复元素。

肥皂响应:

<ns:getAllUserApplicationsResponse
    xmlns:ns="http://application.app.api.admin.abc.example.com"
    xmlns:ax2179="http://logging.app.api.admin.abc.example.com/xsd"
    xmlns:ax2169="http://stagingarea.app.api.admin.abc.example.com/xsd"
    xmlns:ax2159="http://types.core.api.admin.abc.example.com/xsd"
    xmlns:ax2171="http://permission.common.app.api.admin.abc.example.com/xsd"
    xmlns:ax2161="http://application.app.api.admin.abc.example.com/xsd"
    xmlns:ax2183="http://component.app.api.admin.abc.example.com/xsd"
    xmlns:ax2173="http://resinstance.app.api.admin.abc.example.com/xsd"
    xmlns:ax2165="http://status.app.api.admin.abc.example.com/xsd"
    xmlns:ax2176="http://svars.app.api.admin.abc.example.com/xsd"
    xmlns:ax2187="http://binding.app.api.admin.abc.example.com/xsd"
    xmlns:ax2155="http://exception.core.api.admin.abc.example.com/xsd"
    xmlns:ax2156="http://fixer.core.api.admin.abc.example.com/xsd">
    <ns:return
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ax2161:ApplicationShortDesc">
        <ax2159:id>396112</ax2159:id>
        <ax2159:name>com.example.app.name</ax2159:name>
        <ax2161:environment xsi:type="ax2159:EntityIdentifier">
            <ax2159:id>6175</ax2159:id>
            <ax2159:name>app_environment</ax2159:name>
        </ax2161:environment>
        <ax2161:folder xsi:type="ax2159:EntityIdentifier">
            <ax2159:id>34148</ax2159:id>
            <ax2159:name>MYAPP</ax2159:name>
        </ax2161:folder>
        <ax2161:runtimeState>Running</ax2161:runtimeState>
        <ax2161:runtimeStateEnum>RUNNING</ax2161:runtimeStateEnum>
    </ns:return>
</ns:getAllUserApplicationsResponse>
XML bash xml命名空间 xmlstarlet xmllint

评论


答:

1赞 pmf 9/9/2023 #1

对于此任务,您可以考虑使用 xq。它可以读取XML和写入CSV,并负责所有的引用和转义。

xq -r '."ns:getAllUserApplicationsResponse"."ns:return"
  | arrays[] // . | [."ax2159:id", ."ax2159:name"] | @csv
' request.xml
"396112","com.example.app.name"

评论

0赞 Ranjeet 9/9/2023
XQ真的很棒。我有点担心,因为“ax2159”可能会随着产品版本的变化而改变。是否可以将此xml转换为json?如果我尝试放置“accept: application/json”标头,API 将返回无效的 JSON。
0赞 pmf 9/9/2023
@Ranjeet当然。事实上,xq 内部已经将输入转换为 JSON,然后让 jq 接管所有繁重的工作。这里使用的过滤器实际上是用 jq 自己的 DSL 编写的,这是一个非常强大的 JSON 处理器(包括 reex 匹配来查找“更改名称”)。转换为 CSV(包括引用和转义)也是其中的一部分(请参阅此处)。仅要转换为 JSON,请使用 中的身份过滤器。@csv.xq . request.xml
0赞 LMC 9/9/2023 #2

这可以通过考虑命名空间的 shell 来完成xmllint

printf "%s\n" "setrootns" 'cat //ns:return/*[name()="ax2159:id" or name()="ax2159:name"]/text()' 'bye' | xmllint --shell test.xml 

原始结果

/ > setrootns
/ > cat //ns:return/*[name()="ax2159:id" or name()="ax2159:name"]/text()
 -------
396112
 -------
com.example.app.name
/ > bye

过滤不需要的行... | grep -vE '^\/ >| ---'

结果

396112
com.example.app.name

Xpath 也可以写成(可能更好)

//ns:return/ax2159:id/text() | //ns:return/ax2159:name/text()

评论

1赞 Léa Gris 9/9/2023
您不需要括号即可将其通过管道传递给 xmllint。它甚至适得其反,因为括号会生成一个 shell。如果确实需要通过管道传递多个命令的输出,请使用大括号,并在大括号内的每个命令后添加一个分号。但这里根本不需要:printf "%s\n" 'setrootns' 'cat //ns:return/*[name()="ax2159:id" or name()="ax2159:name"]/text()' 'bye' | xmllint --shell test.xml