【问题标题】:removing all but one node in perl XML::Twig删除 perl XML::Twig 中除一个节点外的所有节点
【发布时间】:2018-03-01 08:54:40
【问题描述】:

我有一个包含许多 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 = new XML::Twig (twig_handlers => { 'level1/level2' => \&edit }); 我不知道在实际的 xml 文件中 level2 有多深,实际文件的结构可能不完全相同,所以这部分应该是动态的

【问题讨论】:

    标签: xml perl xml-twig


    【解决方案1】:

    不需要$twig-&gt;purge 或类似的行,我不明白你为什么要写它

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

    我也推荐你写

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

    因为您使用的 indirect object 语法模棱两可且容易出错。 pretty_print 选项还将使输出 XML 更具可读性。

    【讨论】:

    • 删除 $twig-&gt;purge 成功了。它在教程中,我仍在学习该模块,并没有考虑太多。有什么办法可以提高代码的速度吗? XML::Twig 似乎比 XML::LibXML 慢得多:将 level2 元素传递给 twig 处理程序并迭代其子代,还是将 level3 元素传递给 twig 处理程序并迭代兄弟姐妹?
    • @Kot789:你需要问一个新问题。
    【解决方案2】:

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

    您想要做的似乎是删除第一个之后的所有“level3”元素。

    所以:

    #!/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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-13
      • 2022-08-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多