1

I got an XML template which looks like this (excerpt):

<isSomething>_xxx_</isSomething>
<someValue>_xxx_</someValue>

My code is going through the template and replacing the _xxx_ placeholders using XML::LibXML's findnode and setData methods respectively.

In the end it looks like this:

<isSomething>true</isSomething>
<someValue>123.45</someValue>

This does the job, however the recipient system would be more happy if the isSomething tag would look like this in case its true:

<isSomething/>

And would be completely omitted in case it's false. Is there a way to do that with XML::LibXML or should i apply the mighty regex power on the string output?

LWNirvana
  • 47
  • 10
  • Nooo don't use regexes! http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags – Sobrique Mar 05 '15 at 16:34

2 Answers2

5

To remove a node, use removeChild. To produce an empty element, remove its text child:

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

use XML::LibXML;

my $xml = 'XML::LibXML'->load_xml( string => << '__XML__');
<root>
  <node id="a">
    <isSomething>_xxx_</isSomething>
    <someValue>_xxx_</someValue>
  </node>
  <node id="b">
    <isSomething>_xxx_</isSomething>
    <someValue>_xxx_</someValue>
  </node>
</root>
__XML__

my %nodes = ( a => [ 'true',  1 ],
              b => [ 'false', 2 ],
            );

for my $node ($xml->documentElement->findnodes('//node')) {
    my $id = $node->{id};
    my ($is_something, $value) = @{ $nodes{$id} };

    my ($s) = $node->findnodes('isSomething[.="_xxx_"]');
    if ('true' eq $is_something) {
        my ($text) = $s->findnodes('text()');
        $s->removeChild($text);
    } else {
        $node->removeChild($s);
    }

    my ($v) = $node->findnodes('someValue/text()[.="_xxx_"]');
    $v->setData($value);
}
print $xml;
choroba
  • 231,213
  • 25
  • 204
  • 289
  • Thanks for that. Had to rewrite for my setup here and there, but worked, and I can utilize this for my code. – LWNirvana Mar 09 '15 at 11:21
4

So first - please don't regex your XML. It's dirty. RegEx match open tags except XHTML self-contained tags

I think what you will be wanting is LibXML::XML::Element - specifically:

new

$node = XML::LibXML::Element->new( $name );

This function creates a new node unbound to any DOM.

Followed by:

$node->replaceNode($newNode);

In XML::LibXML::Node

Community
  • 1
  • 1
Sobrique
  • 52,974
  • 7
  • 60
  • 101