Как я могу удалить магическое число при использовании XML :: Simple? - PullRequest
2 голосов
/ 09 октября 2010

Я выполнил следующее упражнение: как рассчитать # элементов XML, свернутых в массив с помощью XML :: Simple, чтобы мне не приходилось жестко кодировать # элементов?Я планирую использовать код для разбора большего файла XML.Я не хочу упорядочивать элементы вручную.

Могу ли я использовать счетчик для замены магических чисел, немного как person.count или hobbie.length и т. Д. Как я знаю, я могу использовать этот видоператора в C # удобно.

#!/usr/bin/perl -w
use strict;
use XML::Simple;
use Data::Dumper;

my $tree = XMLin('./t1.xml');

print Dumper($tree);
print "\n";
for (my $i = 0; $i < 2; $i++) # magic number '2'
{
    print "$tree->{person}->[$i]->{first_name} $tree->{person}->[$i]->{last_name}\n";
    print "\n";
    for (my $j = 0; $j < 3; $j++) # magic number '3'
    {
        print $tree->{person}->[$i]->{hobbie}->[$j], "\n";
    }
    print "\n";
}

Out out:

could not find ParserDetails.ini in C:/Perl/site/lib/XML/SAX
$VAR1 = {
          'person' => [
                      {
                        'hobbie' => [
                                    'bungy jumping',
                                    'sky diving',
                                    'knitting'
                                  ],
                        'last_name' => 'Bloggs',
                        'first_name' => 'Joe'
                      },
                      {
                        'hobbie' => [
                                    'Swim',
                                    'bike',
                                    'run'
                                  ],
                        'last_name' => 'LIU',
                        'first_name' => 'Jack'
                      }
                    ]
        };

Joe Bloggs

bungy jumping
sky diving
knitting

Jack LIU

Swim
bike
run

Мой исходный XML-файл, как показано ниже

<Document>
  <person>
    <first_name>Joe</first_name>
    <last_name>Bloggs</last_name>
    <hobbie>bungy jumping</hobbie>
    <hobbie>sky diving</hobbie>
    <hobbie>knitting</hobbie>
  </person>
  <person>
    <first_name>Jack</first_name>
    <last_name>LIU</last_name>
    <hobbie>Swim</hobbie>
    <hobbie>bike</hobbie>
    <hobbie>run</hobbie>
  </person>
</Document>

Ответы [ 3 ]

5 голосов
/ 09 октября 2010

Поскольку XML :: Simple создаст для вас массив, легко подсчитать его длину.

Например, $tree->{person} - это массив, или, скорее, ссылка на массив (убедитесь, что он один, используя параметр ForceArrayXML :: Simple, даже если есть только 1 человек).

  • Вы можете получить его длину, сначала отменив ссылку на него в самом массиве (используя @{} разыменование массива): @{ $tree->{person} }

  • Затем вы используете результирующий массив в скалярном контексте, который оценивает количество элементов в массиве (другими словами, a.lenth / a.count функционирует вдругие языки переводят на Perl идиома scalar(@a), где функция scalar() является необязательной, если скалярный контекст уже применяется).

    В этом случае оператор числового сравнения "<" будет принудительно запускать скалярный контекст, но если этоесли бы вы не использовали функцию scalar().

Пример:

# Don't forget ForceArray option of XML::Simple to ensure person and hobbie are array refs
for (my $i = 0; $i < scalar( @{ $tree->{person} } ); $i++) { # scalar() is optional here
    print "$tree->{person}->[$i]->{first_name} $tree->{person}->[$i]->{last_name}\n";
    print "\n";
    for (my $j = 0; $j < @{ $tree->{person}->[$i]->{hobbie} }; $j++) {
        print $tree->{person}->[$i]->{hobbie}->[$j], "\n";
    }
    print "\n";
}

Как примечание, несколько иной метод подсчета длиныМассив Perl - это $#a конструкция, котораяповорачивает индекс последнего элемента массива - например, на 1 меньше, чем количество элементов в массиве.Мне не известно о какой-либо разнице в производительности между использованием двух подходов, поэтому, если вы найдете оба одинаково читабельных, используйте их по мере необходимости (например, если вам нужно получить индекс последнего элемента, используйте $#a; если число элементов,используйте @a или scalar(@a) при необходимости).

Хорошим справочником является Perl Data Structures Cookbook @ perldoc

3 голосов
/ 09 октября 2010
for my $person (@{ $tree->{person} }) {
    print "$person->{first_name} $person->{last_name}\n\n";
    for my $hobby (@{ $person->{hobbie} }) {
      print $hobby, "\n";
    }
    print "\n";
}

и, как говорит DVK, убедитесь, что у вас есть ForceArray => [qw/Person Hobby/] в опциях XMLin, иначе ничего не получится, если у вас только один человек или у любого человека есть только одно хобби.

1 голос
/ 11 октября 2010

Вам нужно знать количество элементов в массиве только в том случае, если вы используете стиль 'C' для цикла. Вместо этого вы можете использовать более перлическую версию: foreach my $val ( @list )

#!/usr/bin/perl

use strict;
use warnings;

use XML::Simple qw(:strict XMLin);
use Data::Dumper;

my $tree = XMLin('./t1.xml', KeyAttr => { }, ForceArray => [ 'person', 'hobbie' ]);

foreach my $person ( @{ $tree->{person} } ) {
    print "$person->{first_name} $person->{last_name}\n";
    foreach my $hobbie ( @{ $person->{hobbie} } ) {
        print "$hobbie\n";
    }
}

Чтобы быть более безопасным (и, возможно, более читабельным), вы можете проверить, что <person> имеет какие-либо элементы <hobbie>, прежде чем пытаться их просмотреть:

foreach my $person ( @{ $tree->{person} } ) {
    print "$person->{first_name} $person->{last_name}\n";
    if(my $hobbies = $person->{hobbie}) {
        foreach my $hobbie ( @$hobbies ) {
            print "$hobbie\n";
        }
    }
}
...