http://www.perlmonks.org?node_id=721522

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

Hi, I am trying to learn and use XML with perl but because of difficulty that I am having with the perldoc XML::Twig and also the website of twig(despite all the tutorials, I decide to seek for help here. honestly, I just don't think I am getting it.

Anyway, I have fairly complicated XML file I want to parse out so that I can do some report on it but I am just not sure how to use XML::Twig nor if XML::Twig is even the right module to use.

I have been
1)trying to read the doc but honestly, it's little bit over my head...
2)trying to follow the tutorials on the website but it's not giving me what I want..(i am sure I am just not getting it .. same for 1) as well but
3)also did super seach on perlmonks w/ following key words ---> xml twig and read pretty much read all posts)

I have wrote a example xml file below and my question is, if I wanted to make a array of id so that my @array will contain qw/ msn movies espn/ how would I go about doing it?

I was thinking somehow using first_child method?
Would appreciate the pointer/advise.
thank you
-------- code that I was just looking at------------- #!/usr/bin/perl use warnings; use strict; use XML::Twig; my $twig = XML::Twig->new(twig_roots => { one => 1}); $twig->parsefile(shift); $twig->print; --- example file ------- <config> <one id="msn" type="shopping"> <traffic> <daily value="on" /> <weekly value="off" /> <monthly value="off" /> </traffic> </one> <one id="movies" type="entertainment"> <traffic> <daily value="on" /> <weekly value="off /> <monthly value="on" /> </traffic> </one> <one id="espn" type="sports"> <traffic> <daily value="on" /> <weekly value="on" /> <monthly value="on /> <hyper value="true /> </traffic> </one> </config>
  • Comment on trying to understand xml::twig and also trying to learn how to extract attribute
  • Download Code

Replies are listed 'Best First'.
Re: trying to understand xml::twig and also trying to learn how to extract attribute
by GrandFather (Saint) on Nov 04, 2008 at 23:27 UTC

    You're not a long way away from what you need to do. twig_roots supplies a reference to a sub to handle matching elements. Consider:

    use warnings; use strict; use XML::Twig; my $xmlStr = <<XML; <config> <one id="msn" type="shopping"> <traffic> <daily value="on" /> <weekly value="off" /> <monthly value="off" /> </traffic> </one> <one id="movies" type="entertainment"> <traffic> <daily value="on" /> <weekly value="off" /> <monthly value="on" /> </traffic> </one> <one id="espn" type="sports"> <traffic> <daily value="on" /> <weekly value="on" /> <monthly value="on" /> <hyper value="true" /> </traffic> </one> </config> XML my $result = ''; my $twig = XML::Twig->new (twig_roots => {one => sub {oneHandler (\$re +sult, @_);}}); $twig->parse ($xmlStr); print $result; sub oneHandler { my ($resRef, $twig, $elt) = @_; $$resRef = join ' ', $$resRef, $elt->att ('id'); return; }

    Prints:

    msn movies espn

    Note that there were a few missing close " in your sample XML that I've fixed.

    Also notice that I created an anonymous sub so I could pass extra parameters into the handler thus avoiding the need for global variables.


    Perl reduces RSI - it saves typing
Re: trying to understand xml::twig and also trying to learn how to extract attribute
by toolic (Bishop) on Nov 05, 2008 at 01:43 UTC
    Here is a different approach using XML::Twig. I consider this a more brute-force, less elegant solution than that provided by GrandFather. However, it illustrates the TIMTOWTDI-ness of Twig; perhaps you are more comfortable thinking of this as looping through elements, rather than the more powerful use of handlers (as I currently am). I have borrowed GrandFather's cleaned up XML text.
    use strict; use warnings; use Data::Dumper; use XML::Twig; my $xmlStr = <<XML; <config> <one id="msn" type="shopping"> <traffic> <daily value="on" /> <weekly value="off" /> <monthly value="off" /> </traffic> </one> <one id="movies" type="entertainment"> <traffic> <daily value="on" /> <weekly value="off" /> <monthly value="on" /> </traffic> </one> <one id="espn" type="sports"> <traffic> <daily value="on" /> <weekly value="on" /> <monthly value="on" /> <hyper value="true" /> </traffic> </one> </config> XML my @ids; my $t = XML::Twig->new(); $t->parse($xmlStr); for my $one ($t->root()->children('one')) { push @ids, $one->att('id'); } print Dumper(\@ids); __END__ $VAR1 = [ 'msn', 'movies', 'espn' ];

      I should have noted that the cleaned up XML is licensed under the Perl license so use it by all means. ;)


      Perl reduces RSI - it saves typing
        thank you guys
        Grandfather's solution is *bit* above my head at this point
        But eventually, I like my code to look like that(once I have better understanding)
        so I tried the second solution with bit of modification, but the way I am doing is I am sure wrong(as it's not working)
        I wanted to loop through and find monthly value eq 'on' and then push a certain elements and attribute in the array which I can loop through later for usage...
        #!/usr/bin/perl use strict; use warnings; use Data::Dumper; use XML::Twig; my $xmlStr = <<XML; <config> <one id="msn" type="shopping"> <traffic> <daily value="on" /> <weekly value="off" /> <monthly value="off" /> </traffic> </one> <one id="movies" type="entertainment"> <traffic> <daily value="on" /> <weekly value="off" /> <monthly value="on" /> </traffic> </one> <one id="espn" type="sports"> <traffic> <daily value="on" /> <weekly value="on" /> <monthly value="on" /> <hyper value="true" /> </traffic> </one> </config> XML my @ids; my $t = XML::Twig->new(); $t->parse($xmlStr); for my $one ( ($t->root()->children('one') ) { for my $month ( ($t->root()->children('monthly') ) { if ( $momth->att('value') eq 'on' ) { push @ids, $one->att('id'); } } } print Dumper(\@ids);