2013-04-08 80 views
0

我在这个主题上询问的第一个问题由于缺乏信息而被关闭。所以再次询问这一点,并添加了一些更多细节使用ksh脚本从XML中提取数据

我必须从一个XML文件中提取一个标签中给出的值,我必须使用ksh(我可以在perl中解决这个问题,但我必须做到ksh,不能使用像xmlsh这样的第三方工具)

sample.xml中

<?xml version="1.0" standalone="yes" ?> 
<parent_one> 
    <parent_two> 
    <Pool> 
     <pool_name>ABC</pool_name> 
     <percent_full>79</percent_full> 
     <pool_state>Enabled</pool_state> 
    </Pool> 
    <Pool> 
     <pool_name>DEF</pool_name> 
     <percent_full>40</percent_full> 
     <pool_state>Enabled</pool_state> 
    </Pool> 
    <Pool> 
     <pool_name>XYZ</pool_name> 
     <percent_full>40</percent_full> 
     <pool_state>Disabled</pool_state> 
    </Pool> 
    <Totals> 
     <total_tracks>4546456</total_tracks> 
     <percent_full>48</percent_full> 
    </Totals> 
    </parent_two> 
</parent_one> 

的KSH脚本应该读sample.xml中和,因为相应的pool_state标签启用从POOL_NAME标签打印ABC,DEF。它不应该打印XYZ,因为它的pool_state标签被禁用。

的KSH脚本会读sample.xml中输出以下

ABC

DEF

这是在KSH可行的还是我用perl这个?

+0

你真的不想自己解析XML。当你声明你不允许使用它时,你为什么要问你是否必须使用perl? – 2013-04-08 17:15:06

回答

1

我已经做了相当多的奇格式文件的解析与(N)AWK。从技术上讲,这可能是与做只是KSH,但AWK(和Per​​l)更容易...

下面的示例利用了开始结构中awk只会处理之间的界线开始结束模式。 (在这种情况下,<Pool></Pool>。)

除此之外,它很简单,使用变量模仿xml元素来清晰起见。

awk '/<Pool>/,/<\/Pool>/ { 
    if (/<pool_state>/) { 
     pool_state=(/<pool_state>Enabled<\/pool_state>/) 
    } 
    if (/<pool_name>/) { 
     if (gsub(/.*<pool_name>|<\/pool_name>.*/,"")) { 
      pool_name=$0 
     } 
    } 
    if (/<\/Pool>/) { 
     if (pool_name && pool_state) 
     print pool_name 
     unset pool_name 
     unset pool_state 
    } 
}' sample.xml 

当XML格式不正确此代码将可怕失败,当多个池元件上的单个行中列出,等等

+0

哇,我不知道你可以在awk中做到这一点。今天学了点儿新东西。谢谢 – Sumedh 2013-04-12 11:26:03

0

话虽这么说(我对试图解析XML没有一个适当的XML解析器评论),让我们使用SED/AWK,不是纯粹的ksh给它一个镜头。以this answer为基础,删除所有<Pool></Pool>块具有pool_state设置为Disabled,然后让含有pool_name的线条和捕捉标记之间的值。如果你的xml文件看起来像你的示例这应该工作,但肯定会打破,如果没有。

awk ' 
    /<Pool>/ { rec=""; f=1 } 
    f {rec = rec $0 ORS} 
    /<\/Pool>/ { 
     if (f && (rec !~ "<pool_state>Disabled</pool_state>")) 
      printf "%s", rec 
      f=0 
    }' sample.xml | 
grep pool_name | 
sed 's#.*>\([^<]*\)<.*#\1#g' 

你能适应整个事情到一个awk脚本,但我想这可能是更容易执行(OK,我的懒惰)。

+0

Adrian,你的解决方案很有效,但我会选择Henk的解决方案,因为它更易于理解:)谢谢 – Sumedh 2013-04-12 11:28:56

+1

当然,无论哪个都适合你!请记住,一旦你开始做更复杂的事情,你应该考虑切换到“正确的”工具:-) – 2013-04-12 13:14:39

1

理智解决这个问题是进行呼叫出来xmllint --xpathxqilla -p,或者你喜欢的Python/Ruby/Perl等XML库。

否则,你可以看看罗兰美因茨的XML实例,并延长他们你的目的。

如果你是这个,你可能会想看看书写绑定的libxml2使ksh很严重的。我认为还没有人做到这一点。