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

Hi Monks, I'm trying to print all of the matching XML node info if the value (6444) for one of the attributes is found. I've tried using XML Simple, Twig and even attempted to write my own, all without any success. The furthest I've managed to get is the following. XML file;

<root> <ProductKey>99</ProductKey> <Test size = "50"> <Job tags = "boo baa"> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063 +</Volume> <Volume VolumeCategory="cuft" MeasurementCategory="Real">2. +2</Volume> <Volume VolumeCategory="6444" MeasurementCategory="Deal">2. +2</Volume> </Job> </Test> <Test size = "100"> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063</V +olume> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063</V +olume> <Volume VolumeCategory="6444" MeasurementCategory="Real">2.2</ +Volume> </Test> <Test> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063</V +olume> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063</V +olume> <Volume VolumeCategory="5555" MeasurementCategory="Real">2.2</ +Volume> </Test> </root>

SCRIPT;

use strict; use XML::LibXML; my $parser = XML::LibXML->new; my $doc = $parser->parse_file("minimal.xml"); my @vol = $doc->findnodes(q {/descendant::Volume[@VolumeCategory="6444 +"]}); foreach my $element (@vol) { print $element->parentNode->nodeName; print $element->parentNode(), $element->nodeValue(), "\n"; }

OUTPUT;

Job<Job tags="boo baa"> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063 +</Volume> <Volume VolumeCategory="cuft" MeasurementCategory="Real">2. +2</Volume> <Volume VolumeCategory="6444" MeasurementCategory="Deal">2. +2</Volume> </Job> Test<Test size="100"> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063</V +olume> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063</V +olume> <Volume VolumeCategory="6444" MeasurementCategory="Real">2.2</ +Volume> </Test>

DESIRED OUTPUT;

<Test size = "50"> Job<Job tags="boo baa"> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063 +</Volume> <Volume VolumeCategory="cuft" MeasurementCategory="Real">2. +2</Volume> <Volume VolumeCategory="6444" MeasurementCategory="Deal">2. +2</Volume> </Job> </Test> Test<Test size="100"> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063</V +olume> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063</V +olume> <Volume VolumeCategory="6444" MeasurementCategory="Real">2.2</ +Volume> </Test>

Where, for the first match I also print the parent of <job> which is <test>. Any ideas? Your help is greatly appreciated!!! Thanks, MM

Replies are listed 'Best First'.
Re: LibXML findnode and parents
by tangent (Parson) on Jul 05, 2015 at 16:49 UTC
    If your XML is always of the format in the example this should work:
    my @vol = $doc->findnodes('//Volume[@VolumeCategory="6444"]'); for my $element (@vol) { my $parent = $element->parentNode; if ( $parent->nodeName eq 'Job' ) { $parent = $parent->parentNode; } print $parent, "\n"; print $element->textContent(), "\n"; }
    If the format varies then you need to show that.

    Note that you need to use ->textContent and not ->nodeValue to get the text value of the element.

    Output:

    <Test size="50"> <Job tags="boo baa"> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063</V +olume> <Volume VolumeCategory="cuft" MeasurementCategory="Real">2.2</ +Volume> <Volume VolumeCategory="6444" MeasurementCategory="Deal">2.2</ +Volume> </Job> </Test> 2.2 <Test size="100"> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063</Volum +e> <Volume VolumeCategory="L" MeasurementCategory="Real">0.063</Volum +e> <Volume VolumeCategory="6444" MeasurementCategory="Real">2.2</Volu +me> </Test> 2.2