Search code examples
xmlperlxml-twig

How can I modify an XML file in place using Perl's XML::Twig?


I am using Perl and XML::Twig. I have made some changes in the XML file( changing the values of the tags). But I cannot write it in the same XML file. If I use parsefile_inplace() the whole XML file got empty. Please find the code below.

use strict;
use warnings;
use XML::Twig;

my $twig= XML::Twig->new(
        pretty_print => 'indented',
        twig_handlers => {
            jdk => sub{ 
            $_->set_text( 'JDK 1.8.0_40' )
            },
            },
        );
$twig->parsefile_inplace( 'nightly.xml', 'bak.*' );
$twig->flush;

Part of XML file:

<jdk>JDK 1.7.0_40</jdk>

If I use flush command it gives the desired output on cmd.

If I use parsefile_inplace command it is emptying the nightly.xml.

If I just use parsefile the original file is left intact without changing the value i want to change.

My requirement is to edit the value and save it in the same file


Solution

  • Here is what the documentation for parsefile_inplace says:

    parsefile_inplace ( $file, $optional_extension)

    Parse and update a file "in place". It does this by creating a temp file, selecting it as the default for print() statements (and methods), then parsing the input file. If the parsing is successful, then the temp file is moved to replace the input file.

    If an extension is given then the original file is backed-up (the rules for the extension are the same as the rule for the -i option in perl). (emphasis mine)

    I do not see any print statements in your code.

    Here is one way to do it, with small changes to your code:

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    use XML::Twig;
    
    my $twig= XML::Twig->new(
        pretty_print => 'indented',
        twig_roots => {
            jdk => sub{
                my ($t, $jdk) = @_;
                $jdk->set_text( 'JDK 1.8.0_40' );
                $jdk->print;
                $jdk->purge;
                return;
            },
        },
        twig_print_outside_roots => 1,
    );
    
    $twig->parsefile_inplace( 'nightly.xml', '.bak' );
    $twig->flush;