繁体   English   中英

使用ksh脚本从XML中提取数据

[英]Extract data from XML using ksh script

由于缺乏信息,我就此主题提出的第一个问题已经结束。 所以再添一些细节再问这个问题。

我必须从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_name标记打印ABC,DEF,因为相应的pool_state标记已启用。 它不应该打印XYZ,因为它的pool_state标记被禁用。

ksh脚本将读取sample.xml并输出以下内容

ABC

DEF

这在ksh中是可行的还是我必须使用perl?

我用(n)awk完成了很多奇数格式文件的解析。 从技术上讲,这可以用ksh完成,但是awk(和perl)更容易......

以下示例使用awk中的startend构造,该构造仅处理开始结束模式之间的行。 (在本例中为<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格式错误,多个Pool元素列在一行上时,此代码将失败。

这个问题的理智解决方案是调用xmllint --xpathxqilla -p或您xqilla -p Python / Ruby / Perl等XML库。

否则,您可以查看Roland Mainz的XML示例并将其扩展用于您的目的。

如果您对此非常认真,那么您可能希望研究为libhml2编写绑定以获取ksh。 我认为还没有人这样做过。

话虽如此(我的评论是关于尝试在没有适当的XML解析器的情况下解析XML),让我们使用sed / awk,而不是纯粹的ksh。 以此答案为基础,删除将pool_state设置为Disabled所有<Pool></Pool>块,然后获取包含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脚本中,但我认为这可能更容易理解(好吧,我很懒)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM