Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

How to remove empty XML elements using XML::LibXML

by FreakyGreenLeaky (Sexton)
on Feb 17, 2013 at 19:22 UTC ( #1019196=perlquestion: print w/ replies, xml ) Need Help??
FreakyGreenLeaky has asked for the wisdom of the Perl Monks concerning the following question:

Evening robe-rufflers... I have next to zero experience with XML and XML::LibXML and I hope someone can shed some light on the following.

Basically, I want to remove some empty elements in XML.

<?xml version="1.0" encoding="UTF-8"?> <epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.o +rg/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:n +s:epp-1.0 epp-1.0.xsd"> <command> <update> <contact:update xmlns:contact="urn:ietf:params:xml:ns:contact-1. +0" xsi:schemaLocation="urn:ietf:params:xml:ns:contact-1.0 contact-1.0 +.xsd"> <contact:id>testaccount3</contact:id> <contact:add/> <contact:rem/>

I need to remove those last two empty elements, but I'm guessing the namespace stuff (or something) is a factor.

I've naively tried the following:

for my $remove ($frame->findnodes(q{/command/update/contact:update/con +tact:add})) { $remove->unbindNode; }

Edit: using the above findnodes() results in the error:

XPath error : Undefined namespace prefix error : xmlXPathCompiledEval: evaluation failed
But I must admit I'm clueless here and would appreciate some pointers.

Update:
I've been looking at the source which creates the XML:
/usr/lib/perl5/site_perl/5.8.8/Net/EPP/Frame/Command/Update/Contact.pm

sub new { my $package = shift; my $self = bless($package->SUPER::new('update'), $package); my $contact = $self->addObject(Net::EPP::Frame::ObjectSpec->spec(' +contact')); foreach my $grp (qw(add rem chg)) { my $el = $self->createElement(sprintf('contact:%s', $grp)); $self->getNode('update')->getChildNodes->shift->appendChild($e +l); } return $self; }
And I must confess to being mightily tempted to just remove add rem from the foreach. This works, but it makes me feel decidedly dirty - and I might need those elements in the future.

Solution:

my $p = $frame->getElementsByTagName('contact:update'); foreach my $n ($p->[0]->childNodes()) { $p->[0]->removeChild($n) if $n->toString(1) eq "<contact:add/> +"; }
Not very elegant, but it works. If someone knows of a better way, I'd love to hear it.

Comment on How to remove empty XML elements using XML::LibXML
Select or Download Code
Re: How to remove empty XML elements using XML::LibXML
by choroba (Canon) on Feb 17, 2013 at 20:40 UTC
    If you want to use a namespace prefix, you have to register it first:
    #!/usr/bin/perl use warnings; use strict; use XML::LibXML; my $xml = XML::LibXML->load_xml( location => '1.xml'); my $xpc = XML::LibXML::XPathContext->new($xml); $xpc->registerNs('contact', 'urn:ietf:params:xml:ns:contact-1.0'); for my $name (qw(rem add)) { for my $node ($xpc->findnodes("//contact:$name".'[not(*|text()|@*| +processing-instruction()|comment())]', $xml->documentElement)) { $node = $node->parentNode->removeChild($node); } } print $xml->serialize;
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      Thanks - that works perfectly when operating on 1.xml or another XML document object.

      Your sample uncovered another layer/problem:

      my XML document comes from Net::EPP::Frame (cpan.org says "This module implements a subclass of the XML::LibXML::Document..."), so I'm doing something wrong when I try:

      use Net::EPP::Frame; my $frame = Net::EPP::Frame::Command::Update::Contact->new; #... my $xpc = XML::LibXML::XPathContext->new($frame); $xpc->registerNs('contact', 'urn:ietf:params:xml:ns:contact-1.0'); for my $name (qw(rem add)) { for my $node ($xpc->findnodes("//contact:$name".'[not(*|text() +|@*|processing-instruction()|comment())]', $frame->documentElement)) +{ $node = $node->parentNode->removeChild($node); } } print $frame->toString(1);

      My thinking is that because Net::EPP::Frame inherits from XML::LibXML::Document, I should be able to operate on $frame (the XML document) similarly to your original solution... but I'm missing something.

        I have no experience with Net::EPP::Frame. What error do you get, or how is the output different from your expectations? Also, what does ref $frame say?
        لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: How to remove empty XML elements using XML::LibXML
by Anonymous Monk on Feb 17, 2013 at 23:16 UTC
      Thanks Anonymous One, I'll definitely study those references to gain a better understanding...

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1019196]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (12)
As of 2015-07-03 08:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (49 votes), past polls