2011-07-20 13 views
1

私は単純な質問について研究しましたが、できませんでした。私はXMLでWebからデータを取得しようとしており、それをperlを使って解析しています。今、繰り返し要素をループする方法を知っています。しかし、私はそれが繰り返されていないとき(私はこれが愚かかもしれないことを知っています)止まっています。要素が繰り返している場合は、配列に入れてデータを取得します。しかし、要素が1つしかない場合、「配列参照ではない」というエラーがスローされ、エラーが発生します。私は両方の時間(単一の要素と複数の要素)で解析できるように自分のコードが欲しいです。私が使用していたコードは次のとおりです。また、私は、セパレータは$$最後の要素の後に印刷を取得しないような何かを行うことができますperlを使用したXML解析

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"; 
} 

をしかし、これはすべてのchildNodesを印刷し、私はちょうどコンテンツノードをしたいです。

答えて

5

PerlのXML::Simpleは、1つのアイテムをスカラーとして返します。値が繰り返されると、配列リファレンスとして返されます。だから、あなたのコードを動作させるために、あなただけ常に配列参照を返すようにMeshHeadingを強制する必要があります。

$data = $xml->XMLin("$dataxml", ForceArray => [qw(MeshHeading)]); 
1

$data->{PubmedArticle}-> ... ->{MeshHeading}は、文書内にいくつの<MeshHeading>タグが存在するかに応じて文字列または配列参照のいずれかになる可能性があるため、値の型をrefで調べ、それを条件付きで逆参照する必要があります。そのようにそれを使用し、その後

 
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})) { ... } 

をした後に印刷されてから' $$ 'を防ぐために、私はこれを行うための任意の簡潔なPerlのイディオムを知らないだので、あなたの最善の策は、関数を記述することです代わりに、リストをループの最後の要素、joinと一緒にすべての要素を連結します。

 
print FH join ' $$ ', map { $_->{DescriptionName}{content} } 
toArray($data->{PubmedArticle}->{MedlineCitation}->{MeshHeadingList}->{MeshHeading}); 
2

を、私はあなたがの一部逃したと思う「はperldoc XMLを::シンプル」それはForceArrayオプションについて語る:

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

その後、あなたは常に配列が一つだけの要素が含まれている場合でも、配列を取得します。

1

これは、XML :: Simpleはが...シンプルされている場所です。配列があるかどうかは、何かが何度も出現するかどうかによって推論されます。 docを読み、これに対処するForceArrayオプションを探します。

だけの要素間の' $$ 'が含まれるように他の人が指摘したように、

print FH join ' $$ ', map $_->{DescriptorName}{content}, @{$data->{PubmedArticle}->{MedlineCitation}->{MeshHeadingList}->{MeshHeading}}; 
2

であなたのループを置き換える、ForceArrayオプションは、この特定の問題を解決します。しかし、XML :: Simpleの仮定があなたのものと一致しないため、間もなく間違いなく別の問題が発生するでしょう。 XML :: Simpleの著者として、Stepping up from XML::Simple to XML::LibXMLを読むことを強くお勧めします。他に何も教えないなら、XML :: Simpleについてもっと学びます。