XML::Simple で RSS の entry を順番通りに取り出す方法
たとえばこんな感じのフィードがあったとします。
<?xml version="1.0" encoding="utf-8"?> <feed> <entry> <key>blog1</key> <title>blog1-title</title> <content>blog1-content</content> </entry> <entry> <key>blog2</key> <title>blog2-title</title> <content>blog2-content</content> </entry> <entry> <key>blog3</key> <title>blog3-title</title> <content>blog3-content</content> </entry> <entry> <key>blog4</key> <title>blog4-title</title> <content>blog4-content</content> </entry> <entry> <key>blog5</key> <title>blog5-title</title> <content>blog5-content</content> </entry> </feed>
単純に parse するとハッシュに格納されるので
entry の並び順はめちゃくちゃになります。
dump結果
$VAR1 = {
'entry' => {
'blog2' => {
'content' => 'blog2-content',
'title' => 'blog2-title'
},
'blog5' => {
'content' => 'blog5-content',
'title' => 'blog5-title'
},
'blog4' => {
'content' => 'blog4-content',
'title' => 'blog4-title'
},
'blog1' => {
'content' => 'blog1-content',
'title' => 'blog1-title'
},
'blog3' => {
'content' => 'blog3-content',
'title' => 'blog3-title'
}
}
};
ランキングの RSS とかだと entry の順番が変わるだけで致命的です。
今回がまさにその状態。
blog1〜5の順番で entry に入っていてほしかったのです。
できないかと思って調べてたらいけました。
how to preserve XML::Simple element order
どうやら Tie::IxHash を使えばいけそうとのこと。
Tie::IxHash については ハッシュのキーを挿入(追加)した順番通りに取り出す がとても
まとまっておりわかりやすいです。
#!/usr/bin/perl use strict; use warnings; use Tie::IxHash; use XML::Simple; use Data::Dumper; *XML::Simple::new_hashref = 'new_hashref'; sub new_hashref { my $self = shift; tie my %hash, 'Tie::IxHash'; %hash = @_; return \%hash; } my $parser = XML::Simple->new(); my $xml = $parser->XMLin('sample.xml'); warn Dumper $xml; 1; __END__ 結果 $VAR1 = { 'entry' => { 'blog1' => { 'content' => 'blog1-content', 'title' => 'blog1-title' }, 'blog2' => { 'content' => 'blog2-content', 'title' => 'blog2-title' }, 'blog3' => { 'content' => 'blog3-content', 'title' => 'blog3-title' }, 'blog4' => { 'content' => 'blog4-content', 'title' => 'blog4-title' }, 'blog5' => { 'content' => 'blog5-content', 'title' => 'blog5-title' } } };
このように new_hashref を Tie::IxHash で tie してやった
ハッシュリファレンスを返すように override してやれば大丈夫です。
XML::LibXML でも同じようなことはできるらしいです。