XML::Twig 如果父标签的属性是某个东西,则替换文件中的字符串

XML::Twig replace string in a file if attribute of parent tag is something

我有一个 XML 文件:uml.model

<UML:Class name="2012">
  <type2>
    <type1>
        <def value="test string ABC" />
    </type1>
  </type2>
</UML:Class>

<UML:Class name="2013">
  <type2>
    <type1>
        <def value="test string ABC" />
    </type1>
  </type2>
</UML:Class>

我想将 'UML:Class name="2012"' 中的 ABC 替换为 DEF,并将结果输出到新文件中:

<UML:Class name="2012">
  <type2>
    <type1>
        <def value="test string DEF" />
    </type1>
  </type2>
</UML:Class>

<UML:Class name="2013">
  <type2>
    <type1>
        <def value="test string ABC" />
    </type1>
  </type2>
</UML:Class>

我使用的perl脚本是:

#!/usr/bin/perl -w
use strict;
use warnings;

use XML::Twig;
my $twig = XML::Twig->new( twig_roots => { 'UML:Class' => \&uml_class } );
$twig->parsefile( 'uml.model' );
$twig->print_to_file( 'uml.model.new' );

sub uml_class {
    my ( $twig, $section ) = @_;
    my $subTwig;
    my $year = $section->{'att'}->{'name'};

    if ( $year eq '2012' ) {
        $subTwig = XML::Twig->new( twig_roots => { 'type1/def' => \&type_def } );
        $subTwig->parse( $section->sprint() };
    }
}

sub type_def {
    my ($twig, $elt) = @_;
    $elt->print ();
    print "\n";
}

它没有按预期工作。我怎样才能改变它以获得想要的结果?非常感谢,

您正在混合 printprint_to_fileprint_to_file 并不神奇,它不会导致所有 print 都转到文件中。您需要修改原始文档中的属性值,然后print_to_file将输出新值。

我会这样做:

#!/usr/bin/perl

use strict;
use warnings;

use XML::Twig;

open( my $out, '>', 'uml.model.new') or die "cannot create uml.model.new: $!";

XML::Twig->new( twig_roots => { 'UML:Class[@name="2012"]' =>
                                   sub { my $def= $_->next_elt( 'def');
                                         $def->latt( 'value')=~ s{ABC}{DEF};
                                         $_->flush;
                                       },
                                 },
                twig_print_outside_roots => $out,
                pretty_print => 'indented',


              )
         ->parsefile( 'uml.model');

一些注意事项:

  • 我使用复杂的触发器 ('UML:Class[@name="2012"]') 而不是简单的 UML:CLASS,然后在处理程序中测试属性值。
  • latt 方法为您提供了一个 lvalue 属性,您可以就地更改,您也可以使用 $v= $def->att( 'value'); $v=~ s{ABC}{DEF}; $def->set_att( $v);... 但是使用 latt简单多了
  • 我链接了方法调用 (new/parse/print_to_file),我喜欢这种代码风格,就像这个 YMMV