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

如何在Shell脚本中解析XML?求xmllint/grep实现指定输出

问题描述

需要从给定的XML文件中提取以下格式的输出:

availStart="2024-05-24T05:00:30" availId="811220455" q1:campaignIdRef=180398
availStart="2024-05-24T05:13:41" availId="811220484" q2:campaignIdRef=179163
availStart="2024-05-24T05:13:41" availId="811220484" q2:campaignIdRef=179166
availStart="2024-05-24T05:13:41" availId="811220484" q2:campaignIdRef=179164
availStart="2024-05-24T05:13:41" availId="811220484" q2:campaignIdRef=179165

尝试过以下命令,但仅能获取availStart值,availId无输出,且无法关联campaignIdRef:

while read LINE; do time=`grep -io -P 'availstart=.{20}'` && avail=`grep -io -P 'availId=.{11}'`;echo -e "\n$time and $avail";done < sample.xml
解决方案

方法一:使用xmllint(推荐,XML专用工具)

XML包含命名空间,需在XPath中声明才能正确定位元素。以下命令通过xmllint提取所需字段,再用awk格式化输出:

xmllint --xpath "declare default element namespace 'urn:scte:118:version01'; declare namespace q='urn:nds:dynamic:ruleManagerICD:01:01'; /Schedule/Window/Avail/(./@availStart, ./@availId, .//q:campaignIdRef/text())" sample.xml | awk '{
    if (match($0, /availStart="[^"]+"/)) start=substr($0,RSTART,RLENGTH);
    if (match($0, /availId="[^"]+"/)) id=substr($0,RSTART,RLENGTH);
    if ($0 ~ /^[0-9]+$/) {
        prefix = (start ~ /2024-05-24T05:00:30/) ? "q1:" : "q2:";
        print start " " id " " prefix "campaignIdRef=" $0;
    }
}'

说明:

  1. xmllint的--xpath参数声明了XML的默认命名空间和q前缀(对应q1/q2的统一URI),提取每个Avail节点的availStart、availId属性,以及所有后代的campaignIdRef文本值。
  2. awk负责缓存availStart和availId,遇到数字格式的campaignIdRef时,根据时间匹配前缀并输出完整行。

方法二:使用awk+正则(快速处理结构固定的XML)

如果XML结构稳定,可直接用awk逐行扫描,关联Avail节点和对应的campaignIdRef:

awk '
/<Avail/ {
    # 提取当前Avail的availStart和availId属性
    match($0, /availStart="[^"]+"/, start_match);
    match($0, /availId="[^"]+"/, id_match);
    current_start = start_match[0];
    current_id = id_match[0];
    # 提取当前Avail的命名空间前缀(q1/q2)
    match($0, /xmlns:(q[12])="urn:nds/, prefix_match);
    current_prefix = prefix_match[1] ":";
}
/campaignIdRef>/ {
    # 提取campaignIdRef的值并输出完整行
    match($0, /campaignIdRef>([0-9]+)</, camp_match);
    print current_start " " current_id " " current_prefix "campaignIdRef=" camp_match[1];
}
' sample.xml

说明:

  • 遇到<Avail>行时,缓存该行的availStart、availId和命名空间前缀。
  • 遇到campaignIdRef行时,直接使用缓存的Avail信息,输出目标格式的行。

原命令问题分析

你之前的while read循环存在两个核心问题:

  1. 循环内的grep默认读取整个文件,而非当前行,导致变量值重复且无法关联上下文。
  2. 没有处理campaignIdRef与对应Avail节点的关联关系,无法生成目标格式的输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 01:50:55