由于缺乏信息,我就此主题提出的第一个问题已经结束。因此,再添一些细节再次询问这一点。
我必须从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?
答案 0 :(得分:1)
我用(n)awk解析了奇数格式文件。从技术上讲,这可以通过ksh完成,但awk(和perl)更容易......
以下示例使用awk
中的 start , end 构造,该构造仅处理 start 之间的行和结束模式。 (在这种情况下为<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元素列在一行上时,此代码将会失败,等等。
答案 1 :(得分:1)
这个问题的理智解决方案是调用xmllint --xpath
,xqilla -p
或您喜欢的Python / Ruby / Perl等XML库。
否则,您可以查看Roland Mainz的XML示例并将其扩展用于您的目的。
如果您对此非常认真,那么您可能希望研究为libhml2编写绑定以获取ksh。我认为还没有人这样做过。
答案 2 :(得分: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脚本中,但我认为这可能更容易理解(好吧,我很懒)。