Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

XML::Twig first_child_matches question

by convenientstore (Pilgrim)
on Nov 10, 2008 at 05:18 UTC ( [id://722554]=perlquestion: print w/replies, xml ) Need Help??

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

Ok very very frustrated xml learner here(due to my lack of will power and ability).
So I decide to write a dummy XML file to give myself better understanding of what XML::Twig doc is trying to say.

I learn better by doing it visually so I was typing it away while looking up XML::Twig doc.
I am doing ok so far(I also had help from other perl monks from here already.. but still not getting it!!!!!
Anyway, below is the code which gives me fairly decent idea but my last portion is not working as I expected.. I wanted to use 'first_child_matches' to find the element and print it's value ..

I also hope my dumb example would give the other newbie some clue as well

for my $para ( $root->children('para') ) { if ( $para->first_child_matches('get_this') ) { print $para->first_child('get_this')->att('value'); } }
it should print out 'yes' but it does not.. can someone please give me a pointer? thank you
use strict; use warnings; use XML::Twig; my $xml = <<XML; <root> <para id="000">0000000000000000000000000000000000000000000<yahoo>XXXXX +XX </yahoo> <get_this value="yes" /> <get_this_two>ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ</get_this_two> </para> <para id="111">1111111111111111111111111111111111111111111</para> <para id="222">2222222222222222222222222222222222222222222</para> <para id="333">3333333333333333333333333333333333333333333</para> <para id="444">4444444444444444444444444444444444444444444</para> <para id="555">5555555555555555555555555555555555555555555</para> <para_type type="para type 3rd" active="true"> <para_cat type="category 3" /> </para_type> <para_type type="para type 2nd" active="false"> <para_cat type="category 2" /> </para_type> <para id="XXX" value="XXX_para" > XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX <para_2nd value="PPPP" /> <para_3rd> <para_3rd_name value="para type 3rd" active="true"> <para_4th value="empty" active="false"/> </para_3rd_name> </para_3rd> <para_4th value="on" eff="no">does this work</para_4th> </para> </root> XML my $tmp = XML::Twig->new(); $tmp->parse ($xml); my $root = $tmp->root; print "Here is XML file \n" . $xml . "\n"; print ">>>>>>>>>> children of when 'para' is root<<<<<<<<<<<<<\n"; print $_->trimmed_text (), "\n" for $root->children ('para'); print ">>>>>>>>>> first_child of when 'para' is root <<<<<<<<<<<<<\n"; print $_->text (), "\n" for $root->first_child ('para'); print ">>>>>>>>>> last_child of when 'para' is root <<<<<<<<<<<<<\n"; print $_->text (), "\n" for $root->last_child('para'); print ">>>>>>>>>> children of when 'para_4th' is root<<<<<<<<<<<<<<<\n +"; print $_->text (), "\n" for $root->last_child('para')->first_child('pa +ra_4th'); print ">>>>>>>>>> find att 'eff' value from para_4th <<<<<<<<<<<<<\n"; print $_, "\n" for $root->last_child('para')->first_child('para_4th' +)->att('eff'); print ">>>>>>>>>> children of when 'para' is root find value of id<<<< +<<<<<<<<<<<<<<\n"; #print $_, "\n" for $root->children('para')->att('id'); for my $para ( $root->children('para') ) { print $para->att('id') . "\n"; } for my $para ( $root->children('para') ) { if ( $para->first_child_matches('get_this') ) { print $para->first_child('get_this')->att('value'); } }
result when i run this
Here is XML file <root> <para id="000">0000000000000000000000000000000000000000000<yahoo>XXXXX +XX </yahoo> <get_this value="yes" /> <get_this_two>ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ</get_this_two> </para> <para id="111">1111111111111111111111111111111111111111111</para> <para id="222">2222222222222222222222222222222222222222222</para> <para id="333">3333333333333333333333333333333333333333333</para> <para id="444">4444444444444444444444444444444444444444444</para> <para id="555">5555555555555555555555555555555555555555555</para> <para_type type="para type 3rd" active="true"> <para_cat type="category 3" /> </para_type> <para_type type="para type 2nd" active="false"> <para_cat type="category 2" /> </para_type> <para id="XXX" value="XXX_para" > XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX <para_2nd value="PPPP" /> <para_3rd> <para_3rd_name value="para type 3rd" active="true"> <para_4th value="empty" active="false"/> </para_3rd_name> </para_3rd> <para_4th value="on" eff="no">does this work</para_4th> </para> </root> >>>>>>>>>> children of when 'para' is root<<<<<<<<<<<<< 0000000000000000000000000000000000000000000XXXXXXX ZZZZZZZZZZZZZZZZZZZ +ZZZZZZZZZZZ 1111111111111111111111111111111111111111111 2222222222222222222222222222222222222222222 3333333333333333333333333333333333333333333 4444444444444444444444444444444444444444444 5555555555555555555555555555555555555555555 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX does this work >>>>>>>>>> first_child of when 'para' is root <<<<<<<<<<<<< 0000000000000000000000000000000000000000000XXXXXXX ZZZZZZZZZZZZZZZZZZZ +ZZZZZZZZZZZ >>>>>>>>>> last_child of when 'para' is root <<<<<<<<<<<<< XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX does this work >>>>>>>>>> children of when 'para_4th' is root<<<<<<<<<<<<<<< does this work >>>>>>>>>> find att 'eff' value from para_4th <<<<<<<<<<<<< no >>>>>>>>>> children of when 'para' is root find value of id<<<<<<<<<<< +<<<<<<< 000 111 222 333 444 555 XXX

Replies are listed 'Best First'.
Re: XML::Twig first_child_matches question
by Anonymous Monk on Nov 10, 2008 at 07:14 UTC
    first_child_matches ($optional_condition) Return the element if the first child of the element (if it exists) passes the $optional_condition undef otherwise
    The first child is yahoo, not get_this. Instead use child_matches, or children, or descendants.
      hi, yes I did see that first_child_matches were wrong choice
      however, when I use child_matches, I get undesirable results
      Can't call method "att" on an undefined value at ././././xml_t line 64 +. yes [root@xmen script]#
      I think it's looping over more than necessary??
      shouldn't it enter below if statement, ONLY when it has element 'get_this'??
      for my $para ( $root->children('para') ) { if ( $para->child_matches('get_this') ) { print $para->first_child('get_this')->att('value'); } }
      **UPDATE** I tried descendent and works for me.. thank you!!!
Re: XML::Twig first_child_matches question
by mirod (Canon) on Nov 10, 2008 at 11:55 UTC

    The best way to see if there is a child that matches 'get_this' is to try to get it, there is really no need to use 2 methods, one to test if it's there and one to retrieve it. So the loop should look like this:

    for my $para ( $root->children('para') ) { if ( my $get_this= $para->first_child('get_this') ) { print $get_this->att('value'), "\n"; } }

    The docs for child_matches are a bit... short. In fact child_matches is based on child, which needs an offset as a first argument. Hence the test returned true even for the second para, at which point trying to grab the first_child failed, returning undef.

    As a side note, if you had printed a \n after the attribute value, you would have gotten the first 'yes', and then the crash. But because output is buffered, you didn't see it. So it might be a good idea to output a \n (or unbuffer output) when doing tests like this.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (5)
As of 2024-04-19 23:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found