删除perl XML :: Twig中除一个节点外的所有节点

时间:2017-09-20 10:27:53

标签: xml perl xml-twig

我有一个包含多个level3元素的xml文件。我想删除除一个这样的元素之外的所有元素。我的xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<level1 id="level1_id">
    <level2 id="level2_id">
        <level3 id="level3_id1">
            <attributes>
                <attribute>1</attribute>
                <attribute>2</attribute>
            </attributes>
        </level3>
        <level3 id="level3_id2">
            <attributes>
                <attribute>1</attribute>
                <attribute>2</attribute>
            </attributes>
        </level3>
        <level3 id="level3_id3">
            <attributes>
                <attribute>1</attribute>
                <attribute>2</attribute>
            </attributes>
        </level3>
    </level2>
</level1>

我的perl脚本:

my $filename = 'test3.xml';
my $outfile = $filename."_after";
open my $output, '>', $outfile or die "Couldn't open output file\n";
my $twig = new XML::Twig (twig_handlers => { 'level2' => \&edit });
$twig->parsefile($filename);
#$twig->flush;
$twig->print($output);

sub edit {
    my ($twig, $element) = @_;
    my @elements= $element->children('level3');
    print $#elements."\n";
    my @elements= @elements[1..$#elements];
    print $#elements."\n";
    my $count = 0;
    foreach (@elements){
        $count++;
        $_->delete;
    }
    print $count;
    $twig->purge;

}

然而,这只留下了level1元素:

<?xml version="1.0" encoding="UTF-8"?>
<level1 id="level1_id"></level1>

另一方面,当顶级为level2时,我的脚本运行正常。示例xml文件和处理后的结果:

<?xml version="1.0" encoding="UTF-8"?>

<level2 id="level2_id">
    <level3 id="level3_id1">
        <attributes>
            <attribute>1</attribute>
            <attribute>2</attribute>
        </attributes>
    </level3>
    <level3 id="level3_id2">
        <attributes>
            <attribute>1</attribute>
            <attribute>2</attribute>
        </attributes>
    </level3>
    <level3 id="level3_id3">
        <attributes>
            <attribute>1</attribute>
            <attribute>2</attribute>
        </attributes>
    </level3>
</level2>

结果:

<?xml version="1.0" encoding="UTF-8"?>
<level2 id="level2_id">
    <level3 id="level3_id1">
        <attributes>
            <attribute>1</attribute>
            <attribute>2</attribute>
        </attributes>
    </level3>
</level2>

这正是我想要的,即只留下一个level3元素。我究竟做错了什么?是否与我如何定义枝条处理程序有关? 我不想硬编码xml结构,例如我的$ twig =新的XML :: Twig(twig_handlers =&gt; {'level1 / level2'=&gt; \&amp; edit}); 我不知道level2在实际的xml文件中有多深,实际文件的结构可能不一样,所以这部分应该是动态的

2 个答案:

答案 0 :(得分:1)

不需要第$twig->purge行或类似的内容,我也不明白为什么要写它

它将丢弃已解析但未打印到输出的任何内容,这是您刚刚编辑的整个level2元素

我还建议你写

my $twig = XML::Twig->new(
    twig_handlers => { level2 => \&edit },
    pretty_print  => 'indented',
);

由于您使用的间接对象语法不明确且容易出错。 pretty_print选项还可以使输出XML更具可读性。

答案 1 :(得分:-1)

我建议除非您特别想要对大文件进行增量解析,否则twig_handers会不必要地复杂化。如果您希望将XML视为流并修改/丢弃其中的一部分,它实际上通常只是加载整个XML,并且使用它更简单,更清晰,它就是一个强大的工具。

您要做的似乎是删除所有&#39; level3&#39;第一个元素之后。

所以:

#!/usr/bin/perl

use strict;
use warnings;

use XML::Twig;


my $twig = XML::Twig->new->parsefile('your_xml_file.xml');
my $count;

foreach my $level3 ( $twig->get_xpath('.//level3') ) {
   #delete after the first one. 
   $level3->delete if $count++;
}

#set formatting
$twig -> set_pretty_print('indented_a');
#print to stdout
$twig->print;