Linux Shell提取XML多值:XPath在xq/xmlstarlet失效求解决方案
问题:Shell环境下提取XML指定内容的可行方案
现有XML文档结构示例如下:
Olivia Jones It may be late in the day but Olivia Jones still has a stack full of the best songs around to soundtrack your night.
需求为提取**标题含"Olivia"**的节目中的channel、start时间及title字段。此前编写的XPath语句:
tv / programme / title [ contains(text(), "Olivia") ] / parent::*/concat(@channel, "_", @start, "_", title)
在在线测试器中可用,但在xq和xmlstarlet工具中无法运行,以下是Shell环境下的可行实现方案:
方案1:使用xmlstarlet
xmlstarlet基于XPath 1.0,需调整写法直接定位符合条件的programme节点再拼接字段:
# 处理本地文件 xmlstarlet sel -t -m "//programme[title[contains(text(), 'Olivia')]]" -v "concat(@channel, '_', @start, '_', title)" -n epg.xml # 直接处理远程XML curl -s https://raw.githubusercontent.com/dp247/Freeview-EPG/master/epg.xml | xmlstarlet sel -t -m "//programme[title[contains(text(), 'Olivia')]]" -v "concat(@channel, '_', @start, '_', title)" -n
参数说明:
-t:启用模板模式-m:匹配标题含"Olivia"的programme节点-v:输出拼接后的目标字段-n:每行输出后添加换行
方案2:使用xq(基于jq的XML处理工具)
xq需结合jq风格语法实现筛选与拼接:
# 处理本地文件 xq -r '.tv.programme[] | select(.title[] | contains("Olivia")) | "\(.["@channel"])_ \(.["@start"])_ \(.title)"' epg.xml # 直接处理远程XML curl -s https://raw.githubusercontent.com/dp247/Freeview-EPG/master/epg.xml | xq -r '.tv.programme[] | select(.title[] | contains("Olivia")) | "\(.["@channel"])_ \(.["@start"])_ \(.title)"'
参数说明:
-r:输出原始字符串(避免转义).tv.programme[]:遍历所有节目节点select(...):筛选标题含"Olivia"的节点- 字符串插值拼接目标字段
方案3:使用xmllint(随libxml2安装)
通过两次xpath查询实现筛选与拼接:
# 处理本地文件 xmllint --xpath "//programme[title[contains(text(), 'Olivia')]]" epg.xml | xmllint --xpath "concat(@channel, '_', @start, '_', title)" - # 直接处理远程XML curl -s https://raw.githubusercontent.com/dp247/Freeview-EPG/master/epg.xml | xmllint --xpath "//programme[title[contains(text(), 'Olivia')]]" - | xmllint --xpath "concat(@channel, '_', @start, '_', title)" -
内容的提问来源于stack exchange,提问作者Richard Barraclough
相关产品推荐
相关产品推荐

