从unix命令行执行基本xml解析的最简单方法

时间:2012-02-08 19:57:10

标签: xml perl unix awk grep

我正在搜索具有某些属性的xml文件。例如,包含以下模式的文件:

<param-value>
  <name>Hosts</name>
  <description>some description</description>
  <value></value>
</param-value>

对于此类文件,我想解析另一个标记的值,例如:

<param-value>
  <name>Roles</name>
  <description>some description</description>
  <value>asdf</value>
</param-value>

并打印出文件名和“asdf”。从命令行完成此操作的最简单方法是什么?

我想到的一种方法是使用带有-l选项的grep来过滤匹配的文件,然后使用xargs grep来提取角色的值。但是,grep不适用于多行正则表达式。我看到另一个问题表明它可以用-Pzo选项完成,但是没有任何运气让它在我的情况下工作。有更简单的方法吗?

7 个答案:

答案 0 :(得分:13)

以下linux命令使用XPath访问XML文件中的指定值

for xml in `find . -name "*.xml"`
do  
echo $xml `xmllint --xpath "/param-value/value/text()" $xml`| awk 'NF>1'
done

匹配XML文件的示例输出:

./test1.xml asdf
./test4.xml 1234

答案 1 :(得分:2)

对我来说最简单的方法是从命令行使用Saxon

以下是使用XPath on the command line的示例。这与shell脚本相结合,可以完全满足您的要求。

答案 2 :(得分:1)

根据the answer to this questionXMLStarlet似乎非常适合这类事情。

答案 3 :(得分:1)

我使用基本的perl / awk功能(基本上是一个穷人对标签的解析)制定了几个解决方案。如果您看到只使用基本perl / awk功能的任何改进,请告诉我。我通过设置一个标志来避免处理多行正则表达式,我看到了一个特定的标签。有点笨拙但有效。

perl的:

perl -ne '$h = 1 if m/Host/; $r = 1 if m/Role/; if ($h && m/<value>/) { $h = 0; print "hosts: ", $_ =~ /<value>(.*)</, "\n"}; if ($r && m/<value>/) { $r = 0; print "\nrole: ", $_ =~ /<value>(.*)</, "\n" }'

AWK:

awk '/Host/ {h = 1} /Role/ {r = 1} h && /<value>/ {h = 0; match($0, "<value>(.*)<", a); print "hosts: " a[1]} r && /<value>/ {r = 0; match($0, "<value>(.*)<", a); print "\nrole: " a[1]}'

答案 4 :(得分:1)

$ xmlstarlet ed -u /param-value/name -v Roles -u /param-value/value -v asdf data.xml

<?xml version="1.0"?>
<param-value>
  <name>Roles</name>
  <description>some description</description>
  <value>asdf</value>
</param-value>

答案 5 :(得分:0)

我原本希望更仔细地解决你的问题,但我已经没时间了,抱歉。

无论如何 - perl有一些非常好的模块用于阅读xml。

特别是,以下文章perl and xml on the command line可能很有用。

答案 6 :(得分:0)

我通常使用Perl的XML::XSH2。您可以在其中以交互方式处理XML文件,也可以编写脚本。该脚本将类似于(未经测试):

for my $file in { glob "*.xml" } {
    open $file ;
    my $param_value = //param-value[name="Hosts"] ;
    if $param_value echo $file $value/value ;
}