Gajiu Gajiu - 1 month ago 19
Perl Question

How can I write at the top of an XML file with XML::Writer

I create an XML file with XML::Writer in Perl and I would want that each times I call my script it write the new XML file at the beginning of the old file. I know how to write a line at the beginig of a file, but with XML::Writer I can't find how to do that.

my $output = new IO::File(">>tmp.xml");
my $writer = new XML::Writer(
OUTPUT => $output,
DATA_INDENT => 3, # indentation, trois espaces
DATA_MODE => 1, # changement ligne.
);


That's the beginning of my script wich write the xml file.
Edit :
I actually do a changelog.xml wich looks like that :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet href="changelog.xsl" type="text/xsl"?>

<root text="MultiDiag">
<version number="V: 7.07.10.0" date="Release date (Fri Oct 7 14:44:52 2016)">
Things
</version>
</root>


What I want is that each day, the new changelog is write at the top of the old one like that :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet href="changelog.xsl" type="text/xsl"?>
<root text="MultiDiag">
<version number="V: 7.07.10.0" date="Release date (The new one)">
Things
</version>
<version number="V: 7.07.10.0" date="Release date (The old one)">
Things
</version>
</root>


Thanks for the help.

Answer

The trick is to not let XML::Writer write to a file directly. Instead, you can set OUTPUT to "self" and then use the $writer->to_string method to get a string with the rendered output.

After that, all you need to do is follow this example from perlfaq5 on how to write to the beginning of a file. You basically read in your existing file line by line, and print it back to a new file. If you're at line 1 ($. is the current line number being read), you print the XML from $writer. Then you move/rename your temporary new file over the old one.

use strict;
use warnings;
use IO::File;
use XML::Writer;

my $writer = XML::Writer->new( 
    OUTPUT      => 'self',
    DATA_INDENT => 3,             # indentation, trois espaces
    DATA_MODE   => 1,             # changement ligne.
);

# ... put in your data

# open the old file and a temporary new file
open my $in,  '<',  'tmp.xml'  or die "Can't read old file: $!";
open my $out, '>', 'tmp.xml.new' or die "Can't write new file: $!";

# read from the old file
while( <$in> ) {
    # write the XML into the first line
    print $out $writer->to_string if $. == 1;

    # write the rest of the file line by line
    print $out $_;
}
close $in; 
close $out;

# replace the old file with the new file
rename 'tmp.xml.new', 'tmp.xml';