Question

I am new to XML::Twig. How can I change all empty elements to use empty-element tags (<foo/>) instead of a start-tag and end-tag combo (<foo></foo>)?

Input:

<book>
    <given-names>Maurice<xref ref-type="fn" rid="fnI_1"></xref></given-names>
    <colspec colname="col1" colnum="1"></colspec>
    <entry align="left"><p></p></entry>
</book>

I need output as:

<book>
    <given-names>Maurice<xref ref-type="fn" rid="fnI_1"/></given-names>
    <colspec colname="col1" colnum="1"/>
    <entry align="left"><p/></entry>
</book>

I tried:

       use XML::Twig;
       my $xml = XML::Twig->new(twig_handlers => {
                                  'xref' => sub {$_->set_tag('#EMPTY'),},
                                },
                                pretty_print => 'indented',                                        
                               );
       $xml->parse('sample.xml');
       $xml->print;
}

But I can't process it. How can change gloabally without content tag to empty tag? how can I change?

Was it helpful?

Solution 2

If you want to stick with Twig, you can do it like this:

#!usr/bin/perl
use strict;
use warnings;
use XML::Twig;

my $xml = XML::Twig->new(twig_handlers => {
             'p' => sub { 
                 if (!$_->first_child()) { $_->set_content('#EMPTY') } 
              },
           },
           pretty_print => 'indented',
           empty_tags => 'normal'                                 
);

$xml->parsefile('file.xml');
$xml->print;

Basically you have to manually check if the element contains nothing, then set it to be an empty element.

OTHER TIPS

XML::LibXML will automatically output the shorter version.

use XML::LibXML qw( );
print XML::LibXML->new()->parse_file($ARGV[0])->toString();

As for XML::Twig, it also uses the shorter form by default (empty_tags => 'normal'). However, it only considers empty elements those that were created from <foo/>. (Seems pretty stupid to me!) I did some digging and found that it does allow you change if it considers an element empty or not. This is done using set_empty and set_not_empty.

use XML::Twig qw( );
my $twig = XML::Twig->new(
   twig_handlers => {
      '*' => sub {
         $_->set_empty() if !$_->first_child();
      },
   },
);
$twig->parsefile($ARGV[0]);
$twig->print();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top