XML :: LibXML, namespaces and findvalue
I am using XML::LibXML
to parse a namespaced XML document. So I am using XML::LibXML::XPathContext
up findnodes
using XPath //u:model
. This correctly returns 3 nodes.
Now I would like to use findvalue
for the 3 returned objects XML::LibXML::Element
, but cannot figure out a working method / xpath.Alternatively, I iterate over the children and map them to nodeName directly, but this is less than ideal:
use strict;
use warnings;
use XML::LibXML;
use XML::LibXML::XPathContext;
my $dom = XML::LibXML->load_xml( IO => \*DATA );
my $context = XML::LibXML::XPathContext->new( $dom->documentElement() );
$context->registerNs( 'u' => 'http://www.ca.com/spectrum/restful/schema/response' );
for my $node ( $context->findnodes('//u:model') ) {
#my $mh = $node->findvalue('mh');
my ($mh)
= map { $_->textContent() }
grep { $_->nodeName() eq 'mh' } $node->childNodes();
#my $attr = $node->findvalue('attribute');
my ($attr)
= map { $_->textContent() }
grep { $_->nodeName() eq 'attribute' } $node->childNodes();
print "mh = $mh, attr = $attr\n";
}
__DATA__
<root xmlns="http://www.ca.com/spectrum/restful/schema/response">
<error>EndOfResults</error>
<throttle>86</throttle>
<total-models>86</total-models>
<model-responses>
<model>
<mh>0x100540</mh>
<attribute id="0x1006e">wltvbswfc02</attribute>
</model>
<model>
<mh>0x100c80</mh>
<attribute id="0x1006e">wltvsutm1ds02</attribute>
</model>
<model>
<mh>0x100c49</mh>
<attribute id="0x1006e">wltvsdora03</attribute>
</model>
</model-responses>
</root>
Outputs:
mh = 0x100540, attr = wltvbswfc02
mh = 0x100c80, attr = wltvsutm1ds02
mh = 0x100c49, attr = wltvsdora03
Is there a way to use commented lines to find nodes instead of an indirect iteration method on children? Or is there any other way to approach this problem in order to get paired values?
source to share
You cannot use $node->findvalue()
because of the whole thing the default namespaces. However, you can reuse your XML :: LibXML :: XPathContext object to find the values you want:
for my $node ( $context->findnodes('//u:model') ) {
my $mh = $context->findvalue('u:mh', $node);
my $attr = $context->findvalue('u:attribute', $node);
print "mh = $mh, attr = $attr\n";
}
source to share
XPath lets you ignore namespaces with the function local-name
:
use XML::LibXML;
my $dom = XML::LibXML->load_xml( IO => \*DATA );
for my $node ( $dom->findnodes('//*[local-name()="model"]') ) {
my $mh = $node->findvalue('*[local-name()="mh"]');
my $attr = $node->findvalue('*[local-name()="attribute"]');
print "mh = $mh, attr = $attr\n";
}
This removes the need to provide context for a single namespace document like in the question.
source to share