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?

+3


source to share


2 answers


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";
}

      

+4


source


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.

Ref: Re ^ 2: XML :: LibXML and namespaces

+2


source







All Articles