3

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.

  • I would want the code to replace any value that is present to given value.
  • Also, How can I add a new tag under a parent tag. Exp Add Tag -

    <OptimizeThreshold>250</OptimizeThreshold> under
    <ftOptimizeThreshold>1000</ftOptimizeThreshold>
    

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;
}
Community
  • 1
  • 1
Arun Ganesh
  • 65
  • 1
  • 10

1 Answers1

3

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.
}
Birei
  • 35,723
  • 2
  • 77
  • 82
  • Thanks Mate....But abt my first question....for numCoreThreads parameter how can I replace any value irrespective of a string there..in this case its 12...but can it search only tag and replace target value....Thanks Again :) – Arun Ganesh Nov 07 '13 at 16:03
  • 1
    @ArunGanesh: Remove the condition `[string()="12"]`. I put it because it was in your original code, but I've edited the answer to remove it. – Birei Nov 07 '13 at 16:05
  • Thanks will test and get back if I have more questions ....any gud guide for XML Twig ...examples etc? – Arun Ganesh Nov 07 '13 at 16:12
  • 1
    @ArunGanesh: Its `pod` documentation: `perldoc XML::Twig` – Birei Nov 07 '13 at 16:23
  • Basically...I am opening a file and trying to direct the print on that... open(OUT,">New_FTS_PRIMARY_pluginsvr_config_updated.xml");)->parsefile( shift )->print OUT; – Arun Ganesh Nov 08 '13 at 07:08
  • No worries...I did it...using the command perl script.pl xmlfile >xmlfile_updated.xml – Arun Ganesh Nov 08 '13 at 07:11
  • I am trying to make the code more dynamic...like reading a input file for arguments and updating the XML based on that...updated the question with my not working code...not really how to fit in regualr code in twig. @Birei / Guys ...need help ..thanks – Arun Ganesh Nov 08 '13 at 07:57
  • @@Birei: Thanks for your response. I understand fetching the data from the input file...but how can I use it within Twig handlers? The way that I have mentioned in my updated code...wud that work. Please see my code update above in Question. Thanks!! – Arun Ganesh Nov 08 '13 at 14:39
  • 1
    @ArunGanesh: This has nothing to do with a `xml` problem. It depends in what data structure you use and how you save your data. If you use a hash with `numCoreThreads` as key and `20` as value, replace the literal `5000` with `hash['numCoreThreads']`. If you use an array and you save the value in first position, replace the literal with `array[0]` and so on. Take a look to `perldsc` documentation page. – Birei Nov 08 '13 at 14:51
  • Thanks...noob alert..the code that I have made above also reads the input file one by one...stores the values in separate variables and tries to feed them to XML Twig. However, my current code gives me lot of compilation errors...Errors that I get... – Arun Ganesh Nov 08 '13 at 15:13
  • "my" variable $e masks earlier declaration in same statement at C:\xml_New.pl line 21. Use of my $_ is experimental at C:\xml_New.pl line 21. syntax error at C:\xml_New.pl line 14, near "$3my " Global symbol "$twig" requires explicit package name at C:\xml_New.pl line 14. Global symbol "$f1" requires explicit package name at C:\xml_New.pl line 17. syntax error at C:\xml_New.pl line 22, near "}" Execution of C:\xml_New.pl aborted due to compilation errors. – Arun Ganesh Nov 08 '13 at 15:14
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/40834/discussion-between-arun-ganesh-and-birei) – Arun Ganesh Nov 08 '13 at 15:59
  • @ArunGanesh: Your question has changed the focus. You don't know how to handle a data structure and is not related with the title of the question (replace xml tag). Your current code is a mess because you can't use XML::Twig without extracting all data from the configuration file first. I suggest you to open a new question asking for this concrete issue and some users will help you instead of going after me asking to modify my asnwer to fit your new requirements. – Birei Nov 08 '13 at 17:41
  • Thanks Mate ... I'll repost my question with more clarity to my new requirement. – Arun Ganesh Nov 08 '13 at 18:01