XML::Simple で RSS の entry を順番通りに取り出す方法

By | 2009年9月6日

たとえばこんな感じのフィードがあったとします。

<?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 でも同じようなことはできるらしいです。

モジュールに定義されている関数名一覧を取得

By | 2009年6月7日

よく忘れるのでメモ。
シンボルテーブルの一覧を取得するには以下の方法で取得できます。
ポイントはモジュール名の後に :: をつけること。
これよく忘れます。

%モジュール::;

で、これだと変数なのか関数なのかが判断できません。
そこで便利なのが Devel::Symdump です。

 @array = Devel::Symdump->functions(@packs);

これだけで関数一覧が取得できます。
関数だけでなく hash や scalar が取得できたり
diff とれたり HTML で出力できたり地味に便利です。

ports で入れた perl で Mac::Growl が使えるようになるまで

By | 2009年5月25日

Test::Continuous に興味がわいたので
さわってみようとしたらMac::Growl が必要とのこと。
いれようとしたら Foundation.pm 等がないためちゃんと test に通らなかった。

どうやら ports でいれたのには Foundation の ラッパーモジュール がないらしい。
variants で調べて +darwin を足していれなおしたけどなかった。
というわけでいいのかわからないけど、デフォルトに入ってるのにシンボリックリンクを貼って
その場をしのいだ。

以下、説明。
mac 独自に bundle されたモジュール類(Foundation.pmとか)は
/System/Library/Perl/Extras/5.8.8/darwin-thread-multi-2level 以下にあります。
Foundation.pm が PerlObjCBridge.pm と CoreFoundation.pm にも依存していたので忘れなく貼ること。

自分の環境だと以下のパスに貼った。

sudo ln -s /System/Library/Perl/Extras/5.8.8/darwin-thread-multi-2level/Foundation.pm /opt/local/lib/perl5/5.10.0/darwin-2level/Foundation.pm
sudo ln -s /System/Library/Perl/Extras/5.8.8/darwin-thread-multi-2level/CoreFoundation.pm /opt/local/lib/perl5/5.10.0/darwin-2level/CoreFoundation.pm
sudo ln -s /System/Library/Perl/Extras/5.8.8/darwin-thread-multi-2level/PerlObjCBridge.pm  /opt/local/lib/perl5/5.10.0/darwin-2level/PerlObjCBridge.pm

perl のバージョンが 5.10 だけど 5.8.8 からのシンボリックリンクでも現状、一応動いてる。

ただ、Mac::Growl が utf8 で文字を渡しても文字化けする始末。
というわけで Net::Growl や GNTP::Growl も試してみたが
残園なことにNet::Growl は何もおこらない。
GNTP::Grwol は IO::Socket::INET でコネクションできない感じ。

IO::Socket::INET: connect: Connection refused at /opt/local/lib/perl5/site_perl/5.10.0/GNTP/Growl.pm line 44,  line 1.

うむぅ〜困った。

追記 2009/08/29 20:17:22

snow leopard にしたら Mac::Growl が使えなくなった。
どうやら Carbon 系が 32bit でしか使えないみたい。
64bit で起動させると使えない。
ソース

Mac(Leopard) に DBD::SQLite をいれる時には注意

By | 2009年3月22日

DBIx::Class をいれようとした時に少しハマったのでメモ。
どうやら CPAN コマンドを使ってインストールしようとすると
Mac にバンドルされている sqlite を使ってないらしい。。。
そのためインストールに失敗する。
これを回避しようと思うと Makefile.PL に USE_LOCAL_SQLITE=true に指定すればよいらしい。

1
2
3
$sudo cpan
cpan[1]> o conf makepl_arg USE_LOCAL_SQLITE=true
cpan[2]> install DBD::SQLite

o conf commit をしない限りここで変更しても cpan を再起動すると元の設定を使うことになる。

参考資料

DBD-SQLite-1.14
cpan コマンドでモジュールをインストールするときに Makefile.PL の引数を設定するCommentsAdd Star

actionscirpt3 で変数に格納された値を使って動的にインスタンスを生成

By | 2008年9月29日

以前からできないのかなと思っていて、
ちょっと調べたらできそうだったので調べてみた。

試した環境は Flex3 SDK です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package {
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.utils.getDefinitionByName;
 
    public class Hoge extends Sprite {
        public function Hoge() {
       var cls:Class = getDefinitionByName("flash.text.TextField") as Class;
            var t:TextField = new cls();
            t.text = "hoge";
            t.y = 100;
            addChild(t);
 
            var t2:TextField = new TextField();
            t2.text = "fuga";
            addChild(t2);
        }
    }
}

特に重要なのが8-9行目ですね。
これで動的にインスタンスを生成することができるみたいです。

getDefinitionByName便利ですね。
でもよく考えればできそうな気もせんでもないような。。。。
ま、できてなによりです。

参考資料
http://blog.isocchi.com/2007/12/flex-actionscript.html
http://www.fxug.net/modules/xhnewbb/viewtopic.php?topic_id=1241

——————————————————————————————–
追記: 2008/9/30 22:52

パフォーマンスがちょっと気になったのでベンチをとってみた。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package {
 
    import flash.display.Sprite;
    import flash.utils.getTimer;
    import flash.utils.getDefinitionByName;
    import org.libspark.utils.Dumper;
 
    public class Generate extends Sprite{
 
        private static const ROUND:uint = 50000;
 
        public function Generate(){
            bench(generate_new, "new");
            bench(generate_class, "[new - class]");
        }
 
 
        private function generate_new():void{
            for (var i:int = 0; i < ROUND; i++){ new Sprite(); }
        }
 
        private function generate_class():void{
            for (var i:int = 0; i < ROUND; i++){
                var cls:Class = getDefinitionByName("flash.display.Sprite") as Class;
                new cls();
            }
        }
 
        private function bench(func:Function, tag:String):void{
            var start:uint = getTimer();
            func();
            trace((getTimer() - start) + "ms :" + tag);
        }
    }
}
[64bitの結果]
330ms :new
659ms :[new - class]
355ms :new
658ms :[new - class]
 
[32bitの結果]
1285ms :new
1172ms :[new - class]
1285ms :new
1211ms :[new - class]

会社でも試した結果、おそらく32bitだと[new – class]の方がはやかった。
なぜだーーーーーと思って、家の64bit環境で試したら上記のような結果。
まぁ。。。納得?

できねーしw