【问题标题】:count number of xml element from linux shell从 linux shell 计算 xml 元素的数量
【发布时间】:2011-08-12 23:58:45
【问题描述】:

我的 xml 看起来像这样:

<elements>
<elem>
....bunch of other elements
</elem>
</elements>

有没有办法通过linux shell计算一些xml文件中elem标签的出现次数?像 perl/python 或任何可能作为一个衬垫工作的东西?

我可能会尝试类似grep -c "elem" myfile.xml 之类的方法,然后将得到的数字除以2 并得到数字,有没有类似的东西,但只有一条线?

编辑:

我正在寻找替代的 grep 解决方案

【问题讨论】:

    标签: python xml linux perl


    【解决方案1】:

    xml_grep 工具可以满足您的需求 - 请尝试以下操作:

    xml_grep --count //elem example.xml
    

    该实用程序位于 Debian / Ubuntu 上的 xml-twig-tools 软件包和 documentation is here 中。

    【讨论】:

    • @Mark Longair 这似乎没问题,但我在我的 linux 上找不到该命令,我该如何安装它?
    • @London:你使用的是什么发行版?
    • 我没有红帽系统,但你可以试试:yum install perl-XML-Twig
    • 它还与cpan XML::Twig一起安装
    • 你甚至可以写 xml_grep --count elem example.xml (不需要 //)
    【解决方案2】:

    你也可以使用xmllint:

    xmllint --xpath "count(//elem)" myfile.xml
    

    【讨论】:

    • 目前这是该线程中迄今为止最好的答案。使用适当的 xml 工具是要走的路,而不是一些 hacky grep 解决方案。
    • 如果元素有命名空间前缀怎么办?
    【解决方案3】:

    不要使用正则表达式来解析或扫描 XML 文件

    强制免责声明被解雇,这是我的解决方案:

    xmllint --nocdata --format myfile.xml | grep -c '</elem>'
    

    xmllintlibxml 的一部分,这在许多Linux 发行版中相当常见。此解决方案通过以下正则表达式/XML 陷阱:

    • 虚假空格(--format)
    • 单行上有几个结束标签(--format)
    • CDATA 部分 (--nocdata)

    但是,你会被讨厌的命名空间声明和默认设置所吸引。

    【讨论】:

    • 您说不要使用正则表达式,但您使用正则表达式给出了解决方案?
    • @London 具有讽刺意味的是......必须在每个场合发出警告。尽管您似乎从外壳中寻找解决方案。我给了你一个,恕我直言,在正确性和快速性之间取得了很好的折衷。
    【解决方案4】:

    伦敦,

    试试fgrep -c '&lt;/elem&gt;' $filename

    fgrep 是一个标准的 unix 实用程序,但对 linux 并不确定。 -c 开关表示 count

    干杯。基思。

    PS:计算 CLOSING 标签总是更容易,因为它们没有属性 ;-)

    【讨论】:

    • 计算结束标签可能会产生错误的结果,因为 是结束标签的缩写形式。此外,通常的“您不能通过正则表达式解析 xml”-参数适用,例如: ]]>>
    • 是的...没想到&lt;elem /&gt;的...臭虫!
    • 此外 grep 计数匹配行而不匹配。因此,如果一行中有多个&lt;elem/&gt;,它们只会将计数器增加一个。
    【解决方案5】:

    grep 本身不会在所有情况下都有帮助,但对于XMLStarlet 来说这是一个简单的案例。您可以将elemXMLStarlet 匹配,然后用wc -l 计算新行数。新行减 1 是元素的数量。

    例如 YOURFILE.xml:

    <elements>
    <elem>....bunch of other elements</elem><elem>....bunch of other elements</elem>
    <elem>
    ....bunch of other elements
    ....bunch of other elements
    </elem>
    </elements>
    

    使用XMLStarletwc-l

    echo $(($(xmlstarlet sel -t -m //elem -n YOURFILE.xml | wc -l)-1))
    

    输出:3

    【讨论】:

      【解决方案6】:

      @OP,所有的grep 解决方案都有一个基本的“缺陷”,如果超过 1 个&lt;elem&gt; 标记是一行,它就会错过计数。使用awk 以编程方式计数

      awk 'BEGIN{
          totalelem=0
          totalendelem=0
      }
      /<elem>/{
          m = split($0,a,"<elem>") # or m = gsub(/<elem>/,"")
          totalelem+=m-1
      }
      /<\/elem>/{
          m = split($0,b,"</elem>") # or m = gsub("</elem>","")
          totalendelem+=m-1
      }
      END{
          print "Total elem tags: " totalelem
          print "Total end elem tags: " totalendelem
          # if you want to make sure each elem tag is enclosed  by corresponding end elem tag
          if ( totalelem == totalendelem ){
              print "Equal start and end tags"
          }
      }
      ' file
      

      此解决方案假定您知道您的 elem 标记将是什么样子。没有&lt;elem /&gt; 或者那些有额外属性的..

      【讨论】:

      • 感谢您的回复,但我需要使用管道将文件内容传递给此,然后键入 awk/grep 或任何命令,这可能吗?如何将 awk 脚本保存为 .awk?目前我得到awk: ^ syntax error
      • 将其保存为 shell 脚本。然后从命令行调用 shell 脚本。例如./myscript.sh。确保使其可执行。
      【解决方案7】:

      这是对@bluenote10 的xmllint answer 的改进,它也适用于任意命名空间前缀:

      xmllint --xpath "count(//*[local-name()='elem'])" myfile.xml
      

      (已经尝试将此作为对@Ryan_Pelletier 问题的回复添加到原始答案下方,但一直遇到格式问题,因此创建了一个单独的答案)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-15
        • 2017-12-16
        • 1970-01-01
        • 2014-07-08
        • 2017-08-23
        • 1970-01-01
        相关资源
        最近更新 更多