鉴于这个大型深层嵌套XML文档(bookstore.xml)的片段,我想知道amazon
节点的完整路径。如何从命令行打印该路径?
<bookstore>
<book>
<title lang="eng">Learning XML</title>
<price>
<retail>39.95</retail>
<discounts>
<amazon>29.99</amazon>
</discounts>
<currency>USD</currency>
</price>
</book>
...
</bookstore>
理想情况下,它看起来像这样:
old-gregg$ magic bookstore.xml amazon
/bookstore/book/price/discounts/amazon
答案 0 :(得分:8)
我找到了XMLStarlet,它正是我在这里寻找的。要使用Homebrew安装它:
$ brew update
$ brew install xmlstarlet
$ xml el bookstore.xml | grep amazon
/bookstore/book/price/discounts/amazon
答案 1 :(得分:5)
使用xmllint这是与libxml2捆绑在一起的命令行工具。很可能它在您的系统上可用。
根据您的示例数据(删除省略号),我玩了并管理了以下内容:
echo -e "du\nbye\n" | \
xmllint --shell data
返回
/ > du
/
bookstore
book
title
price
retail
discounts
amazon
currency
/ > bye
这使用工具的交互模式
du
要求从当前节点(此处为root)开始打印整个子树。
bye
只退出该计划。
下一步是解析此输出。
<强>更新:强>
(假设XML在data
)中
请注意,有问题的节点目前是硬编码的!
#!/bin/bash
echo -e "du\nbye\n" | \
xmllint --shell data | \
sed 's/ /: /g' | \
awk '
BEGIN {depth = 0}
$NF == "amazon" {
for(i=1; i<NF; i++) {printf("/%s", STACK[i])}
print "/" $NF
}
/^\// {next}
NF == depth + 1 {depth = NF; STACK[depth] = $NF; next}
NF == depth {STACK[depth] = $NF; next}
NF < depth {depth = NF; STACK[depth] = $NF; next}
1 {print "something went horribly wrong!"}
'
给出
/bookstore/book/price/discounts/amazon
解释一下sed
命令后的输出:
/ > du
/
bookstore
: book
: : title
: : price
: : : retail
: : : discounts
: : : : amazon
: : : currency
/ > bye
sed
用[two spaces]
替换[:space]
在下文中,使用awk
检测深度很简单。
答案 2 :(得分:0)
在XPath 2.0中,您可以使用//amazon
选择元素/ancestor-or-self::*/node-name(.)
以获取父节点名称,并string-join(..., "/")
从中获取路径。
最后是XPath 2.0表达式
string-join(("",//amazon/ancestor-or-self::*/node-name(.)),"/")
将准确返回您想要的路径。 (虽然它不会添加[]属性测试,如果你也需要它们)
我不知道是否有任何其他XPath 2.0命令行工具,但我几天前做了自己的。如果您碰巧有fpc,可以下载source并编译它(没有二进制编辑:现在它们在那里链接:http://videlibri.sourceforge.net/xidel.html)。 有了它,你可以运行:
xidel /tmp/so2.xml --extract 'string-join(("",//amazon/ancestor-or-self::*/node-name(.)),"/")'
我也做了一个你可以尝试的CGI服务:
wget -qO - 'http://videlibri.sourceforge.net/cgi-bin/xidelcgi?extract=string-join(("",//amazon/ancestor-or-self::*/node-name(.)),"/")&data=<bookstore><book> <title lang="eng">Learning XML</title> <price> <retail>39.95</retail> <discounts> <amazon>29.99</amazon> </discounts> <currency>USD</currency> </price></book></bookstore>'