Есть ли * простой * способ извлечь глубоко вложенные значения с помощью XML :: Simple? - PullRequest
4 голосов
/ 12 февраля 2009

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

A
  B
    C 
      D1
      D2
      D3

В идеале я хочу сделать это на шаге ввода, если это возможно. Как это:

my @list = XMLin($xml, { SomeAttribute => 'ButWhat?' });

заканчивая тем же, что и я:

@list = ('D1', 'D2', 'D3')

Возможно ли? Или просто не так просто?

Ответы [ 5 ]

3 голосов
/ 12 февраля 2009

Предположим, ваши данные в памяти выглядят так:

my $parsed = {
    A => {
        B => {
            C => [ qw/here is your list/ ],
        },
    },
};

Тогда вы можете получить свой список с помощью my @list = @{ $parsed->{A}{B}{C} }.

Это то, что вы пытаетесь сделать?

Редактировать: принимая во внимание некоторые комментарии, возможно, вы хотите Visitor Data :: :: Callback . Затем вы можете извлечь все массивы, например:

my @arrays;
my $v = Data::Visitor::Callback->new(
    array => sub { push @arrays, $_ },
);
$v->visit( $parsed_xml );

После этого \ @arrays будет список ссылок на произвольно-глубоко вложенные массивы.

Наконец, если у вас просто есть имя атрибута и вы хотите найти сопоставляя узлы XML, вы действительно хотите XPath:

use XML::LibXML;
my $parser = XML::LibXML->new;
my $doc = $parser->parse_string( $xml_string );

# yeah, I am naming the variable data.  so there.
my @data = map { $_->textContent } $doc->findnodes('//p[@id="foo"]');

Во всяком случае, TMTOWTDI. Если вы работаете с XML, и хотите сделать что-то сложное, XML :: Simple редко является правильным ответом. я использую XML :: LibXML для всего, так как это почти всегда проще.

Еще одна вещь, вы можете захотеть Данные :: DPath . Позволяет Вы "XPath" структура данных Perl в памяти:

1 голос
/ 12 февраля 2009

Опираясь на Ответ Джона , вот основной код, который я использую, когда мне нужно сделать что-то подобное. Если мне нужно что-то более необычное, я обычно берусь за модуль, если мне позволено это делать.

Трюк в get_values начинается с ссылки на верхний уровень, получает следующий нижний уровень и помещает его в ту же переменную. Это продолжается до тех пор, пока я не достигну того, чего хочу. Большая часть кода - это просто утверждения, гарантирующие, что все работает правильно. В большинстве случаев я нахожу, что это запутанные данные, а не обход (но я делаю много работы по очистке данных). Настройте проверку ошибок в своей ситуации.

use Carp qw(croak);

my $parsed = {
  A => {
    B => {
      C => [ qw/here is your list/ ],
      D => {
        E =>  [ qw/this is a deeper list/ ],
        },
    },
  },
};

my @keys = qw( A B C D );

my @values = eval { get_values( $parsed, @keys ) } or die;

$" = " ][ ";
print "Values are [ @values ]\n";

sub get_values
    {
    my( $hash, @keys ) = @_;

    my $v = $hash; # starting reference

    foreach my $key ( @keys )
        {
        croak "Value is not a hash ref [at $key!]\n" unless ref $v eq ref {};
        croak "Key $key does not exist!\n" unless exists $v->{$key};
        $v = $v->{$key}; # replace with ref down one level
        }

    croak "Value is not an array ref!" unless ref $v eq ref [];
    @$v;
    }
0 голосов
/ 15 февраля 2009

Спасибо за все предложения.

В конце я решил проблему обхода структуры данных с помощью блока eval.

my $xml_tree;
my @list;

eval {

   # just go for it
   my @list = @{ $xml_tree->{A}->{B}->{C} };

};

if ($@) {
   say "oops - xml is not in expected format - and that happens sometimes";
}
0 голосов
/ 12 февраля 2009

Data :: Diver предоставляет удобный интерфейс для копания в глубоких структурах.

0 голосов
/ 12 февраля 2009

Тот факт, что вы используете XML :: Simple, не имеет значения; Вы пытаетесь найти в структуре ссылки и массивы. Вы знаете, что вы ищете? Всегда ли это будет в одном и том же месте? Если так, то что-то наподобие того, что написал jrockway, поможет легко. Если нет, то вам нужно пройтись по каждой части конструкции, пока не найдете то, что ищете.

Одна вещь, которую я часто делаю, это дамп структуры, которую возвращает XML :: Simple, используя Data :: Dumper , чтобы посмотреть, как это выглядит (если он всегда будет «выглядеть» одинаково; если нет , вы можете динамически определить, как пройти его, протестировав, что-то является ссылкой и что это за ссылка). Реальный вопрос: что вы ищете?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...