user690182
user690182

Reputation: 279

perl, libxml, xpath : how to get an element through an attribute in this example .xml file

I would like your help in the following :

given the .xml file :

<network>
    <netelement>
            <node pwd="KOR-ASBG" func="describe_SBG_TGC">
                    <collection category="IMT" dir="Stream_statistics"></collection>
                                    </node>
    </netelement>
    <netelement>
            <node pwd="ADR-ASBG" func="describe_SBG_TGC">
                    <collection category="IMT" dir="Stream_statistics"></collection>
                    <collection category="IMT" dir="Proxy_registrar_statistics_ACCESS"></collection>
            </node>
    </netelement></network>

What I would like to do is to get the element with the attribute "KOR-ASBG", for example, but using only XPath.

I have written the following Perl code :

#!/usr/bin/perl         -w

use             strict ;
use             warnings ;
use             XML::LibXML ;
use             Data::Dump qw(dump) ;


my $dump = "/some_path/_NETELEMENT_.xml" ;
my $parser = new XML::LibXML ; my $doc ;
eval{ $doc = $parser->parse_file($dump) ; } ;
if( !$doc ) { print "failed to parse $dump" ; next ; }
my $root = $doc->getDocumentElement ;

my $_demo = $root->find('/network/netelement/node[@pwd="KOR-ASBG"]') ;
print dump($_demo)."\n" ;

But, what it gets dispalyed is :

bless([bless(do{\(my $o = 155172440)}, "XML::LibXML::Element")], "XML::LibXML::NodeList")

So the question would be, how can I get the XML Element that contains the "pwd" attribute (that equals "KOR-ASBG"), using XPath ?

Thank you :)

PS. I have also tried :

my @_demo = $root->findnodes('/network/netelement/node[@pwd="KOR-ASBG"]') ;
print dump(@_demo)."\n" ;

and what it gets displayed is :

bless(do{\(my $o = 179552448)}, "XML::LibXML::Element")

Upvotes: 2

Views: 8313

Answers (3)

Axeman
Axeman

Reputation: 29844

What you are seeing is what they call in Perl an "opaque object". It's not a hash, but a key to a set of lexical hashes in the the package which hold the fields for all the instances. It's Perl's way of implementing objects with security. The only way to get at their info is to call their get accessors.

The way to figure out how to deal with these is note the second argument to the bless and look up this:

http://search.cpan.org/perldoc?<name-of-package>

Or in your case: http://search.cpan.org/perldoc?XML::LibXML::NodeList and
http://search.cpan.org/perldoc?XML::LibXML::Element

Now, I don't recommend this in all cases, but if you notice, the NodeList object is a blessed array reference. So you could just access the last node, like so:

my $nodes      = $root->find('/network/netelement/node[@pwd="KOR-ASBG"]');
my $first_node = $nodes->[0];
my $last_node  = $nodes->[-1];

Of course it often makes sense to make a list implementation behave like an array, either through blessed array or overloaded operators or ties. So, in this case, I don't think it's too big a violation of encapsulation.

Upvotes: 2

Leonardo Herrera
Leonardo Herrera

Reputation: 8406

Your dumper object is not lying to you; you are getting a node list. To access it you may either iterate through it or just access the first node:

print $_demo->get_node(0)->toString()

Of course, all DOM methods are available to you once you get the actual node:

print $_demo->get_node(0)->getAttribute('func');

Upvotes: 2

ikegami
ikegami

Reputation: 385496

There could technically be more than one element that matches, which is why a result set is being returned instead of single node. You could use

my ($ele) = $root->findnodes('/network/netelement/node[@pwd="KOR-ASBG"]');

That will place the first match into $ele.

Upvotes: 4

Related Questions