tags:

views:

619

answers:

4

Hi,

I have a XML file of the format:

<outer1>
    <inner1>
     <name>Stonecold</name>
     <profession>warrior</profession>
     <org>wwf</org>
    </inner1>
    <inner1>
     <name>Shanebond</name>
     <profession>Bowler</profession>
     <org>newzealand</org>
    </inner1>
    <inner1>
     <name>brain schemidit</name>
     <profession>Chairman</profession>
     <org>Google</org>
    </inner1>
</outer1>

I want to change the value of Shanebond to Shane Bond.

I was using XML::Simple, but the result was a hash.

I want the same format as the input file. E.g: the output file should be as follows:

<outer1>
    <inner1>
     <name>Stonecold</name>
     <profession>warrior</profession>
     <org>wwf</org>
    </inner1>
    <inner1>
     <name>Shane Bond</name>
     <profession>Bowler</profession>
     <org>newzealand</org>
    </inner1>
    <inner1>
     <name>brain schemidit</name>
     <profession>Chairman</profession>
     <org>Google</org>
    </inner1>
</outer1>

Please advice how to do this.

Thanks in advance.

I want the output file to be saved in the same directory and if possible with the same name. is it possible?

+3  A: 

Have you tried XMLout with OutputFile

From the documentation for XML::Simple:

The default behaviour of XMLout() is to return the XML as a string. If you wish to write the XML to a file, simply supply the filename using the 'OutputFile' option.
This option also accepts an IO handle object - especially useful in Perl 5.8.0 and later for output using an encoding other than UTF-8, eg:

open my $fh, '>:encoding(iso-8859-1)', $path or die "open($path): $!";
XMLout($ref, OutputFile => $fh);
Nifle
i tried this and its working properly. i have to insert it in the main code and then check the result. thanks for your help.
PJ
+3  A: 

XML::Simple has options that allow you to specify how input will be transformed into a Perl data structure and how that structure will be output:

#!/usr/bin/perl

use strict;
use warnings;

use XML::Simple;

my $xml_file = 'b.xml';

my $xml = XMLin(
    $xml_file,
    KeepRoot => 1,
    ForceArray => 1,
);

$xml->{outer1}->[0]->{inner1}->[1]->{name} = 'Shane Bond';

XMLout(
    $xml,
    KeepRoot => 1,
    NoAttr => 1,
    OutputFile => $xml_file,
);

XML::Simple does get a little hairy if you do anything interesting because its purpose is not to be a general purpose XML library but to provide a simple way to deal with configuration files written in XML.

CPAN has a plethora of XML related modules. Unless this was a one-off issue you had to deal with, it would be worth looking into some of the more capable and better suited modules.

Sinan Ünür
I want the output file to be saved in the same directory and if possible with the same name. is it possible?
PJ
@pchakraborty Of course it is possible. Nifle even showed how to do it. The docs explain `OutputFile` clearly. Do read them occasionally: They help.
Sinan Ünür
i tried this and its working properly. i have to insert it in the main code and then check the result. thanks for your help.
PJ
+3  A: 

When it comes to reading or manipulating a XML file then XML::Twig is often the first tool I look to use.

At first I thought it maybe an overkill for your requirement but then I noticed it did come with a parsefile_inplace() option:

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

XML::Twig->new(
    pretty_print  => 'indented',
    twig_handlers => { 
        name => sub { 
            $_->set_text( 'Shane Bond' )->flush  if $_->text eq 'Shanebond' 
        },
    },
)->parsefile_inplace( 'data.xml', 'bak_*' );

NB. If you don't want to keep a backup file then remove the second arg ('bak_*').

/I3az/

draegtun
A: 

Why bother processing it as XML at all? Why not just do a regexp-replace?

perl -pi -e 's/Shanebond/Shane Bond/' filename.xml

That will do the replacement in place, keeping the same filename and everything.

Peter Kovacs