Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

XML Node Values Based On Attributes

by gpjahn (Novice)
on Sep 29, 2022 at 18:24 UTC ( [id://11147151]=perlquestion: print w/replies, xml ) Need Help??

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

Hello,

I've been playing with, and trying to learn, XML::LibXML. I've been trying to get the values from specific nodes based on one of its attributes. I can get and print "all" the node values, and I can get and print just the specific attribute values, but I can't seem to figure out how to print the node values of nodes with specific attributes.

Here is the xml I'm using. I'd like to grab the values from the <Data> nodes, but only the ones with the "name" attribute that equals "NAME_2".

<xml> <Document> <Name>Places To Visit</Name> <Folder> <Place> <Name>Location 1</Name> <ExtendedName> <Data name="NAME_0">United States</Data> <Data name="NAME_1">Utah</Data> <Data name="NAME_2">Salt Lake City</Data> </ExtendedName> </Place> <Place> <Name>Location 2</Name> <ExtendedName> <Data name="NAME_0">United States</Data> <Data name="NAME_1">Rhode Island</Data> <Data name="NAME_2">Providence</Data> </ExtendedName> </Place> <Place> <Name>Location 3</Name> <ExtendedName> <Data name="NAME_0">United States</Data> <Data name="NAME_1">Wisconsin</Data> <Data name="NAME_2">Green Bay</Data> </ExtendedName> </Place> <Place> <Name>Location 4</Name> <ExtendedName> <Data name="NAME_0">United States</Data> <Data name="NAME_1">Wyoming</Data> <Data name="NAME_2">Casper</Data> </ExtendedName> </Place> </Folder> </Document> </xml>

Here is the small bit of code that I'm using to pull out the contents of the attributes, but I don't know how to get the node values. I hope that makes sense.

Thank you for your help!

#!/usr/bin/perl use strict; use warnings; use XML::LibXML; my $xml = XML::LibXML->load_xml(location => 'locations.xml'); foreach my $node2 ($xml->findnodes('//Place')) { my $attr; foreach( $node2->findnodes('./ExtendedName/Data/@name') ) { $attr = $_->textContent(); if($attr eq "NAME_2" ) { print $_->textContent() . "\n"; } } }

Replies are listed 'Best First'.
Re: XML Node Values Based On Attributes
by choroba (Cardinal) on Sep 29, 2022 at 19:22 UTC
    It's much shorter and also faster to do most of the work in XPath.
    #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; use XML::LibXML; my $xml = 'XML::LibXML'->load_xml(location => 'file.xml'); for my $place ($xml->findnodes('/xml/Document/Folder/Place')) { print $place->findvalue('Name'), "\t"; my $name2 = $place->findvalue('ExtendedName/Data[@name="NAME_2"]') +; say $name2; }

    If you want to learn XPath, I humbly recommend you XML::XSH2, a module I happen to maintain. It's a wrapper around XML::LibXML which features an interactive shell where you can play with the data and XPath. The above code can be tried like this:

    $scratch/> open file.xml parsing file.xml done. /> for /xml/Document/Folder/Place echo (Name) ExtendedName/Data[@name= +"NAME_2"] Location 1 Salt Lake City Location 2 Providence Location 3 Green Bay Location 4 Casper
    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      Thank you! I've not looked at XPath directly. I'll have to do that.
Re: XML Node Values Based On Attributes
by hippo (Bishop) on Sep 29, 2022 at 22:13 UTC

    There are so many different ways to approach this given the size of the toolkit that is libxml2. Here is one native approach.

    #!/usr/bin/env perl use strict; use warnings; use XML::LibXML; my $xml = XML::LibXML->load_xml(location => 'locations.xml'); my $nl = $xml->getElementsByLocalName ('Data'); my @text; for my $node ($nl->get_nodelist) { push @text, $node->textContent if 'NAME_2' eq $node->getAttribute +('name'); } print "$_\n" for @text;

    I've structured it this way because to me it is pretty easy to follow and clear what is going on. YMMV.


    🦛

      Thank you! Nice and simple, I like it.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11147151]
Approved by choroba
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (4)
As of 2024-04-23 15:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found