in reply to xpath problem using XML::LibXML

G'day anadem,

You appear to have gotten close. You give the impression that you were just trying all the variations you could think of: one more and you probably would have been there. However, that's not a very efficient way to code: it's better to understand what you're doing than continually throwing pieces of code at a problem until one of them turns out to be right.

Here's the latest "W3C XPath" documentation. The "Path Expressions" section has full details but I usually find that just the "Abbreviated Syntax" subsection suffices in most cases.

In your first code fragment you needed this path for findnodes():

'//matrix/vm[@type="br"]'

Had you done that, I believe you would have got what you wanted.

All of your attempts had either the findnodes() or the findvalue() path right but the other one wrong.

The XML::LibXML documentation should help you with your outstanding tasks.

-- Ken

Replies are listed 'Best First'.
Re^2: xpath problem using XML::LibXML
by anadem (Scribe) on Apr 12, 2014 at 17:40 UTC

    Thank you Ken for the pointers to the docs. Your assessment of my trying variations is close; I'm a slow learner, new to xml (and not strong on perl), and was getting desperate. That documentation will be my friend for the remaining tasks!

    Fwiw the change of quoting you suggested doesn't actually fix my mistake. My error was misunderstanding of the result that xpath '//matrix/vm@type="br"' matches, so as pointed out in the comment above I was wrongly adding an extra 'vm' child level in findvalue("./vm/release/\@version").

      "Fwiw the change of quoting you suggested doesn't actually fix my mistake."

      My apologies if the change in quoting was misinterpreted as part of the fix.

      The change from //vm to //matrix/vm was the fix.

      You had multiple instances of \' and \@ (within double-quoted strings) throughout your post: the quoting change was a cure for backslashitis. :-)

      Here's the test I ran prior to posting:

      #!/usr/bin/env perl -l use strict; use warnings; use XML::LibXML; my $file = 'pm_1082058_n4000-small.xml'; my $parser = XML::LibXML->new(); my $doc = $parser->parse_file($file); for my $vm ($doc->findnodes('//matrix/vm[@type="br"]')) { my $version = $vm->findvalue('./release/@version'); print 'Version: ', $version; print 'Wanted: ', $vm->findvalue('./release/@wanted'); if ($version eq '7.2.1') { print 'Found!'; last; } }

      Output:

      Version: 7.2.2 Wanted: Version: 7.2.1 Wanted: YES Found!

      As you can see, there's no backslashes here at all (which I find makes the code more readable). The '//matrix/vm[@type="br"]' solution which I posted in my original reply was copied directly from that. If you want to run that test (or modifiy it for other tests), the data I used (pm_1082058_n4000-small.xml) is in the spoiler below.

      -- Ken

        Ah, thanks, understood. Yes, the de-backslashed code is much easier to grasp. And thank you for pointing the xpath element fix.