Arun Ganesh
Arun Ganesh

Reputation: 65

XML Replace Value for a Tag and Add a Tag

Need help in updating XML. I have gone through this link and it has been very helpful.

Perl code for Find and replace a tag value in XML

In continuation, I have created below code but still need more help. The tag value that I want to replace is 'numCoreThreads'.

When I give a tag value, it replaces the value and working fine.

My XML -->

<svr_config>
<port>34343</port>
<PortMapper>false</PortMapper>
<numCoreThreads>12</numCoreThreads>

<plugins>
    <plugin>

        <userDefined>
            <ftOptimizeThreshold>1000</ftOptimizeThreshold>
        </userDefined>
    </plugin>
</plugins>

Current Code -->

#!C:\strawberry\perl

use strict;
use warnings;

use XML::Twig;

XML::Twig->new( twig_roots =>    { numCoreThreads => sub { $_->flush }, },
            twig_handlers => { 'numCoreThreads[string()="12"]' => sub { $_->set_text(       '5000'); } },
            twig_print_outside_roots => 1,
          )
      ->parsefile_inplace( 'config.xml');

Trying to make the code more dynamic like reading the input file and then updating the xml based on argument read from input file. I know...running the loop would print the whole file again...can we optimize that?

My Input file looks like this

numCoreThreads: 20
OptimizeThreshold: ftOptimizeThreshold: 250

Code I have made looks like this:

#!C:\strawberry\perl

use strict;
use warnings;
use XML::Twig;
open(IN1,"INPUT_FTS_XML_PRIMARY.txt");

while(my $r=<IN1>)
{
    $r=~/(.*:)\s(.*)/;
    my $c1=$1;
    my $d1=$2;
    my $f1=$3
my $twig = XML::Twig->new(
twig_handlers => {
    '$c1' => sub { $_->set_text( 'd1' ) },
    if (defined $f1)
    {
    '$d1' => sub {
        my $e = XML::Twig::Elt->new( '$c1' => '$f1' );
        $e->move( after => $_ );
    },}  
},  
pretty_print => 'indented',
)->parsefile( shift )->print;
}

Upvotes: 3

Views: 917

Answers (1)

Birei
Birei

Reputation: 36262

I would do all the work inside twig_handlers:

#!/usr/bin/env perl

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

my $twig = XML::Twig->new(
    twig_handlers => {
        'numCoreThreads' => sub { $_->set_text( '5000' ) },
        'ftOptimizeThreshold' => sub {
            my $e = XML::Twig::Elt->new( 'OptimizeThreshold' => '250' );
            $e->move( after => $_ );
        },  
    },  
    pretty_print => 'indented',
)->parsefile( shift )->print;

Run it like:

perl script.pl xmlfile

It yields:

<svr_config>
  <port>34343</port>
  <PortMapper>false</PortMapper>
  <numCoreThreads>5000</numCoreThreads>
  <plugins>
    <plugin>
      <userDefined>
        <ftOptimizeThreshold>1000</ftOptimizeThreshold>
        <OptimizeThreshold>250</OptimizeThreshold>
      </userDefined>
    </plugin>
  </plugins>
</svr_config>

UPDATE: See comments.

Read each line of the file with arguments, split with colon and save fields in a data structure that fits your needs. Then simply replace literals with the content of these values.

die qq|Usage: perl $0 <arg-file> <xml-file>\n| unless @ARGV == 2;

open my $fh, '<', shift or die;
while ( <$fh> ) {
    chomp;
    my @f = split /\s*:\s*/;
    ## Save fields in a data structure.
}

Upvotes: 3

Related Questions