2013-06-27 32 views
2

我需要使用Perl腳本來獲取XML文件中給定名稱的節點的子節點數據值。 我正在使用XML::LibXML::Simple如何在Perl中使用XML文件?

一個代碼片段如下:

my $booklist = XMLin(path); 

    foreach my $book (@{$booklist->{detail}}) { 
    print $book->{name} . "\n"; 
} 

和XML文件如下所示:

<?xml version='1.0' encoding='iso-8859-1'?> 
<booklist> 
<book> 
<detail label='label1' status='active' type='none'> 
<name>book1</name> 
</detail > 
<detail label='label2' status='active' type='none'> 
<name>book2</name> 
</detail > 
</book> 
</booklist> 

當我使用上面的代碼中,我得到了以下錯誤消息: 「不是一個ARRAY參考「

任何人都可以請幫助我嗎?

+0

你喜歡嗎? book1,book2,文字 – user1811486

+0

你能解釋一下你輸出哪些東西嗎? – user1811486

+0

是的,我想要book1和book2文本作爲輸出 – user2526936

回答

2

下面是在OP中使用的XML :: Simple解決方案。

use strict; 
use warnings; 
use XML::Simple; 

my $booklist = XMLin($ARGV[0], KeyAttr => [], ForceArray => qr/detail/); 

foreach my $book (@{$booklist->{book}->{detail}}) { 
    print $book->{name} . "\n"; 
} 

這裏重要的是片給予XMLin的選項,迫使「細節」子節點被表示爲陣列。

一個快速入門的XML ::簡單是CPAN文件: http://metacpan.org/pod/XML::Simple

+0

幹得好。但將任何人鏈接到XML :: Simple文檔是一個錯誤 - 他們是可悲的。 – 7stud

+0

謝謝@mahnkong :) – user2526936

1

當你寫:

@{ $booklist->{detail} } 

...你是說$書目 - > {}詳細返回數組引用,你想要Perl取消對它的引用到一個數組,即「@」 。

請勿使用<name>作爲標籤。 XML :: Simple很奇怪地解析。這裏有一個例子:

1)

<?xml version='1.0' encoding='iso-8859-1'?> 
<booklist> 
    <book> 
     <bname>book1</bname> 
    </book> 
    <book> 
     <bname>book2</bname> 
    </book> 
</booklist> 

use strict; 
use warnings; 
use 5.016; 

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



my $booklist = XMLin('xml.xml'); 
print Dumper($booklist); 


--output:-- 

$VAR1 = { 
      'book' => [ 
        { 
         'bname' => 'book1' 
        }, 
        { 
         'bname' => 'book2' 
        } 
        ] 
     }; 

2)現在看看會發生什麼,當你使用一個<name>標籤:

<?xml version='1.0' encoding='iso-8859-1'?> 
<booklist> 
    <book> 
     <name>book1</bname> 
    </book> 
    <book> 
     <name>book2</bname> 
    </book> 
</booklist> 

--output:-- 
$VAR1 = { 
      'book' => { 
        'book2' => {}, 
        'book1' => {} 
        } 
     }; 
與你原來的例子

所以:

<?xml version='1.0' encoding='iso-8859-1'?> 
<booklist> 
    <book> 

    <detail label='label1' status='active' type='none'> 
     <bname>book1</bname> 
    </detail> 

    <detail label='label2' status='active' type='none'> 
     <bname>book2</bname> 
    </detail> 

    </book> 
</booklist> 


--output:-- 
$VAR1 = { 
      'book' => { 
        'detail' => [ 
           { 
            'bname' => 'book1', 
            'status' => 'active', 
            'label' => 'label1', 
            'type' => 'none' 
           }, 
           { 
            'bname' => 'book2', 
            'status' => 'active', 
            'label' => 'label2', 
            'type' => 'none' 
           } 
           ] 
        } 
     }; 

爲了得到所有的bname標籤,你可以這樣做:

use strict; 
use warnings; 
use 5.016; 

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

my $booklist = XMLin('xml.xml'); 
my $aref = $booklist->{book}{detail}; 

for my $href (@$aref) { 
    say $href->{bname}; 
} 


--output:-- 
book1 
book2 
+0

對不起,我錯誤地更新了我的代碼。你可以請現在檢查嗎? – user2526936

+0

$ booklist - > {detail}返回多個值,我將把它存儲到數組中,並且正在打印。但我不知道這個,如果你有其他的想法請分享我 – user2526936

+0

有沒有其他的方式來獲取名稱值? – user2526936

1

我覺得像這樣的....

use strict; 
use XML::Twig; 

