使用grep,awk或sed等shell工具解析xml

时间:2017-04-12 16:01:09

标签: bash shell awk sed

我有以下xml来解析并根据tag的值提取tag的值。仅在type =='hosted'时提取。我想使用像grep,sed和awk这样的bash工具进行提取。在没有条件的情况下提取单个标记值是我以前做过的,而不是条件。我可以使用python或我知道的任何其他编程语言轻松完成它。但如果在shell脚本中完成,这将是理想的。

...
    <repositories-item>
      <name>hosted-npm</name>
      <type>hosted</type>
    </repositories-item>
    <repositories-item>
      <name>proxied-npm</name>
      <type>proxied</type>
    </repositories-item>
...

2 个答案:

答案 0 :(得分:3)

xmlstarlet是一个命令行XML Toolkit,可以将复杂的XSLT模板表示为一系列命令行开关。

假设我们提供了格式良好的XML文档repos.xml

<repositories>
  <repositories-item>
      <name>hosted-npm</name>
      <type>hosted</type>
    </repositories-item>
    <repositories-item>
      <name>proxied-npm</name>
      <type>proxied</type>
    </repositories-item>
</repositories>

如果您通过带有以下开关的XMLStarlet过滤器运行它

$ cat repos.xml | xmlstarlet sel -t -m '//repositories-item' \
                 -i 'type="hosted"' -v 'name' -n 

您将获得一行输出

hosted-npm

让我们看一下XMLStarlet命令行。

  1. 我们在使用sel开关
  2. 指定的选择模式下运行命令
  3. 我们使用-t开关
  4. 指定选择模板
  5. 我们使用<repositories-item> swicth指定的//repositories-item模板将解析器限制为-m元素
  6. 我们只选择那些拥有&#34;托管&#34;作为type开关
  7. 指定的-i元素的值
  8. 我们打印出使用name开关指定的-v元素的值。
  9. 在每行输出后,我们打印使用-n开关指定的换行符。
  10. 这是XMLStarlet生成的等效XSLT

    <?xml version="1.0"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
      <xsl:output omit-xml-declaration="yes" indent="no"/>
      <xsl:template match="/">
        <xsl:for-each select="//repositories-item">
          <xsl:choose>
            <xsl:when test="type=&quot;hosted&quot;">
              <xsl:call-template name="value-of-template">
                <xsl:with-param name="select" select="name"/>
              </xsl:call-template>
              <xsl:value-of select="'&#10;'"/>
            </xsl:when>
          </xsl:choose>
        </xsl:for-each>
      </xsl:template>
      <xsl:template name="value-of-template">
        <xsl:param name="select"/>
        <xsl:value-of select="$select"/>
        <xsl:for-each select="exslt:node-set($select)[position()&gt;1]">
          <xsl:value-of select="'&#10;'"/>
          <xsl:value-of select="."/>
        </xsl:for-each>
      </xsl:template>
    </xsl:stylesheet>
    

    根据Charles Duffy的建议,值得注意的是,可以使用-C选项使用XMLStarlet生成此XSLT规范:

    xmlstarlet sel -C -t -m '//repositories-item' \
           -i 'type="hosted"' -v 'name' -n > hosted-repos.xslt
    

    此生成的XSLT规范可以直接与xsltproc一起用作

    cat repos.xml | xsltproc hosted-repos.xslt - 
    

答案 1 :(得分:0)

缺少xml特定工具

awk使用封闭标签来定义记录分隔符

$ awk -v RS='</?repositories-item>' '/<type>hosted<\/type>/' file

  <name>hosted-npm</name>
  <type>hosted</type>

请注意,这需要GNU awk支持的多字符RS。

您可以对匹配和输出进行更多控制

$ awk -v RS='</?repositories-item>' -F'[<>]' '
    {delete a; 
     for(i=2;i<=NF;i+=4) a[$i]=$(i+1); 
     if(a["type"]=="hosted") print a["name"] }' file


hosted-npm