使用 unix 终端解析 XML

Parsing XML using unix terminal

提问人:Mattias 提问时间:8/27/2008 最后编辑:Martin BrisiakMattias 更新时间:12/7/2022 访问量:50177

问:

有时我需要从XML文件快速提取一些任意数据,以放入CSV格式。在 Unix 终端中执行此操作的最佳实践是什么?我想要一些代码示例,例如,如何解决以下问题?

XML 输入示例:

<root>
    <myel name="Foo" />
    <myel name="Bar" />
</root>

我想要的 CSV 输出:

Foo,
Bar,
XML UNIX 解析 shell csv xidel

评论


答:

9赞 Peter Hilton 8/27/2008 #1

使用命令行 XSLT 处理器(如 xsltprocsaxonxalan)解析 XML 并生成 CSV。下面是一个示例,就您的情况而言,它是样式表:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>

    <xsl:template match="root">
        <xsl:apply-templates select="myel"/>
    </xsl:template>

    <xsl:template match="myel">
        <xsl:for-each select="@*">
            <xsl:value-of select="."/>
            <xsl:value-of select="','"/>
        </xsl:for-each>
        <xsl:text>&#10;</xsl:text>
    </xsl:template> 
</xsl:stylesheet>
7赞 jpick 8/27/2008 #2

如果您只想要任何元素的名称属性,这里有一个快速但不完整的解决方案。

(您的示例文本在文件示例)

grep “name” 示例 |切 -d“\”“ -f2,2 |xargs -I{} 回显 “{},”

13赞 jelovirt 8/27/2008 #3

Peter 的答案是正确的,但它输出的是尾随换行符。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="text"/>
  <xsl:template match="root">
    <xsl:for-each select="myel">
      <xsl:value-of select="@name"/>
      <xsl:text>,</xsl:text>
      <xsl:if test="not(position() = last())">
        <xsl:text>&#xA;</xsl:text>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

只需运行例如

xsltproc stylesheet.xsl source.xml

将 CSV 结果生成为标准输出。

2赞 AndrewR 8/27/2008 #4

这里有一个小的 ruby 脚本,它完全按照你的问题要求执行(从名为“myel”的元素中提取一个名为“name”的属性)。应该易于概括

#!/usr/bin/ruby -w

require 'rexml/document'

xml = REXML::Document.new(File.open(ARGV[0].to_s))
xml.elements.each("//myel") { |el| puts "#{el.attributes['name']}," if el.attributes['name'] }
7赞 DaveP 9/12/2008 #5

XMLStarlet 是一个用于查询/编辑/检查/转换的命令行工具包 XML 文档(有关详细信息,请参阅 XMLStarlet 命令行 XML 工具包)

无需写入文件,只需将文件通过管道传输到 xmlstarlet 并应用 xpath 过滤器即可。

cat file.xml | xml sel -t -m 'xpathExpression' -v 'elemName' 'literal' -v 'elname' -n

-m 表达式 -v 值 '' 包含文字 -n 换行符

因此,对于您的 xpath,xpath 表达式将是 //myel/@name 这将提供两个属性值。

非常方便的工具。

1赞 Bartik 9/18/2008 #6

您的测试文件位于 中。test.xml

sed -n 's/^\s*<myel\s*name="\([^"]*\)".*$/\1,/p' test.xml

它有其陷阱;例如,如果没有严格规定每个文件都在一行上,则必须首先“规范化”XML文件(因此每个文件都在单独的行上)。myelmyel

评论

0赞 tripleee 12/7/2022
这看起来是多年来被破坏的。 通常不支持,尽管一些现代变体支持。我从早期版本中挽救了代码,但也许可以查看编辑历史记录。sed\s
1赞 Uday Thombre 1/21/2014 #7

回答原始问题,假设 xml 文件是“test.xml”,其中包含:

<root>
<myel name="Foo" />
<myel name="Bar" />
</root>
tr -s "\"" " " < text.xml | awk '{printf "%s,\n", $3}'
1赞 Reino 10/31/2020 #8

使用

xidel -s input.xml -e '//myel/concat(@name,",")'
1赞 jpseng 11/6/2022 #9

yq 可用于 XML 解析。

它是一个轻量级且可移植的命令行 YAML 处理器,也可以处理 XML。 语法类似于 jq

输入

<root>
  <myel name="Foo" />
  <myel name="Bar">
    <mysubel>stairway to heaven</mysubel>
  </myel>
</root>

使用示例1

yq e '.root.myel.0.+name' $INPUT(版本 >= 4.30:yq e '.root.myel.0.+@name' $INPUT)

Foo

使用示例2

yq有一个很好的内置功能,使 XML 易于 grep

yq --input-format xml --output-format props $INPUT

root.myel.0.+name = Foo
root.myel.1.+name = Bar
root.myel.1.mysubel = stairway to heaven

使用示例 3

yq还可以将 XML 输入转换为 JSON 或 YAML

yq --input-format xml --output-format json $INPUT

{
  "root": {
    "myel": [
      {
        "+name": "Foo"
      },
      {
        "+name": "Bar",
        "mysubel": "stairway to heaven"
      }
    ]
  }
}

yq --input-format xml $FILE (YAML是默认格式)

root:
  myel:
    - +name: Foo
    - +name: Bar
      mysubel: stairway to heaven