使用Perl删除XML节点 - 这个或那个

时间:2015-08-10 14:28:02

标签: perl

站在网络上其他人的伟大(对他们的道具),我跑过这个命令:

perl -0 -p -i -e 's|<nodeName>.*?</nodeName>|$&=~/this/?"":$&|gse' file

它将找到一个XML节点(在本例中为“nodeName”),查找特定字符串(在本例中为“this”),并删除整个节点。这很可爱。

使用此命令,文件如下所示:

<nodeName>
    <subNode>those</subNode>
</nodeName>
<nodeName>
    <subNode>this</subNode>
</nodeName>
<nodeName>
    <subNode>that</subNode>
</nodeName>
<nodeName>
    <subNode>these</subNode>
</nodeName>

看起来像这样:

<nodeName>
    <subNode>those</subNode>
</nodeName>
<nodeName>
    <subNode>that</subNode>
</nodeName>
<nodeName>
    <subNode>these</subNode>
</nodeName>

但是,我需要它来查找“this”或“that”,如果找到,则删除整个节点。所以为此,我正在使用这个命令:

perl -0 -p -i -e 's|<nodeName>.*?</nodeName>|$&=~/this/?"":$&|gse' file;perl -0 -p -i -e 's|<nodeName>.*?</nodeName>|$&=~/that/?"":$&|gse' file

这基本上是“两次执行命令以寻找两个不同的东西,但执行相同的操作。”我的问题是,原始的perl命令是否可以简化为在一个命令中查找“this”或“that”?

我试过这个:

perl -0 -p -i -e 's|<nodeName>.*?</nodeName>|$&=~/(this|that)/?"":$&|gse' file

但我对perl有点绿。我认为这可以与此类似:

s/(dog|cat)s are (invited|welcome)/$1s are not $2/;

但事实并非如此。我不确定我希望能达到的目标是否可行。所以最后,我确实得到了一点点。重申一下这个问题:可以简化原始的perl命令,在一个命令中查找“this”或“that”吗?

提前谢谢。

注意:我正在处理未安装xmlstarlet的服务器,我无权安装它。

3 个答案:

答案 0 :(得分:5)

由于您的外部正则表达式使用管道|作为分隔符,因此在内部正则表达式中将管道用作or时,您将破坏该模式。

perl -0 -p -i -e 's{<nodeName>.*?</nodeName>}{$&=~/(?:this|that)/?"":$&}gse' file

就像它应该工作。我用{}替换了管道。我还添加了一个非捕获组,因为没有理由保持this|that可用。

你当然也可以逃避内部|,但上述解决方案更清晰。

perl -0 -p -i -e 's|<nodeName>.*?</nodeName>|$&=~/(this\|that)/?"":$&|gse' file

另请注意,它可能适用于每个行文件的一个标记,但如果XML更复杂,它将会中断。

答案 1 :(得分:2)

perl -i -0777pe's{
   <nodeName>
   (?: (?!</nodeName>). )*
   (?: this | that )
   (?: (?!</nodeName>). )*
   </nodeName>
}{}xsg' file

答案 2 :(得分:2)

呃,请不要这样做。 XML不适合使用正则表达式进行解析。您可以对XML执行各种语义相同的操作,这意味着正则表达式不再匹配。

请 - 代表未来的系统管理员和维护程序员 - 改为使用解析器。

如果要删除包含文本'this'或'that'的'nodeName':

#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;

XML::Twig->new(
    'pretty_print'  => 'indented_a',
    'twig_handlers' => {
        'nodeName' => sub { $_->delete if $_->text =~ m/this|that/ }
    }
)->parse( \*DATA )->print;

__DATA__
<root>
<nodeName>
    <subNode>those</subNode>
</nodeName>
<nodeName>
    <subNode>this</subNode>
</nodeName>
<nodeName>
    <subNode>that</subNode>
</nodeName>
<nodeName>
    <subNode>these</subNode>
</nodeName>
</root>

这会设置一个“捕获”nodeName的小枝处理程序,并在条件适用时删除。

如果你想要单行:

perl -MXML::Twig -e 'XML::Twig->new( 'pretty_print'  => 'indented_a', 'twig_handlers' => {'nodeName' => sub { $_->delete if $_->text =~ m/this|that/ }})->parsefile( $ARGV[0] )->print;'

您也可以使用parsefile_inplace更改原始源文件。