0

由于缺乏信息,我就该主题提出的第一个问题已关闭。因此,再次询问这个问题并添加了更多细节。

我必须从 xml 文件中提取一个标签中给出的值,并且必须使用 ksh 来完成(我可以在 perl 中解决这个问题,但我必须使用 ksh,不能使用第三方工具,如 xmlsh)

示例.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 并输出以下内容

美国广播公司

国防军

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

4

3 回答 3

1

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

以下示例使用了startend构造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 元素列在一行上等时,此代码将严重失败。

于 2013-04-09T22:39:16.140 回答
1

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

否则,您可以查看 Roland Mainz 的 XML 示例并根据您的目的对其进行扩展。

如果您对此非常认真,您可能希望考虑为 ksh 的 libxml2 编写绑定。我认为还没有人这样做过。

于 2013-04-09T23:08:26.097 回答
0

话虽如此(我对尝试在没有适当的 XML 解析器的情况下解析 XML 的评论),让我们使用 sed/awk 来试一试,而不是纯 ksh。以这个答案为基础,删除所有设置为的<Pool></Pool>块,然后获取包含并捕获标签之间的值的行。如果您的文件看起来像您的示例,这应该可以工作,但如果没有,肯定会中断。pool_stateDisabledpool_namexml

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 脚本中,但我认为这可能更容易理解(好吧,我很懒)。

于 2013-04-08T17:34:06.337 回答