http://www.perlmonks.org?node_id=1174530


in reply to XML::LibXML drives me to drinking

What you're wanting is $xpathcontext->findnodes( $xpathstring, $startnode )

I much prefer my version $node->F($xpathstr, 'prefix'=>'http...')

#!/usr/bin/perl -- use strict; use XML::LibXML; my $string = qq~<?xml version="1.0"?> <ItemLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceS +ervice/2013-08-01"> <Items> <Item> <ASIN>B01KI4JSQY</ASIN> </Item> </Items> </ItemLookupResponse> ~; my $dom = XML::LibXML->new(qw/ recover 2 / )->load_xml(string => $str +ing, {no_blanks => 1}); # *register* namespace $dom->F( '/', 'x', 'http://webservices.amazon.com/AWSECommerceService/2013-08-01 +' ); foreach my $item ( $dom->F('/x:ItemLookupResponse/x:Items/x:Item' )){ print $item->firstChild->nodeName, "\n"; print $item->firstChild->toString, "\n"; print $item->F('x:ASIN')->shift()->string_value, "\n"; print $item->F('./x:ASIN/text()'), "\n"; print $item->F('./x:ASIN')->[0]->textContent, "\n"; } sub XML::LibXML::Node::F { my $self = shift; my $xpath = shift; my %prefix = @_; our $XPATHCONTEXT; $XPATHCONTEXT ||= XML::LibXML::XPathContext->new(); while( my( $p, $u ) = each %prefix ){ $XPATHCONTEXT->registerNs( $p, $u ); } $XPATHCONTEXT->findnodes( $xpath, $self ); }

Replies are listed 'Best First'.
Re^2: XML::LibXML drives me to drinking
by tunafish (Beadle) on Oct 23, 2016 at 03:59 UTC

    Wait, are you saying I need to create a new XML::LibXML::XPathContext object for each node as I loop through them?!

    I modified my code in the following way:

    # Parse items foreach my $item ($xml->findnodes('/x:ItemLookupResponse/x:Items/x:Ite +m', $parser)){ my $item_xml = XML::LibXML::XPathContext->new($item); $item_xml->registerNs('x', 'http://webservices.amazon.com/AWSE +CommerceService/2013-08-01'); print $item_xml->findvalue('x:ASIN'), "\n"; print $item_xml->findnodes('x:ASIN')->shift->textContent, "\n" +; }

    And bingo!

    B01KI4JSQY B01KI4JSQY

    Oy vey! Wouldn't it be much more convenient if a XML::LibXML::XPathContext object calling the findnodes() method returned another XML::LibXML::XPathContext object, rather than a XML::LibXML::Node or XML::LibXML::Element object?

    I haven't pulled this much hair in one day for a coding-related reason IN YEARS.

      Wait, are you saying I need to create a new XML::LibXML::XPathContext object for each node as I loop through them?!

      No, what gave you that idea?

      All XML::LibXML::XPathContext does is map prefixes to namespaces, and that only needs to be done once.

      See https://metacpan.org/pod/XML::LibXML::Node#findnodes

      I haven't pulled this much hair in one day for a coding-related reason IN YEARS.

      step away from the keyboard, lunch, nap, vacation, whatever it takes