-1

I am just entering to the perl world, I got a task to replace multiple xml file in a folder using perl, I tried some of the perl one line code but it does not helped me out, I need a perl code which replace multiple text files in a selected folder. I tried this below post from stackoverflow Replace values for multiple XML files in a folder using perl but it also not helped me. Kindly be gentle because I am new, I furnish my tried code from above stackflow post showing error, please see and suggest solution.

my $dir = ***D:\Perl***;
my $d = opendir();
map {
    if (
        -f "$dir/$_"
        && ($_ =~ "\.xml$")
    ) {
        open (my $input_file, '<', ) or die "unable to open $input_file $!\n";

        my $input;
        {
            local $/;               #Set record separator to undefined.
            $input = <$input_file>; #This allows the whole input file to be read at once.
        }
        close $input_file;

        $input =~ s/Comment//g;

        open (my $output_file, '>', "$dir/$_") or die "unable to open $output_file $!\n";
        print {$output_file} $input;

        close $output_file or die $!;
    }
} readdir($d);
closedir($d);

error

syntax error at hello3.pl line 10, near "=~ "\.xml$""
Global symbol "$dir" requires explicit package name at hello3.pl line 23.
Global symbol "$output_file" requires explicit package name at hello3.pl line 23.
syntax error at hello3.pl line 28, near "}"
Global symbol "$d" requires explicit package name at hello3.pl line 28.
Global symbol "$d" requires explicit package name at hello3.pl line 29.
Execution of hello3.pl aborted due to compilation errors.

XML files are in the folder D:\Perl\

1.xml
2.xml
3.xml

codes in each xml files are follow below

<?xml version="1.0">
<root>
<!--This is my comment line 1-->
<subtag>
<element>This is 1.xml file</element>
</subtag>
</root>
3
  • What exactly are you trying to replace? Commented May 21, 2015 at 4:08
  • replace a specific tag from all xml files, say for example I am removing <!--comment text--> from all xml files Commented May 21, 2015 at 4:40
  • Why am I seeing uses of map instead of foreach recently? Commented May 21, 2015 at 6:58

1 Answer 1

2

I'm impressed as a newcomer to Perl, you've latched on to map. map is designed to turn an array into a hash - and it can do this by evaluating a code block.

However that's pretty nasty, because it creates code that's hard to follow. Why not instead use a for (or foreach) loop? The key warning sign is 'am I assigning the result of map to a hash (or hashref)?' If the answer is no, then chances are this isn't a good way to do it.

Also: I tend to prefer glob over opendir for this style of iteration operation.

But most importantly of all:

Don't use regular expressions and line based parsing for XML

Please, please, please use an XML Parser to parse XML. Doing so via regular expressions is just nasty - it makes brittle unreliable code. There's a bunch of things in the XML spec that makes semantically identical XML (and therefore 'valid' from a perspective of an upstream system) not match your regular expressions. Things like unary tags, line wrapping and splitting tags across lines.

As an example:

<XML
><some_tag
att1="1"
att2="2"
att3="3"
></some_tag></XML>

Or:

<XML><some_tag att1="1" att2="2" att3="3"></some_tag></XML>

Or:

<XML>
  <some_tag
      att1="1"
      att2="2"
      att3="3"></some_tag>
</XML>

Or:

<XML>
  <some_tag att1="1" att2="2" att3="3"></some_tag>
</XML>

Or:

<XML>
  <some_tag att1="1" att2="2" att3="3"/>
</XML>

All 'say' basically the same thing (technically there's a minor difference between a 'no text' and a 'null text' in the last example), but as I hope you can clearly see - a line and regex based test to encompass all of them would be difficult. Which is why I keep on suggesting - "use a parser" every time this comes up.

With that in mind - you probably don't actually need to remove comments at all - because they're part of the XML spec, and it's far better to handle them as part of the parse process.

I like XML::Twig and perl for this. Other modules exist though, and it may be that you get on with others (like XML::LibXML) instead.

Oh, and there's an error in your XML the line should be:

<?xml version="1.0"?>

Anyway, with that in mind - to answer your question as asked:

Removing comments from some XML

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

use XML::Twig;

foreach my $file ( glob("$dir/*.xml") ) {
    my $twig =
        XML::Twig->new( comments => 'drop', pretty_print => 'indented_a' );
    $twig->parsefile($file);
    open( my $output, ">", $file . ".new" ) or warn $!;
    print {$output} $twig->sprint;
    close($output);
}

This will turn your sample XML into:

<?xml version="1.0"?>
<root>
  <subtag>
    <element>This is 1.xml file</element>
  </subtag>
</root>

Deleting 'non comment' elements

If you were wanting to delete something other than comments - bearing in mind that comments are a special case - and instead wanted to say, get rid of a particular element:

XML::Twig->new( pretty_print => 'indented_a',
                twig_handlers => { 'element' => sub { $_ -> delete } } );

Note - this will delete every element tag - you can apply more selective criteria either via an xpath expression (e.g. 'subtag/element') or use a proper subroutine to handle and parse:

sub delete_element_with_file {
    my ( $twig, $element ) = @_;
    if ( $element->text =~ m/file/ ) { $element->delete }
}


my $twig = XML::Twig->new(
    pretty_print  => 'indented_a',
    twig_handlers => { 'subtag/element' => \&delete_element_with_file }
);

##etc. 
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your encouragement, I am just a beginner not a perfect coder, I got referenced the code from internet and tried. Please I don`t have know the knowledge as you guess any way thanks for your comment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.