The following working code reads my XML
file containing lots of empty elements, then applies 2 changes and saves it again under different name.
But it also changes empty elements like <element></element>
to self-closing tags like <element />
which is unwanted.
How to save it not using self-closing tags?
Or by another words how to tell XML::LibXML
to use empty tags?
The original file is produced in commercial application, which uses style with empty elements, so I want to sustain that.
#! /usr/bin/perl
use strict;
use warnings;
use XML::LibXML;
my $filename = 'out.xml';
my $dom = XML::LibXML->load_xml(location => $filename);
my $query = '//scalar[contains(@name, "partitionsNo")]/value';
for my $i ($dom->findnodes($query)) {
$i->removeChildNodes();
$i->appendText('16');
}
open my $out, '>', 'out2.xml';
binmode $out;
$dom->toFH($out);
# now out2.xml has only self-closing tags where previously
# were used empty elements
Unfortunately, XML::LibXML
doesn't support libxml2's xmlsave
module which has a flag to save without empty tags.
As a workaround you can add an empty text node to empty elements:
for my $node ($doc->findnodes('//*[not(node())]')) {
# Note that appendText doesn't work.
$node->appendChild($doc->createTextNode(''));
}
This is a bit costly for large documents, but I'm not aware of a better solution.
That said, the fragments <foo></foo>
and <foo/>
are both well-formed and semantically equivalent. Any XML parser or application that treats such fragments differently is buggy.
Note that some people believe the XML spec recommends using self-closing tags, but that's not exactly true. The XML spec says:
Empty-element tags may be used for any element which has no content, whether or not it is declared using the keyword EMPTY. For interoperability, the empty-element tag should be used, and should only be used, for elements which are declared EMPTY.
This means elements that are declared EMPTY in a DTD. For other elements, or if no DTD is present, the XML standard advises not to use self-closing tags ("and should only be used"). But this is only a non-binding recommendation for interoperability.