5

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?

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
PJ.
  • 625
  • 3
  • 12
  • 24
  • the xml file is a config file and the component that is using it can't read the hash file. also if its format is changed after creating the file then also the component is unable to read the value from the config file – PJ. Aug 25 '09 at 12:14
  • 1
    XMLin -> process contents -> XMLout – innaM Aug 25 '09 at 13:00

4 Answers4

8

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_*').

AndyG
  • 39,700
  • 8
  • 109
  • 143
draegtun
  • 22,441
  • 5
  • 48
  • 71
5

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
  • 2,657
  • 21
  • 19
4

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
  • 116,958
  • 15
  • 196
  • 339
  • I want the output file to be saved in the same directory and if possible with the same name. is it possible? – PJ. Aug 25 '09 at 12:14
  • @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 Aug 25 '09 at 13:28
  • 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. Aug 26 '09 at 11:27
3

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
  • 11,745
  • 10
  • 75
  • 100
  • 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. Aug 26 '09 at 11:29