user3649361
user3649361

Reputation: 954

How to add node to a XML file using perl XML::Twig

I need to add a node to a already existing xml file,my xml is like:-

<Install>
  <version >
    <number>6.1</number>
    <build>1025654</build>
    <path>path</path>
    <kind>RIBS</kind>
  </version>
</Install>

and after adding node it should look like

<Install>
  <version >
    <number>6.1</number>
    <build>1025654</build>
    <path>path</path>
    <kind>native</kind>
  </version>
  <version >
    <number>6.0</number>
    <build>1025786</build>
    <path>path</path>
    <kind>native</kind>
  </version>
</Install>

I tried the idea from following link but was not able to figure it out. using perl insert string xml to a node

I need to add the node and save the changes to the file. It should be reflected into the file. I am new to perl that why not able to figure it out.

What I tried is :-

use strict;
use warnings;

use XML::Twig;

my $myXML
  ='<version>6.1</version>
    <number>101445</number>
    <path>path</path>
    <kind>native</kind>
   ';
my $file = "C:\\Users\\bjoshi\\LightroomBuilds\\Win\\data.xml";
my $t= XML::Twig->new( twig_handlers => { grouping => sub { grouping( $myXML, @_); }, })
                ->parsefile( "$file") or die $!;

$t->print;
open my $xml_fh, '>', "$file" or die $!;
$t->set_pretty_print('indented_c');
$t->print($xml_fh);
exit;

sub grouping
  { my( $xml, $t, $grouping)= @_;
    my $new_elt= XML::Twig::Elt->parse( $xml);
    $new_elt->paste( last_child => $grouping);
  }

The output which I an getting is:-

<Install>
  <version>
    <number>6.1</number>
    <build>1025654</build>
    <path>path</path>
    <kind>native</kind>
  </version>
</Install>

Upvotes: 2

Views: 526

Answers (1)

simbabque
simbabque

Reputation: 54323

While the code from the linked answer by mirod did the same thing you wanted to do, you need to adjust it to fit your XML. I'll explain below what I did.

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

my $myXML = <<'XML';
<version>
  <number>6.0</number>
  <build>1025786</build>
  <path>path</path>
  <kind>native</kind>
</version>
XML

my $t = XML::Twig->new(
  twig_handlers => {
    Install => sub { add_version( $myXML, @_ ); }, }
  )->parse( \*DATA ) or die $!;

$t->set_pretty_print('indented_c');
$t->print;

sub add_version {
    my ( $xml, $t, $install ) = @_;
    my $new_elt = XML::Twig::Elt->parse($xml);
    $new_elt->paste( last_child => $install );
}

__DATA__
<Install>
  <version >
    <number>6.1</number>
    <build>1025654</build>
    <path>path</path>
    <kind>RIBS</kind>
  </version>
</Install>

This will read not from a file but from the DATA file handle that takes the stuff below __DATA__, and just print to the terminal/screen.

First of all, your expected output was like this:

<Install>
  ...
  <version>
    <number>6.0</number>
    ...
  </version>
</Install>

But the piece of XML to insert that you used in your code is like this:

<version>6.1</version>
<number>101445</number>
...

That's not what you said you wanted, so I guess that is a mistake.

The code you took from the answer was supposed to work for an element <grouping>. In principle it's the same, but it has a different name. So you need to adapt the code. I changed the twig_handlers to have a handler for Install because that is the root element of your XML. I went on to rename the subroutine and the variables inside to match that. It makes it more clear what's going on.

If you run it, you get this output:

<Install>
  <version>
    <number>6.1</number>
    <build>1025654</build>
    <path>path</path>
    <kind>RIBS</kind>
  </version>
  <version>
    <number>6.0</number>
    <build>1025786</build>
    <path>path</path>
    <kind>native</kind>
  </version>
</Install>

Upvotes: 2

Related Questions