Question

Ok, this is a pretty rudimentary question, but I'm new to Perl and I honestly can't seem to find the answer anywhere, even though I'm sure it will be ridiculously simple.

Let's say I have the following XML schema:

<root>
    <parentNode status="Good">
        <A>
            <B>
                <value><![CDATA[This is my value]]</value>
            </B>
        </A>
    </parentNode>
</root>

Assume there are going to be multiple parentNodes with varying statuses.

I'm trying to write a script that will give me the content of each of the value nodes of the parentNodes where status isn't "Good"

Using the following code I've been able to successfully get the correct parentNodes:

my $parser = XML::LibXML->new();
my $tree = $parser->parse_file($xml_file);
my $root = $tree->getDocumentElement;
my @records = $root->findnodes("//parentNode");
foreach my $node (@records) {
    my $resultAtt = $node->getAttribute('status');
    next if $resultAtt ne "Good";

But when I try:

my $val = $node->findvalue("value");

I get nothing.

Additionally, I'm really just interested in the "This is my value" part. When you read the value, does the CDATA affect it at all?

Was it helpful?

Solution

Your XPath needs to be implicit.

Rather than using :my $val = $node->findvalue("value"); you should use: $val = $node->findvalue('./A/B/value');

You should have success :D

Copying your code (and fixing the CDATA to have the closing angle bracket) and using the above code snippet instead:

$ ./test2.pl 
Found the value: This is my value
$

OTHER TIPS

XPath

value

is short for

child::value

which means look for a node named value that is a child of the context node. If you want to search for a descendant, you want

descendant::value

which mean people write as

.//value

This is made very straightforward by crafting an appropriate XPath expression to find the value elements that you want

use strict;
use warnings;

use XML::LibXML;

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

for my $value ($xml->findnodes('/root/parentNode[@status != "Good"]//value') ) {

  print $value->textContent, "\n";
}


__DATA__
<root>
    <parentNode status="Good">
        <A>
            <B>
                <value><![CDATA[This is my value]]></value>
            </B>
        </A>
    </parentNode>
    <parentNode status="Not Good">
        <A>
            <B>
                <value><![CDATA[This is another value]]></value>
            </B>
        </A>
    </parentNode>
</root>

output

This is another value
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top