如何使用基于标记值的shell脚本拆分xml文件

时间:2016-09-16 13:10:33

标签: shell

我有一个以下示例XML文件作为源。

<XML version?>
<DATA>
<List>
    <A> </A>
    <B>100</B>
    <C> </C>
</List>
<List>
    <A> </A>
    <B>200</B>
    <C> </C>
</List>
<List>
    <A> </A>
    <B>100</B>
    <C> </C>
</List>
<List>
    <A> </A>
    <B>100</B>
    <C> </C>
</List>
</DATA>

根据标签B中的值,我需要创建一个新的xml文件。

例如,我必须在标签B中过滤100以外的值,我需要创建一个新的xml文件,如下所示,

<XML version?>
<DATA>
<List>
    <A> </A>
    <B>100</B>
    <C> </C>
</List>
<List>
    <A> </A>
    <B>100</B>
    <C> </C>
</List>
<List>
    <A> </A>
    <B>100</B>
    <C> </C>
</List>
</DATA>

请告诉我,如何在shell脚本中执行此操作。在此先感谢。

2 个答案:

答案 0 :(得分:0)

尝试使用它作为stdinstdout的过滤器:

    sed -ne'/<List>/!{p;b};:a;H;/<\/List>/!{n;ba};x;/<B>100<\/B>/p'

详情请查看this tutorial

答案 1 :(得分:0)

使用实际上支持XML的工具。例如,使用XMLStarlet

# delete all List elements with a B having a value other than 100
xmlstarlet ed -d '//List[B != "100"]' <in.xml >out.xml

迭代所有这些值可能如下所示:

infile=in.xml

# to output to out-<B_VALUE>.xml
out_prefix=out-
out_suffix=.xml

while read -r b_value; do
  xmlstarlet ed -d "//List[B != '${b_value}']" \
    <"$infile" \
    >"${out_prefix}${b_value}${out_suffix}"
done < <(xmlstarlet sel -t -m '//List/B' -v . -n <"$infile" | sort -u)

将输入文件修复为实际有效的XML(<?xml version="1.0"?>,而不是<XML version?>)后,我会从您的示例输入中获取两个文件。

out-100.xml包含以下内容:

<DATA>
  <List>
    <A> </A>
    <B>100</B>
    <C> </C>
  </List>
  <List>
    <A> </A>
    <B>100</B>
    <C> </C>
  </List>
  <List>
    <A> </A>
    <B>100</B>
    <C> </C>
  </List>
</DATA>

...和out-200.xml因此:

<?xml version="1.0"?>
<DATA>
  <List>
    <A> </A>
    <B>200</B>
    <C> </C>
  </List>
</DATA>