my $text = join '', <DATA>; 
my $story_file = XML::Twig->new(
       twig_handlers =>{ 
       'name' => \&name, 
       keep_atts_order => 1, 
}, 
       pretty_print => 'indented', 
); 
$story_file->parse($text); 

sub name { 
     my ($stroy_file, $name) = @_; 
    print $name->text, "\n"; 
} 

__END__ 
<?xml version='1.0' encoding='iso-8859-1'?> 
<booklist> 
<book> 
<detail label='label1' status='active' type='none'> 
<name>book1</name> 
</detail > 
<detail label='label2' status='active' type='none'> 
<name>book2</name> 
</detail > 
</book> 
</booklist> 
+0

我試過你的代碼,當我試圖用ppm命令安裝XML :: Twig包時,我得到了下面的錯誤信息 「正在下載XML-Twig-3.32 ...重定向 正在下載XML-Twig-3.32 ...失敗401需要授權 ppm安裝失敗:401需要授權「 – user2526936

+0

爲什麼'keep_atts_order'?這裏不需要。 – mirod

+0

XML :: Twig似乎只適用於許多perl版本的付費用戶,請參閱http://code.activestate.com/ppm/XML-Twig/。使用PPM :: Repositories(https://metacpan.org/module/JDB/PPM-Repositories-0.19/Repositories.pm)中列出的存儲庫,我可以在http://www.bribes.org/perl/ppm/中看到它。我不熟悉Activestate Perl,但你應該可以添加一個新的存儲庫,以便你可以獲得XML :: Twig。 – mirod

1

XML::Simple docs

使用本模塊中新代碼是不鼓勵。其他模塊可提供更直接和一致的接口。尤其強烈建議使用XML :: LibXML。

該模塊的主要問題是大量的選項以及這些選項交互的任意方式 - 通常會帶來意想不到的結果。

無論如何。

在您的代碼中,您正在瀏覽書單中包含包含詳細信息的書籍的事實。該書目沒有直接的細節。下面是使用XML::LibXML短的解決方案:

use strict; use warnings; use 5.010; use XML::LibXML; 

my $dom = XML::LibXML->load_xml(IO => \*DATA) or die "Can't load"; 

for my $detail ($dom->findnodes('/booklist/book/detail')) { 
    say $detail->findvalue('./name'); 
} 

__DATA__ 
<?xml version='1.0' encoding='iso-8859-1'?> 
<booklist> 
    <book> 
    <detail label='label1' status='active' type='none'> 
     <name>book1</name> 
    </detail > 
    <detail label='label2' status='active' type='none'> 
     <name>book2</name> 
    </detail > 
    </book> 
</booklist> 

正如你可以在XPath表達式/booklist/book/detail看到的,我們首先要看看書發現的細節之前。當然,這可以縮短到//detail

一般來說,如果一個數據結構不像它看起來那樣,那麼應該轉儲它,例如,

use Data::Dumper; 
print Dumper $booklist; 

這將輸出:

$VAR1 = { 
    'book' => { 
    'detail' => { 
     'book2' => { 
     'status' => 'active', 
     'type' => 'none', 
     'label' => 'label2' 
     }, 
     'book1' => { 
     'status' => 'active', 
     'type' => 'none', 
     'label' => 'label1' 
     } 
    } 
    } 
}; 

所以對一些性交的原因,book1book2字符串現在是在一個嵌套的哈希。幫你一個忙,並停止使用CPAN上最複雜的XML模塊,即「XML :: Simple」。

+0

我更新了上面的代碼並運行腳本,那次我通過包「XML :: LibXML」得到了錯誤消息「無法找到對象方法」load_xml「(也許你爲 加載了」XML :: LibXML「 ?)」 然後我用的PPM命令來安裝包 PPM安裝XML ::的libxml 現在我得到了以下錯誤消息 PPM安裝失敗:無法找到提供XML任何包::的libxml – user2526936

+0

你知道爲什麼會出現這個錯誤嗎? – user2526936

+0

PPM倉庫中有一個[XML :: LibXML包](http://code.activestate.com/ppm/XML-LibXML/)。因此,它應該工作。你確定你已經複製了整個代碼片段,包括。 '使用XML :: LibXML'?它運行在XML :: LibXML v2.0018,perl5 v16.3(儘管我不使用活動perl) – amon

0

然而使用XML::Rules(假設的一點是要得到的東西在「細節」,而不是僅僅打印「名稱的內容另一種方式'):

use XML::Rules; 
my @rules = (
    detail => sub { 
    print "$_[1]{name}\n"; 
    return; 
    }, 
    name => 'content', 
    _default => undef, 
); 

my $xr = XML::Rules->new(rules => \@rules); 
$xr->parsefile("tmp.xml"); 
相關問題