Синтаксический анализ XML с использованием Perl - PullRequest
1 голос
/ 21 июля 2011

Я пытался исследовать простой вопрос, который у меня был, но не мог этого сделать.Я пытаюсь получить данные из сети в формате XML и проанализировать их с помощью Perl.Теперь я знаю, как зацикливаться на повторяющихся элементах.Но я застреваю, когда это не повторяется (я знаю, что это может быть глупо).Если элементы повторяются, я помещаю их в массив и получаю данные.Но когда есть только один элемент, он выдает сообщение об ошибке «Не ссылка на массив».Я хочу, чтобы мой код был таким, чтобы он мог анализироваться одновременно (для одного и нескольких элементов).Код, который я использую, выглядит следующим образом:

use LWP::Simple;
use XML::Simple;
use Data::Dumper;

open (FH, ">:utf8","xmlparsed1.txt");

my $db1 = "pubmed";
my $query  = "13054692";
my $q = 16354118;          #for multiple MeSH terms
my $xml = new XML::Simple;

$urlxml = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=$db1&id=$query&retmode=xml&rettype=abstract";
$dataxml = get($urlxml);
$data = $xml->XMLin("$dataxml");
#print FH Dumper($data);
foreach $e(@{$data->{PubmedArticle}->{MedlineCitation}->{MeshHeadingList}->{MeshHeading}})
     {
       print FH $e->{DescriptorName}{content}, ' $$ ';
     } 

Кроме того, можно ли сделать что-то такое, чтобы разделитель $$ не печатался после последнего элемента?Я также попробовал следующий код:

$mesh = $data->{PubmedArticle}->{MedlineCitation}->{MeshHeadingList}->{MeshHeading};
while (my ($key, $value) = each(%$mesh)){
    print FH "$value";
}

Но это печатает все дочерние узлы, и я просто хочу узел содержимого.

Ответы [ 5 ]

5 голосов
/ 21 июля 2011

Perl's XML::Simple возьмет один элемент и вернет его в качестве скаляра, а если значение повторится, отправит его обратно в качестве ссылки на массив. Итак, чтобы заставить ваш код работать, вам просто нужно заставить MeshHeading всегда возвращать ссылку на массив:

$data = $xml->XMLin("$dataxml", ForceArray => [qw( MeshHeading )]);
2 голосов
/ 21 июля 2011

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

2 голосов
/ 21 июля 2011

Я думаю, что вы пропустили часть "perldoc XML :: Simple", которая говорит о параметре ForceArray:

check out ForceArray because you'll almost certainly want to turn it on

Тогда вы всегда получите массив, даже если массив содержит только один элемент.

1 голос
/ 21 июля 2011

Это место, где XML :: Simple ... просто. Он определяет, существует ли массив или нет, по тому, что что-то происходит более одного раза. Прочтите doc и найдите опцию ForceArray для решения этой проблемы.

Чтобы включить ' $$ ' только между элементами, замените цикл на

print FH join ' $$ ', map $_->{DescriptorName}{content}, @{$data->{PubmedArticle}->{MedlineCitation}->{MeshHeadingList}->{MeshHeading}};
1 голос
/ 21 июля 2011

Поскольку $data->{PubmedArticle}-> ... ->{MeshHeading} может быть либо строкой, либо ссылкой на массив в зависимости от того, сколько тегов <MeshHeading> присутствует в документе, вам необходимо проверить тип значения с помощью ref и условно разыменовать его.Поскольку я не знаю о каких-либо кратких идиомах Perl для этого, лучше всего написать функцию:

sub toArray {
 my $meshes = shift;
 if (!defined $meshes) { return () }
 elsif (ref $meshes eq 'ARRAY') { return @$meshes }
 else { return ($meshes) }
}

, а затем использовать ее следующим образом:

foreach my $e (toArray($data->{PubmedArticle}->{MedlineCitation}->{MeshHeadingList}->{MeshHeading})) { ... }

Чтобы предотвратить ' $$ ' после печати после последнего элемента, вместо циклического перемещения по списку, объедините все элементы вместе с join:

print FH join ' $$ ', map { $_->{DescriptionName}{content} }
 toArray($data->{PubmedArticle}->{MedlineCitation}->{MeshHeadingList}->{MeshHeading});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...