Search code examples
perlxml-twig

Processing nested elements using XML::Twig


<cov>
    <item>
        <valo></valo>
        <valt></valt>
        <valtr></valtr>
    </item>             
    <item>
        <valo></valo>
        <valt></valt>
        <valtr></valtr>
    </item>             
    <item>
        <valo></valo>
        <valt></valt>
        <valtr></valtr>
    </item>             
</cov>

I'm trying to use twig to loop through valo and valtr for each item - how can I do this?

I have this so far, but inside the subroutine how can I then specify the right node "valo"?

my $t = XML::Twig->new(twig_handlers => {'cov/item' => \&item });
my $url;
$t->parse($fileContent);

sub item {
    my ($t, $item) = @_;
    print $item->text . "\n";
}

Solution

  • Here's a handler that shows a way to inspect the children of the cov/item nodes:

    sub item {
        my ($t, $item) = @_;
    
        my @kids = $item->children;
        for my $kid ( @kids ) {
            warn "valo is:  " . $kid->text if $kid->name eq q{valo};
            warn "valtr is: " . $kid->text if $kid->name eq q{valtr};
        }
    }
    

    Another approach is to use findnodes( ) and Twig's XPath-like syntax to locate the elements:

    my $t = XML::Twig->new->parse( $fileContent );
    for my $node ( $t->findnodes( '//valo' ) ) {
        warn "valo is: " . $node->text;
    }
    

    ... Or for full XPath syntax, use XML::Twig::XPath instead:

    my $t = XML::Twig::XPath->new->parse( $fileContent );
    for my $node ( $t->findnodes( '//valo | //valtr' ) ) {
        warn "valo is:   " . $node->text if $node->name eq q{valo};
        warn "valtr is:  " . $node->text if $node->name eq q{valtr};
    }
    

    See the XML::Twig docs for details of the methods used here.