如何使用 XMLLINT 和 BASH 解析 XML 文件中的命名空间

如何使用 XMLLINT 和 BASH 解析 XML 文件中的命名空间

下面是一个用于跟踪库存的 Adob​​e XML swidtag 示例。我需要在 bash 中使用 xmllint 解析相关信息并将其输出到新的文本文件。

例如我想解析以下内容

swid:entitlement_required_indicator
swid:product_title
swid:product_version
swid:name
swid:numeric
swid:major
swid:minor
swid:build
swid:review

我尝试过使用它,但它不会让我读取名称空间

xmllint --xpath '//swid:product_version/swid:name/text()' file.xml

我也尝试过

xmllint --xpath "//*[local-name1()='product_version']/*[local-name2()='name']/text()" file.xml

但出现了这些错误

xmlXPathCompOpEval: function local-nameame1 not found
XPath error : Unregistered function
XPath error : Stack usage errror
XPath evaluation failure

Creative Suite 5 的示例标记文件 以下示例适用于序列号为 Creative Suite 5 Master Collection(套件)的 Adob​​e Photoshop CS5

<?xml version="1.0" encoding="utf-8"?>
<swid:software_identification_tag xsi:schemaLocation="http://standards.iso.org/iso/19770/-2/2008/schema.xsd software_identification_tag.xsd" 
     xmlns:swid="http://standards.iso.org/iso/19770/-2/2008/schema.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<!--Mandatory Identity elements -->
<swid:entitlement_required_indicator>true</swid:entitlement_required_indicator>
<swid:product_title>Acrobat XI Pro</swid:product_title>
<swid:product_version>
    <swid:name>1.0</swid:name>
    <swid:numeric>
        <swid:major>1</swid:major>
        <swid:minor>0</swid:minor>
        <swid:build>0</swid:build>
        <swid:review>0</swid:review>
    </swid:numeric>
</swid:product_version>
<swid:software_creator>
    <swid:name>Adobe Systems Incorporated</swid:name>
    <swid:regid>regid.1986-12.com.adobe</swid:regid>
</swid:software_creator>
<swid:software_licensor>
    <swid:name>Adobe Systems Incorporated</swid:name>
    <swid:regid>regid.1986-12.com.adobe</swid:regid>
</swid:software_licensor>
<swid:software_id>
    <swid:unique_id>CreativeCloud-CS6-Mac-GM-MUL</swid:unique_id>
    <swid:tag_creator_regid>regid.1986-12.com.adobe</swid:tag_creator_regid>
</swid:software_id>

<swid:tag_creator>
    <swid:name>Adobe Systems Incorporated</swid:name>
    <swid:regid>regid.1986-12.com.adobe</swid:regid>
</swid:tag_creator>
<!--Optional Identity elements -->
<swid:license_linkage>
    <swid:activation_status>activated</swid:activation_status>
    <swid:channel_type>SUBSCRIPTION</swid:channel_type>
    <swid:customer_type>RETAIL</swid:customer_type>
</swid:license_linkage>
<swid:serial_number>909702426602037824854600</swid:serial_number>
</swid:software_identification_tag>

答案1

讨论很有启发性。

至少,即使不理想,你也应该能够做到:

xmllint --xpath "//*[local-name()='product_version']/*[local-name()='name']/text()" file.xml

或者使用xmlstarlet反而:

xmlstarlet sel -t -v //swid:product_version/swid:name file.xml

答案2

尝试使用此处文档。例子:

#!/bin/bash
xmllint --shell file.xml <<EOF
setns swid=http://standards.iso.org/iso/19770/-2/2008/schema.xsd
xpath //swid:product_version/swid:name/text()
EOF

适用于xmllint支持该--xpath参数的更高版本。

答案3

使用旧版本xmllint(不支持 --xpath)你可以设置一个命名空间并更直观地查询(但你必须 grep 出一些额外的垃圾):

#!/bin/bash
echo 'setns swid=http://standards.iso.org/iso/19770/-2/2008/schema.xsd
      cat //swid:product_version/swid:name/text()' | \
xmllint --shell file.xml | egrep -v '^(/ >| -----)'

答案4

我遇到了类似的问题,在 jenkins 的 shell 脚本中读取 pom.xml (maven 配置文件)。为了确保有一个好的结果,我会这样做:

xmllint --xpath "//swid:software_identification_tag/*[local-name()='product_version']/*[local-name()='name']/text()" file.xml

如果您的 xml 具有此类附加内容,那么您似乎不会遇到问题:

<swid:product_specifics>
<swid:product_version>
...
</swid:product_version>
</swid:product_specifics>

xmllint --xpath "//*[local-name()='product_version']/*[local-name()='name']/text()" file.xml行不通

在我的情况下,pom.xml 有许多“版本”元素,因此如果您想要一个特定的元素,路径应该是准确的,否则您将获得多个您不想要的值。

相关内容