Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clear content in xml brackets in all files in directory tree on Windows using Strawberry Perl and twig

Tags:

I want to clear whole content that is placed inside of <loot> </loot> elements in XML files in a directory tree. I am using Strawberry Perl for windows 64 bit.

For example this XML file:

<?xml version="1.0" encoding="UTF-8"?>
<monster name="Dragon"/>
<health="10000"/>
<immunities>
   <immunity fire="1"/>
</immunities>
<loot>
<item id="1"/>
  <item id="3"/>
      <inside>
        <item id="6"/>
      </inside>
  </item>
</loot>

The changed file should look:

<?xml version="1.0" encoding="UTF-8"?>
<monster name="Dragon"/>
<health="10000"/>
<immunities>
   <immunity fire="1"/>
</immunities>
<loot>
</loot>

I have this code:

#!/usr/bin/perl
use warnings;
use strict;

use File::Find::Rule;
use XML::Twig;

sub delete_loot {
   my ( $twig, $loot ) = @_;
   foreach my $loot_entry ( $loot -> children ) {
      $loot_entry -> delete;
   }
   $twig -> flush;
}

my $twig = XML::Twig -> new ( pretty_print => 'indented', 
                              twig_handlers => { 'loot' => \&delete_loot } ); 

foreach my $file ( File::Find::Rule  -> file()
                                     -> name ( '*.xml' )
                                     -> in ( 'C:\Users\PIO\Documents\serv\monsters' ) ) {

    print "Processing $file\n";
    $twig -> parsefile_inplace($file); 
}

But it edits correctly only the first file it meets and the rest files leaves clear (0 kb clear files)

like image 372
Piodo Avatar asked Jan 02 '17 11:01

Piodo


1 Answers

The XML::Twig doc says that "Multiple twigs are not well supported".

If you look at the state of the twig object (using Data::Dumper for example) you see a strong difference between the first and subsequent runs. It looks like it considers that is has been totally flushed already (which is true, as there was a complete flush during the first run). It probably has nothing more to print for the subsequent files and the file ends up empty.

Recreating the twig object at each loop worked for me:

#!/usr/bin/perl
use warnings;
use strict;

use File::Find::Rule;
use XML::Twig;

sub delete_loot {
   my ( $twig, $loot ) = @_;
   foreach my $loot_entry ( $loot -> children ) {
        $loot_entry -> delete;
    }
}

foreach my $file ( File::Find::Rule  -> file()
                                     -> name ( '*.xml' )
                                     -> in ( '/home/dabi/tmp' ) ) {

    print "Processing $file\n";
    my $twig = XML::Twig -> new ( pretty_print => 'indented', 
                                  twig_handlers => { loot => \&delete_loot, } ); 
    $twig -> parsefile($file); 
    $twig -> print_to_file($file);
}

Also, I had to change the XML file structure to have it processed:

<?xml version="1.0" encoding="UTF-8"?>
<monster name="Dragon">
<health value="10000"/>
<immunities>
   <immunity fire="1"/>
</immunities>
<loot>
<item id="1"/>
  <item id="3">
      <inside>
        <item id="6"/>
      </inside>
  </item>
</loot>
</monster>
like image 157
David Verdin Avatar answered Sep 22 '22 11:09

David Verdin