删除多行XML节点的Perl代码
我有一个 xml 文件 test.xml
<many-nested-roots>
<foo>
<bar>
</bar>
</foo>
<other-random-nodes></other-random-nodes>
<foo>
<bar>
<foobar>
</foobar>
</bar>
</foo>
<!-- multiple such blocks not in any particular order -->
</many-nested-roots>
我需要删除 xml 节点<foo><bar></bar></foo>而不是<foo><bar><foobar></foobar></bar></foo>.
编辑:该节点<foo><bar></bar></foo>在严重嵌套的 XML 中随机出现多次。
我试过哪些不起作用:
perl -ne 'print unless /^s*<foo>ns*<bar>ns*<bar>ns*</foo>/' test.xml
^ 这与换行符不匹配
perl -ne 'print unless /<foo>/ ... /</foo>/' test.xml
^ 这将删除所有标签,包括 <foobar>
perl -ne 'print unless /<foo>.*?<bar>.*?</bar>.*?</foo>/s' test.xml
^ 我曾经/s让.匹配换行。不起作用。
回答
一个单行使用XML::LibXML和一个 XPath 表达式来查找要删除的节点:
perl -MXML::LibXML -E '
my $dom = XML::LibXML->load_xml(location => $ARGV[0]);
$_->unbindNode for $dom->documentElement->find("//foo/bar[count(*)=0]/..")->@*;
print $dom->serialize' test.xml
(旧版本的 perl 需要@{$dom->...}而不是$dom->...->@*)
或者使用xmlstarlet(不是 perl,但对于 XML 文件的脚本操作非常方便):
xmlstarlet ed -d '//foo/bar[count(*)=0]/..' test.xml