如何使用shellscript解析XML?

时间:2011-01-13 12:42:11

标签: linux bash shell

我想知道使用shellscript解析XML文件的最佳方法是什么?

  • 一个人应该手工做吗?
  • 第三层库是否存在?

如果你已经成功了,如果你能告诉我你是怎么做到的那样

11 个答案:

答案 0 :(得分:74)

您可以尝试xmllint

  

xmllint程序解析一个或多个   在命令中指定的XML文件   行作为xmlfile。它打印各种   输出类型,取决于   选择的选项。它很有用   检测XML代码和XML中的错误   在XML解析器itse

它允许您使用--pattern选项通过xpath选择XML doc中的元素。

在Mac OS X(Yosemite)上,默认安装 在Ubuntu上,如果尚未安装,则可以运行apt-get install libxml2-utils

答案 1 :(得分:21)

这是一个完整的工作示例 如果它只提取电子邮件地址,您可以执行以下操作:
1)假设XML文件spam.xml就像

<spam>
<victims>
  <victim>
    <name>The Pope</name>
    <email>pope@vatican.gob.va</email>
    <is_satan>0</is_satan>
  </victim>
  <victim>
    <name>George Bush</name>
    <email>father@nwo.com</email>
    <is_satan>1</is_satan>
  </victim>
  <victim>
    <name>George Bush Jr</name>
    <email>son@nwo.com</email>
    <is_satan>0</is_satan>
  </victim>
</victims>
</spam>

2)您可以使用以下简短的bash代码获取电子邮件并进行处理:

#!/bin/bash
emails=($(grep -oP '(?<=email>)[^<]+' "/my_path/spam.xml"))

for i in ${!emails[*]}
do
  echo "$i" "${emails[$i]}"
  # instead of echo use the values to send emails, etc
done

此示例的结果是:

0 pope@vatican.gob.va
1 father@nwo.com
2 son@nwo.com

重要提示:
不要将此用于严肃的事情。这对于玩游戏,获得快速结果,学习grep等都是可以的,但你应该明确地寻找,学习和使用XML解析器进行制作(参见下面的Micha评论)。

答案 2 :(得分:11)

还有xmlstarlet(也适用于Windows)。

http://xmlstar.sourceforge.net/doc/xmlstarlet.txt

答案 3 :(得分:10)

我很惊讶没有人提到xmlsh。使命宣言:

  

XML的命令行shell基于的理念和设计   Unix Shell

     

xmlsh提供了熟悉的脚本环境,但具体而言   为脚本xml进程量身定制。

提供了类似shell命令的列表here

我使用xed命令,相当于sed的XML,并允许基于XPath的搜索和替换。

答案 4 :(得分:8)

试试sgrep。目前尚不清楚你想要做什么,但我肯定不会尝试在bash中编写XML解析器。

答案 5 :(得分:7)

您是否安装了xml_grep?它是某些发行版上基于perl的实用程序标准(它已预先安装在我的CentOS系统上)。不是给它一个正则表达式,而是给它一个xpath表达式。

答案 6 :(得分:4)

一个相当新的项目是xml-coreutils包,其中包含xml-cat,xml-cp,xml-cut,xml-grep,......

http://xml-coreutils.sourceforge.net/contents.html

答案 7 :(得分:4)

尝试使用xpath。您可以使用它来解析xml树中的元素。

http://www.ibm.com/developerworks/xml/library/x-tipclp/index.html

答案 8 :(得分:2)

这实际上超出了shell脚本的功能。 Shell脚本和标准的Unix工具可以解析面向行的文件,但是当你谈论XML时情况会发生变化。即使是简单的标签也会出现问题:

<MYTAG>Data</MYTAG>

<MYTAG>
     Data
</MYTAG>

<MYTAG param="value">Data</MYTAG>

<MYTAG><ANOTHER_TAG>Data
</ANOTHER_TAG><MYTAG>

想象一下,尝试编写一个可以读取其中包含的数据的shell脚本。这三个非常简单的XML示例都显示了不同的方法,这可能是一个问题。前两个示例是XML中完全相同的语法。第三个只是附加了一个属性。第四个包含另一个标签中的数据。简单的sedawkgrep命令无法捕捉所有可能性。

您需要使用完整的脚本语言,如Perl,Python或Ruby。其中每个模块都具有可以解析XML数据并使底层结构更易于访问的模块。我在Perl中使用XML::Simple。我花了几次尝试来理解它,但它完成了我所需要的,并使我的编程更容易。

答案 9 :(得分:1)

这是一个将XML名称 - 值对和属性转换为bash变量的函数。

http://www.humbug.in/2010/parse-simple-xml-files-using-bash-extract-name-value-pairs-and-attributes/

答案 10 :(得分:1)

这是使用xml_grep的解决方案(因为xpath不是我们可分发的一部分,我不想将它添加到所有生产机器中)...

如果您正在寻找XML文件中的特定设置,并且如果给定树级别的所有元素都是唯一的,并且没有属性,那么您可以使用这个方便的函数:

# File to be parsed
xmlFile="xxxxxxx"

# use xml_grep to find settings in an XML file
# Input ($1): path to setting
function getXmlSetting() {

    # Filter out the element name for parsing
    local element=`echo $1 | sed 's/^.*\///'`

    # Verify the element is not empty
    local check=${element:?getXmlSetting invalid input: $1}

    # Parse out the CDATA from the XML element
    # 1) Find the element (xml_grep)
    # 2) Remove newlines (tr -d \n)
    # 3) Extract CDATA by looking for *element> CDATA <element*
    # 4) Remove leading and trailing spaces
    local getXmlSettingResult=`xml_grep --cond $1 $xmlFile 2>/dev/null | tr -d '\n' | sed -n -e "s/.*$element>[[:space:]]*\([^[:space:]].*[^[:space:]]\)[[:space:]]*<\/$element.*/\1/p"`

    # Return the result
    echo $getXmlSettingResult
}

#EXAMPLE
logPath=`getXmlSetting //config/logs/path`
check=${logPath:?"XML file missing //config/logs/path"}

这将适用于此结构:

<config>
  <logs>
     <path>/path/to/logs</path>
  <logs>
</config>

它也适用于此(但它不会保留换行符):

<config>
  <logs>
     <path>
          /path/to/logs
     </path>
  <logs>
</config>

如果您有重复&lt; config&gt;或者&lt; logs&gt;或者&lt; path&gt;,然后它只返回最后一个。如果找到多个匹配项,您可以修改函数以返回数组。

仅供参考:此代码适用于使用GNU BASH 4.1.2的RedHat 6.3,但我不认为我正在做任何特别的事情,所以应该在任何地方工作。

注意:对于任何刚接触脚本的人,请确保使用正确类型的引号,这三个代码都在此代码中使用(正常单引号'=文字,后退单引号`=执行,双引号'=组)