0

Here is some simplified sample xml

<book_reviewers>
    <results>
        <reviewer>
            <name>Anne</name>
            <profession>Catfish wrangler</profession>
        </reviewer>
        <reviewer>
            <name>Bob</name>
            <profession>Beer taster</profession>
        </reviewer>
        <reviewer>
            <name>Charlie</name>
            <profession>Gardener</profession>
        </reviewer>
        <reviewer>
            <name>Don</name>
            <profession>DoGooder</profession>
        </reviewer>
        <reviewer>
            <name>Ellie</name>
            <profession>Elephant Trainer</profession>
        </reviewer>
        <reviewer>
            <name>Freddy</name>
            <profession>Fencer</profession>
        </reviewer>
    </results>
</book_reviewers>

Them i parse the data

#!/usr/bin/perl
use XML::LibXML;
use strict;

my $filename = "cr.xml";

my $parser = XML::LibXML->new();
my $critic_details = $parser->parse_file("$filename") or die;

Now I want to grab the details of a random reviewer

my $no_of_critics = ($critic_details->findvalue("count(/book_reviewers/results/reviewer)"));

I send number 1 and $no_of_critics off to a subroutine that returns a random number between one and $no_of_critics (i.e. n this case 1 and 6)

All of this works fine I just need to know how I tell it which reviewer - say it returns 5, then how do I tell it I want the fifth occurrence of reviewer? I have tried searching but I cannot get the right search term so I am a bit stuck

Cheers

Keryn Drake
  • 121
  • 2
  • 10

4 Answers4

0

Suppose you get 5 in return, then what you need to do is iterate over nodes and keep a counter which increments at each iteration, if the counter reaches 5, then you can print out information of that node.

Check findnodes at XML::LibXML::Node.

Also see:

  1. perl script to iterate over xml nodes using XML::LibXML

  2. Iterating over nodes using XML::LibXML

Community
  • 1
  • 1
Chankey Pathak
  • 21,187
  • 12
  • 85
  • 133
0

findnodes returns an array. You simply need to select which index of that array you want:

use strict;
use warnings;

use XML::LibXML;

my $dom = XML::LibXML->load_xml(IO => \*DATA);

my @reviewers = $dom->findnodes('//reviewer');
print "Count = " . @reviewers . "\n";

my $i = int rand @reviewers;
my $record = $reviewers[$i];
print $record, "\n";

__DATA__
<book_reviewers>
    <results>
        <reviewer>
            <name>Anne</name>
            <profession>Catfish wrangler</profession>
        </reviewer>
...
Miller
  • 34,962
  • 4
  • 39
  • 60
0

You can use the XPath expression that specifies n-th element in a list:

#!/usr/bin/perl
use warnings;
use strict;

use XML::LibXML;

my $filename = 'cr.xml';

my $parser         = 'XML::LibXML'->new();
my $critic_details = $parser->parse_file($filename) or die;
my $index          = 1 + int rand $critic_details->findvalue('count(/book_reviewers/results/reviewer)');
my $reviewer       = $critic_details->findnodes("/book_reviewers/results/reviewer[$index]");
print $reviewer;

Note that positions in XPath start from 1, unlike from 0 as array indices in Perl.

choroba
  • 231,213
  • 25
  • 204
  • 289
0

Building on top of what yu already had in your previous question:

use strict;
use warnings;

use utf8;

use XML::LibXML;

my $filename = "cr.xml";

my $parser = XML::LibXML->new();
my $critic_details = $parser->parse_file("$filename") or die;

# find ALL the <book_reviewers><results><reviewers> nodes
my @reviewers = $critic_details
  ->findnodes("book_reviewers/results/reviewer");
die "no reviewer nodes in xml-file" unless @reviewers;

# @reviewers in scalar context gives the number of elements
my $reviewer = $reviewers[ rand @reviewers ];

printf "reviewer: %s (%s)\n",
  $reviewer->findvalue("name"),
  $reviewer->findvalue("profession"),
  ;

__END__

which could result in:

reviewer: Anne (Catfish wrangler)

enjoy!

vanHoesel
  • 956
  • 9
  • 22