使用简单的shell脚本进行xml解析

时间:2014-07-18 14:22:31

标签: xml shell

有人可以帮助我将xml数据导入shell脚本

这是我的要求。

如果CHILD值大于100,我需要打印CHILD值以及CHILD和parent的属性值

这是我的数据

<mydata>
    <parent detail="school1">
        <CHILD attribute="0">0</CHILD>
        <CHILD attribute="1">1932</CHILD>
        <CHILD attribute="2">0</CHILD>
        <CHILD attribute="3">500</CHILD>
        <CHILD attribute="4">0</CHILD>
        <CHILD attribute="5">0</CHILD>
        <CHILD attribute="6">7819</CHILD>
        <CHILD attribute="7">0</CHILD>
        <CHILD attribute="8">299</CHILD>
        <CHILD attribute="9">0</CHILD>
    </parent>
    <parent detail="school2">
        <CHILD attribute="0">1</CHILD>
        <CHILD attribute="1">7000</CHILD>
        <CHILD attribute="2">0</CHILD>
        <CHILD attribute="3">0</CHILD>
        <CHILD attribute="4">600</CHILD>
        <CHILD attribute="5">0</CHILD>
        <CHILD attribute="6">11674</CHILD>
        <CHILD attribute="7">0</CHILD>
        <CHILD attribute="8">489</CHILD>
        <CHILD attribute="9">0</CHILD>
    </parent>
</mydata>

我的外部文件值是这样的 childvalue_limits.txt文件

attribute0=100
attribute1=60
attribute3=80
attribute4=90
attribute5=100
attribute6=90
attribute7=50
attribute8=80
attribute9=70

我需要将此文件作为参数传递给脚本,并将这些值动态地置于条件中。

当前代码

sed 's|><|>\n<|g' $WORKING_PATH/xml_detail.log | awk -F'"|<|>' '/parent detail/{p=$3} /CHILD attribute/{att=$3;val=$5;if(val>100)print  "child value on " p, "attribute "att,"is at value: "val ,"\n"}' 

当前输出

child value on school2 attribute 1 is at value 1000
child value on school2 attribute 4 is at value 600
.....
.....

所需的输出应该是这样的

child value on school2 attribute 1 is at value 1000 and threshold is 60
child value on school2 attribute 4 is at value 600 and threshold is 90
.....
.....

请注意:阈值是通过名为childvalue_limits.txt的单独文件传递给if条件的动态值

2 个答案:

答案 0 :(得分:1)

您无法(正确)使用正则表达式解析XML。 XML是一种无上下文的语言,它比基于正则表达式的语法更具表现力。有关详细信息,请参阅Chomsky层次结构。这也是你在使用正则表达式时遇到新行问题的原因。

因此,使用适当的XML解析器会更好(也更容易和更稳定)。由于我最熟悉BaseX(完全披露:我也与项目有关),我将使用它。

使用zip版本时,您可以简单地运行文件bin/basex。以下XPath 3.0表达式应该为您提供正确的输出,只需连接不同的值:

for $c in /mydata/parent/CHILD[. > 100] return $c/parent::parent/@detail || " " || $c/@attribute || " " || $c/data() || "&#10;"

假设您的xml文件名为mydata.xml,您可以通过发出以下命令来执行此XPath(即可以在您的shell脚本中完成):

basex -i mydata.xml -q 'for $c in /mydata/parent/CHILD[. > 100] return $c/parent::parent/@detail || " " || $c/@attribute || " " || $c/data() || "&#10;"'

答案 1 :(得分:0)

再次编辑

好的,我已将代码更改为读取输入限制的文件。它看起来很复杂,但事实并非如此 - 你可以删除所有包含单词&#34; DEBUG&#34;如果你愿意的话。 #是评论的开头。

#!/bin/bash

awk -F'"|<|>' '
   FNR==NR           {
                       split($0,f,"=");  # Split line on "=" sign into array f[]
                       gsub(/[[:alpha:]]/,"",f[1]); # Remove non-digits
                       limits[f[1]]=f[2]; # Save for comparison later
                       print "DEBUG: limits[",f[1],"]=",f[2];
                       next
                     }
   /parent detail/   {
                       p=$3
                       print "DEBUG: parent detail=",p;
                     }
   /CHILD attribute/ {
                       att=$3;val=$5;
                       print "DEBUG: att=",att,",val=",val; 
                       if(val>limits[att])print p,att,val,limits[att]
                     }
   ' limits.txt xml

您会在脚本末尾看到它同时读取您的文件 - limits.txtxml。在脚本中,以FNR==NR开头的花括号中的块意味着以下代码仅适用于读取和解析limits.txt

如果您想查看没有DEBUG消息的输出,请运行

./script | grep -v DEBUG

<强> EDITED

使用修改后的数据,您的代码可以正常使用。这是我的输出:

node2 1 1932
node2 6 7819
node1 1 1924
node1 6 11674

我认为您的意思是要避免使用XML解析器,只使用awksed之类的标准工具来实现这一目标,因此我将使用awk

awk -F'"|<|>' '/parent detail/{p=$3} /CHILD attribute/{att=$3;val=$5;if(val>100)print p,att,val}' xml

<强>输出:

school1 1 1932
school1 3 500
school1 6 7819
school1 8 299
school2 1 7000
school2 4 600
school2 6 11674
school2 8 489

因此,它将分隔符设置为"<>中的任何一个。然后,当它看到带有&#34;父细节&#34;它将值保存在p中。当它看到带有单词CHILD attribute的行时,它会提取属性和值。如果该值超过100,则打印父,属性和值。

它假设您的XML位于名为xml的文件中。