nneul has asked for the wisdom of the Perl Monks concerning the following question:

Below code is outputting (paraphrased):
Entry XML for user1 apps:login for user1 apps:login for user2 Entry XML for user2 apps:login for user1 apps:login for user2
I'm expecting it to output:

Entry XML for user1 apps:login for user1 Entry XML for user2 apps:login for user2

What am I doing wrong? It looks like it is searching at the root of the document each time, regardless of what I set as a context node. Code snippet and data set. (http://pastebin.com/m25b1509d)

#!/usr/bin/perl use XML::LibXML; my $content = do { local($/); <DATA>; }; $parser = XML::LibXML->new(); $doc = $parser->parse_string($content); my $xc = XML::LibXML::XPathContext->new(); $xc->registerNs( atom => "http://www.w3.org/2005/Atom" ); $xc->registerNs( app => "http://www.w3.org/2007/app" ); $xc->registerNs( gd => "http://schemas.google.com/g/2005" ); $xc->registerNs( gcontact => "http://schemas.google.com/contact/2008 +" ); $xc->registerNs( batch => "http://schemas.google.com/gdata/batch" + ); $xc->registerNs( openSearch => "http://a9.com/-/spec/opensearchrss/1.0 +/" ); foreach my $entry ( $xc->findnodes( '/atom:feed/atom:entry', $doc ) ) +{ print "entry = '", $entry->toString(1), "'\n"; my @logins = $xc->findnodes( "//apps:login", $entry ); print join( "\n", @logins ), "\n"; } __END__ <?xml version="1.0" encoding="UTF-8"?> <feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9. +com/-/spec/opensearchrss/1.0/" xmlns:apps="http://schemas.google.com/ +apps/2006" xmlns:gd="http://schemas.google.com/g/2005"> <id>https://apps-apis.google.com/a/feeds/mst.edu/user/2.0</id> <updated>1970-01-01T00:00:00.000Z</updated> <category scheme="http://schemas.google.com/g/2005#kind" term="http: +//schemas.google.com/apps/2006#user"/> <title type="text">Users</title> <link rel="next" type="application/atom+xml" href="https://apps-apis +.google.com/a/feeds/mst.edu/user/2.0?startUsername=norbert"/> <link rel="http://schemas.google.com/g/2005#feed" type="application/ +atom+xml" href="https://apps-apis.google.com/a/feeds/mst.edu/user/2.0 +"/> <link rel="http://schemas.google.com/g/2005#post" type="application/ +atom+xml" href="https://apps-apis.google.com/a/feeds/mst.edu/user/2.0 +"/> <link rel="self" type="application/atom+xml" href="https://apps-apis +.google.com/a/feeds/mst.edu/user/2.0"/> <openSearch:startIndex>1</openSearch:startIndex> <entry> <id>https://apps-apis.google.com/a/feeds/mst.edu/user/2.0/user1</i +d> <updated>1970-01-01T00:00:00.000Z</updated> <category scheme="http://schemas.google.com/g/2005#kind" term="htt +p://schemas.google.com/apps/2006#user"/> <title type="text">user1</title> <link rel="self" type="application/atom+xml" href="https://apps-ap +is.google.com/a/feeds/mst.edu/user/2.0/user1"/> <link rel="edit" type="application/atom+xml" href="https://apps-ap +is.google.com/a/feeds/mst.edu/user/2.0/user1"/> <apps:login userName="user1" suspended="false" ipWhitelisted="fals +e" admin="false" changePasswordAtNextLogin="false" agreedToTerms="tru +e"/> <apps:quota limit="7168"/> <apps:name familyName="Last1" givenName="First1"/> <gd:feedLink rel="http://schemas.google.com/apps/2006#user.nicknam +es" href="https://apps-apis.google.com/a/feeds/mst.edu/nickname/2.0?u +sername=user1"/> <gd:feedLink rel="http://schemas.google.com/apps/2006#user.emailLi +sts" href="https://apps-apis.google.com/a/feeds/mst.edu/emailList/2.0 +?recipient=user1%40mst.edu"/> </entry> <entry> <id>https://apps-apis.google.com/a/feeds/mst.edu/user/2.0/user2</i +d> <updated>1970-01-01T00:00:00.000Z</updated> <category scheme="http://schemas.google.com/g/2005#kind" term="htt +p://schemas.google.com/apps/2006#user"/> <title type="text">user2</title> <link rel="self" type="application/atom+xml" href="https://apps-ap +is.google.com/a/feeds/mst.edu/user/2.0/user2"/> <link rel="edit" type="application/atom+xml" href="https://apps-ap +is.google.com/a/feeds/mst.edu/user/2.0/user2"/> <apps:login userName="user2" suspended="false" ipWhitelisted="fals +e" admin="false" changePasswordAtNextLogin="false" agreedToTerms="tru +e"/> <apps:quota limit="7168"/> <apps:name familyName="Last2" givenName="First2"/> <gd:feedLink rel="http://schemas.google.com/apps/2006#user.nicknam +es" href="https://apps-apis.google.com/a/feeds/mst.edu/nickname/2.0?u +sername=user2"/> <gd:feedLink rel="http://schemas.google.com/apps/2006#user.emailLi +sts" href="https://apps-apis.google.com/a/feeds/mst.edu/emailList/2.0 +?recipient=user2%40mst.edu"/> </entry> </feed>
  • Comment on Searching subtrees with XML::LibXML::XPathContext always searches whole document - why?
  • Select or Download Code

Replies are listed 'Best First'.
Re: Searching subtrees with XML::LibXML::XPathContext always searches whole document - why?
by mirod (Canon) on Feb 08, 2010 at 16:26 UTC

    I haven't checked thoroughly your code, but I'd be willing to bet that the problem is that //apps:login should be .//apps:login. With the . you start from the current node, without it you start from the root of the document. That's a common mistake with XPath. Am I right?

      Indeed.
      //apps:login

      is short for

      /descendant::apps:login

      Just like with directory paths, expressions starting with "/" start searching at the root. To look for descendants of the topic node, one must use a relative path such as

      descendant::apps:login
      or
      .//apps:login
        Thank you both!!! Knew it had to be something stupid-simple that was wrong with my usage.