Search code examples
xmlperlmojolicious

Does Mojo::DOM provide the possibility to use nested syntax?


How could I write this example with the Mojo::DOM module?

#!/usr/bin/env perl
use warnings;
use 5.012;
use XML::LibXML;

my $string =<<EOS;
<result>
    <cd>
    <artists>
        <artist class="1">Pumkinsingers</artist>
        <artist class="2">Max and Moritz</artist>
    </artists>
    <title>Hello, Hello</title>
    </cd>
    <cd>
    <artists>
        <artist class="3">Green Trees</artist>
        <artist class="4">The Leons</artist>
    </artists>
    <title>The Shield</title>
    </cd>
</result>
EOS
#/
my $parser = XML::LibXML->new();
my $doc = $parser->load_xml( string => $string );
my $root = $doc->documentElement;

my $xpath = '/result/cd[artists/artist[@class="2"]]/title';

my @nodes = $root->findnodes( $xpath );
for my $node ( @nodes ) {
    say $node->textContent;
}

Solution

  • Mojo::DOM supports CSS3 selectors, which are amazing, but not quite as versatile as xpath; CSS3 doesn't provide a way to ascend after descending into a node.

    You can accomplish the same thing, though it's a bit more involved:

    Mojo::DOM->new($string)
      ->find('result:root > cd > artists > artist.2')
      ->each(sub { say shift->parent->parent->title->text });
    

    or

    say $_->parent->parent->title->text
      for Mojo::DOM->new($string)
        ->find('result:root > cd > artists > artist.2')->each;