You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用xmlstarlet通过XML注释匹配提取/修改数据?无方案用什么Bash工具?

通过注释匹配提取RRD XML中对应的值

问题场景

我有一份RRD格式的XML文件,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE rrd SYSTEM "https://oss.oetiker.ch/rrdtool/rrdtool.dtd">
<!-- Round Robin Database Dump -->
<rrd>
    <version>0003</version>
    <step>10</step> <!-- Seconds -->
    <lastupdate>1743206258</lastupdate> <!-- 2025-03-28 16:57:38 PDT -->

    <ds>
        <name> uptime_remote </name>
        <type> GAUGE </type>
        <minimal_heartbeat>600</minimal_heartbeat>
        <min>2.0000000000e+02</min>
        <max>2.0000000000e+02</max>

        <!-- PDP Status -->
        <last_ds>15508</last_ds>
        <value>2.0000000000e+02</value>
        <unknown_sec> 0 </unknown_sec>
    </ds>

    <!-- Round Robin Archives -->
    <rra>
        <cf>AVERAGE</cf>
        <pdp_per_row>1</pdp_per_row> <!-- 10 seconds -->

        <params>
        <xff>5.0000000000e-01</xff>
        </params>
        <cdp_prep>
            <ds>
            <primary_value>2.0000000000e+02</primary_value>
            <secondary_value>2.0000000000e+02</secondary_value>
            <value>2.0000000000e+02</value>
            <unknown_datapoints>0</unknown_datapoints>
            </ds>
        </cdp_prep>
        <database>
            <!-- 2025-03-27 16:57:40 PDT / 1743119860 --> <row><v>2.0000000000e+02</v></row>
            <!-- 2025-03-27 16:57:50 PDT / 1743119870 --> <row><v>2.0000000000e+02</v></row>
            <!-- 2025-03-27 16:58:00 PDT / 1743119880 --> <row><v>2.0000000000e+02</v></row>
            <!-- 2025-03-27 16:58:10 PDT / 1743119890 --> <row><v>2.0000000000e+02</v></row>
            <!-- 2025-03-27 16:58:20 PDT / 1743119900 --> <row><v>2.0000000000e+02</v></row>
            <!-- 2025-03-27 16:58:30 PDT / 1743119910 --> <row><v>2.0000000000e+02</v></row>
      </database>
    </rra>
</rrd>

我正在学习用xmlstarlet操作这个文件,想要提取特定节点下的值,但唯一能用来标识目标行的是它前面注释里的时间戳(比如2025-03-27 16:57:40 PDT)。目前用xmlstarlet sel -t --value-of "rrd/rra/database/row/v" test_modified.xml只能导出所有值,找不到用xmlstarlet匹配注释的方法,想知道:

  1. 能不能用xmlstarlet实现通过注释匹配并返回对应值?
  2. 如果不行,有哪些适合Bash脚本的工具可以实现?

解答

1. xmlstarlet实现方案

可以实现。xmlstarlet支持XPath查询,而XPath可以通过comment()函数选中注释节点,结合节点关系定位到对应的。

模糊匹配时间戳(适用于只记得部分时间信息的场景)

xmlstarlet sel -t --value-of '//database/comment()[contains(.,"2025-03-27 16:57:40 PDT")]/following-sibling::row[1]/v' test_modified.xml

命令解释:

  • //database/comment():选中<database>节点下的所有注释节点
  • [contains(.,"目标时间戳")]:过滤出包含目标时间戳的注释
  • /following-sibling::row[1]:选中该注释后面紧邻的第一个<row>节点
  • /v:提取该<row>下的<v>节点值并输出

精确匹配注释内容(避免误匹配)

如果需要确保完全匹配注释内容(去掉前后空白字符),可以用normalize-space()处理:

xmlstarlet sel -t --value-of '//database/comment()[normalize-space(.)="2025-03-27 16:57:40 PDT / 1743119860"]/following-sibling::row[1]/v' test_modified.xml

2. 替代工具方案

如果环境限制无法使用xmlstarlet,以下Bash友好的工具也能实现需求:

awk方案

通过匹配注释行,抓取下一行的<v>值:

awk -v ts="2025-03-27 16:57:40 PDT" '
    match($0, "<!--.*" ts ".*-->") { flag=1; next }
    flag && match($0, /<v>([^<]+)<\/v>/, m) { print m[1]; flag=0 }
' test_modified.xml

sed方案

定位注释行后,提取后续行的<v>内容:

sed -n '/<!--.*2025-03-27 16:57:40 PDT.*-->/ {n;s/.*<v>\([^<]*\)<\/v>.*/\1/p}' test_modified.xml

命令解释:

  • /<!--.*目标时间戳.*-->/:匹配包含目标时间戳的注释行
  • n:跳转到下一行(对应目标行)
  • s/.*<v>\([^<]*\)<\/v>.*/\1/p:提取<v>标签内的值并打印

内容的提问来源于stack exchange,提问作者flyingfishfinger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 15:07:31