I have an XML file: 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>
I want to replace the ABC in 'UML:Class name="2012"' into DEF and have the result to be output in a new file:
<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>
The perl script I use is:
#!/usr/bin/perl -w
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->new( twig_roots => { 'UML:Class' => \¨_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";
}
It doesn't work as expected. How can I change it to get the desired result? Thanks a lot,
You're mixing print
and print_to_file
. print_to_file
is not magical, it doesn't cause all print
s to go to the file. You need to modify the attribute value in the original document, then print_to_file
will output the new value.
I would do this this way:
#!/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');
A couple of notes:
'UML:Class[@name="2012"]'
) instead of a simple UML:CLASS
and then testing the attribute value in the handler.latt
method gives you an attribute as an lvalue
that you can change in place, you could alternatively use $v= $def->att( 'value'); $v=~ s{ABC}{DEF}; $def->set_att( $v);
... but using latt
makes it much simplernew
/parse
/print_to_file
), I like this style for code that's as simple as this one YMMV