从命令行将XPath列出到XML节点

Tro*_*vey 2 xml macos bash xpath

鉴于这个大型深层嵌套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>
Run Code Online (Sandbox Code Playgroud)

理想情况下它看起来像这样:

old-gregg$ magic bookstore.xml amazon
/bookstore/book/price/discounts/amazon
Run Code Online (Sandbox Code Playgroud)

Tro*_*vey 8

我发现了XMLStarlet,它正是我正在寻找的东西.使用Homebrew安装它:

$ brew update
$ brew install xmlstarlet
$ xml el bookstore.xml | grep amazon
/bookstore/book/price/discounts/amazon
Run Code Online (Sandbox Code Playgroud)


The*_*eke 5

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

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

echo -e "du\nbye\n" | \
  xmllint --shell data
Run Code Online (Sandbox Code Playgroud)

返回

/ > du
/
bookstore
  book
    title
    price
      retail
      discounts
        amazon
      currency
/ > bye
Run Code Online (Sandbox Code Playgroud)

这使用工具的交互模式.
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!"}
  '
Run Code Online (Sandbox Code Playgroud)

/bookstore/book/price/discounts/amazon
Run Code Online (Sandbox Code Playgroud)

要解释一下这个sed命令之后的输出:

/ > du
/
bookstore
: book
: : title
: : price
: : : retail
: : : discounts
: : : : amazon
: : : currency
/ > bye
Run Code Online (Sandbox Code Playgroud)

sed替代[two spaces][:space].
在下文中,用它来检测深度很简单awk.