2

鉴于这个大型深度嵌套 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
4

3 回答 3

8

我找到了XMLStarlet,它正是我在这里寻找的。使用Homebrew安装它:

$ brew update
$ brew install xmlstarlet
$ xml el bookstore.xml | grep amazon
/bookstore/book/price/discounts/amazon
于 2012-08-17T21:08:27.300 回答
5

使用xmllint,它是一个与 libxml2 捆绑在一起的命令行工具。很可能它在您的系统上可用。

根据您的示例数据(删除省略号),我玩弄并管理了以下内容:

echo -e "du\nbye\n" | \
  xmllint --shell data

返回

/ > du
/
bookstore
  book
    title
    price
      retail
      discounts
        amazon
      currency
/ > bye

这使用工具的交互模式。
du要求打印从当前节点(此处为根)开始的整个子树。 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

于 2012-08-17T20:19:37.873 回答
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,你可以下载源代码并编译它(没有二进制编辑:现在它们在那里链接: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>'  
于 2012-08-17T21:06:41.323 回答