使用 xmlstarlet 将 xml 个节点提取为 table

extract xml nodes as table with xmlstarlet

我有一个非常简单但巨大的 xml(超过 50.000 行)。我只想提取一个重复节点作为 table(环)。考虑到这是一个例子。真正的文件在“ring”节点中有300多个元素,所以我尽量避免写逐个元素提取的命令。

举个小例子

<xml>
<root>
  <ration>
    <ring>
      <id  value="1"/>
      <date  value="2021-01-01"/>
      <price  value="435"/>
    </ring>
  </ration>
</root>
<root>
  <ration>
    <ring>
      <id  value="14"/>
      <date  value="2021-02-01"/>
      <price  value="745"/>
    </ring>
  </ration>
</root>
</xml>

我想实现的是: 这个 xmlstarlet 命令正在运行,我得到了正确的结果,但现在考虑执行 300 次(对于每个元素,我必须将调用插入到 concat 部分)。我需要一个更简单的方法。

xmlstarlet sel -T -t -m '//root/ration/ring' -v "concat(id/@value,',',date/@value,',',price/@value)"  -n file.xml

id, date, price
1, 2021-01-01, 435
14, 2021-02-01, 745

好久没问了。尽管如此...

xmlstarlet sel -T \
    -t -m '//root[1]/ration/ring/*[boolean(@value)]' \
    -v 'substring(", ", 1, 2*(position() != 1))' -v 'local-name()' -b -nl \
    -t -m '//root' -m 'ration/ring/*[boolean(@value)]' \
    -v 'substring(", ", 1, 2*(position() != 1))' -v '@value' -b -nl \
    file.xml

输出:

id, date, price
1, 2021-01-01, 435
14, 2021-02-01, 745

模板 #1 发出 header,#2 数据。 -m 表达式 #1 和 #3 匹配具有 @value 属性的 ring 的 child 个元素。一起使用 -m-b 就可以了。如果 @value 替换为 @* 所有属性都被选中;使用诸如 @*[name()="value" or name()="otherval"] 的谓词,选择可以是 fine-tuned.

值的分离在 XSLT 1.0 中比在 2.0 中需要更多的工作:在这种情况下,substring 函数调用 returns 第一个值的空字符串,其中 position() != 1 为假(转换为数字 0),以及 2 个字符的字符串(逗号和 space)用于以下为真 (1).

顺便说一下,任何 lower/upper 组合中以 xml 开头的标签/PI 名称是 reserved.