2015-12-08 5 views
1

У меня есть простой XML, который я хочу прочитать на Perl и сделать хэш, содержащий все ключи для чтения.Доступ к возвращенным значениям в виде массива

Рассмотрим этот код:

my $content = $xml->XMLin("filesmap.xml")->{Item}; 
my %files = map { $_->{Path} => 1 } @$content; 

Этот фрагмент отлично работает, когда XML-файл содержит много Item тегов. Тогда $content является ссылкой на массив. Но когда есть только один Item, я получаю сообщение об ошибке при разыменовании как массив. Мое предположение состоит в том, что $content является ссылкой на скаляр, а не на массив.

Какова практика, чтобы убедиться, что я получаю массив значений, считанных из XML?

+2

Во-первых: [Не используйте XML :: Simple] (/http://stackoverflow.com/questions/33267765/why-is-xmlsimple-discouraged), и тогда все будет хорошо и легко. Дайте нам образец XML, и мы сможем дать вам точный ответ. – Sobrique

+0

Появившиеся сообщения уже отвечают на мой вопрос. В общем, существует практика использования 'ref $ content eq 'ARRAY'', где мне нужно убедиться, что я получаю массивы, что, кстати, уродливо, но в моем случае XML я могу использовать параметр ForceArray или использовать другой xml lib. Благодаря! –

ответ

8

Что вам нужно, чтобы не использовать XML::Simple, а затем это действительно тривиально. Мой любимый для достаточно простых образцов XML является XML::Twig

use XML::Twig; 
my $twig = XML::Twig -> new -> parsefile ('filesmap.xml'); 

my @files = map { $_ -> trimmed_text } $twig -> get_xpath ('//Path'); 

С более подробной выборкой XML (и желаемым результатом) я буду в состоянии дать вам лучший ответ.

Часть проблемы с XML::Simple он пытается превратить структуру данных XML в PERL структур данных, и - так как хэши ключевые ценности и неупорядоченный но массивы упорядочиваются, он должен угадать. И иногда он делает это неправильно, а иногда это непоследовательно.

Если вы хотите, чтобы быть последовательными, вы можете установить:

my $xml = XMLin("filesmap.xml", ForceArray => 1, KeyAttr => [], ForceContent => 1); 

Но на самом деле - XML::Simple это просто путь к боли. Не используйте его. Если вам не нравится XML::Twig, попробуйте XML::LibXML.

1

Что бы я сказал, вам нужен flatten-шаг.

my %files 
    = map { $_->{Path} => 1 } 
     # flatten... 
     map { ref() eq 'ARRAY' ? @$_ : $_ } 
     $xml->XMLin("filesmap.xml")->{Item} 
    ; 
1

Вы можете сделать чек и заставить возвращение в ссылку на массив, если это необходимо:

my $content = $xml->XMLin("filesmap.xml")->{Item}; 

$content = ref $content eq 'ARRAY' 
    ? $content 
    : [$content]; 
+2

лично, я бы отменил логику: 'ref $ content eq 'ARRAY'? $ content: [$ content] ' – Alnitak

+1

Или знайте, включите' ForceArray' (или просто не используйте XML :: Simple в первую очередь). – Sobrique

Смежные вопросы