3

I am attempting to parse over the MediaWiki's API output with format=yaml. My YAML code looks something like:

use YAML qw(Dump Bless Load);
use YAML::LoadURI;
use YAML::Tag;
my $yaml_hash = LoadURI($wiki_url);
my $id = $yaml_hash->{query}->{namespaces}->[0];
print $id;

This is fine and dandy, but how do you to iterate over the YAML output without brute forcing it? This would be idea, but obviously this does not work.

my $id = $yaml_hash->{query}->{namespaces}-[*]->{id}

This is what the YAML output looks like:

---
query:
  namespaces:
    -
      id: -2
      case: first-letter
      '*': Media
      canonical: Media
    -
      id: -1
      case: first-letter
      '*': Special
      canonical: Special
    -
      id: 0
      case: first-letter
      '*':
          content:
    -
      id: 1
      case: first-letter
      '*': Talk
      subpages:
      canonical: Talk
    -
      id: 2
      case: first-letter
      '*': User
      subpages:
      canonical: User
    -
      id: 3
      case: first-letter
      '*': User talk
      subpages:
      canonical: User talk
Nemo
  • 2,441
  • 2
  • 29
  • 63
kSiR
  • 774
  • 4
  • 9

1 Answers1

4

Is this what you want? Note: I haven't tested it:

Goal: something "Like" $yaml_hash->{query}->{namespaces}-[*]->{id} -- except functional

Try this:

my @ids = map { $_->{id} } @{$yaml_hash->{query}->{namespaces}} ;

However, a for loop is probably clearer to a lot of people.

my @ids;
foreach my $ns ( @{$yaml_hash->{query}->{namespaces}} ){ push @ids, $ns->{id} }

Note I am proceeding on general perl data structure knowledge, not anything YAML specific.

It is assumed that 'query' and 'namespaces' are literals; if those are parameters then you need to brute force those with additional for-in or while loops. For iterating over hashes, look up keys() and each() in perldoc perlfunc.

Community
  • 1
  • 1
Paul
  • 26,170
  • 12
  • 85
  • 119
  • the map function worked like an champ, thanks for the fast response! – kSiR Apr 02 '11 at 22:19
  • So only to further my own self education on perl, is the map function providing the $_ to the for lack of better terms "internal loop" inside of map based of what the id value is from ->{query}->{namespaces} ? – kSiR Apr 02 '11 at 22:32
  • Yes, in fact, every for loop in perl has a $_ loop variable, though you can name your loop variable with an explicit for loop. $_ is also available in grep {block} @array; and some others. As anonymous variables go, there is also @_ that contains the list of parameters to subroutines, and a very seldom used %_ that is an anonymous hash. – Paul Apr 02 '11 at 22:34
  • awesome thanks for the explanation, I use perl for general systems administration and do not have to deal with some of the Advanced Perl Structures often. I was getting slightly lost when it came time to start talking to the arrays listed in the hash via the number bit and the YAML documentation is sometimes... hard to follow to say the least. Again thanks for your help. – kSiR Apr 02 '11 at 22:43
  • 1
    Every loop in Perl does NOT have a $_ loop variable. Only foreach loops and a special case of while loops have an implicit $_ variable. There is no implicit loop variable for the for(;;) loop. – tadmc Apr 02 '11 at 23:08
  • @tadmc Thanks, I stand corrected. for(@array){block ; } and while(){ block; }, and the array valued functions map and grep do have $_. for($i=0;$i<10;$i++){...} and while(condition){...} do not act on an @array and obviously have no handle $_ to the current item in the array. Also, as a matter of style, named variables are preferred to $_ as more readable and less bug-prone. – Paul Apr 03 '11 at 00:39
  • You don't need `my @ids ();`, doing so is like saying clear this new, already empty array. Just use `my @ids;` – Brad Gilbert Apr 03 '11 at 01:02
  • @Brad Thanks. It is a matter of style and depends on who else reads your code. – Paul Apr 03 '11 at 01:40