Hatena::ブログ(Diary)

あまやん胸いっぱい このページをアンテナに追加 RSSフィード

2007-11-16

[][][] XML::LibXMLで(とりあえず)XMLパースする

これまでXML::TreePPにべったりだった私。最近はXMLの要素指定にXPathを使うのが主流?らしいので、その練習がてら使ってみることにしました。

インストール

検索するとみんな苦労しているインストール。まずはいろんなライブラリを入れないといけない。

僕の環境(Fedora 7 + Perl5.8.8)ではこんな感じでインストール

$ su -

# yum -y install libxml

# yum -y install libxml-devel

# yum -y install libxml2

# yum -y install libxml2-devel

# yum -y install libxml++

# yum -y install libxml++-devel

# cpan -fi XML::LibXML

なんつーかもう、片っ端から放り込んだ感じですが・・・



サンプルファイル

今回は /home/amaya/ramens.xml という場所に置いてみます。/span>

<Ramens>
    <Ramen>
        <Shop name="Perl軒" />
        <Menus>
            <Menu>野菜ラーメン</Menu>
            <Menu>全部入りラーメン</Menu>
        </Menus>
        <Comment>会社帰りに良く寄るお店</Comment>
    </Ramen>
    <Ramen>
        <Shop name="麺屋CPAN" />
        <Menus>
            <Menu>カレーラーメン</Menu>
            <Menu>餃子</Menu>
        </Menus>
        <Comment>床がベタベタしてる</Comment>
    </Ramen>
</Ramens>

こんな感じで作ったファイルを解析して、整形表示するサンプルスクリプトを作ってみます。

(自分にとって)わかりやすくするために「ノード」という表現は使わず「タグのリスト」と表現します。


XPathの記述

難しいことは良く分からないので、取り急ぎ解析に必要な情報だけ。


  • 基本的にはUNIXのパスと同じ文法。
    • 階層を「/」で表す。現在の階層を示すには「.」で、ひとつ上の階層を示すには「..」。
  • 要素( <test name="****">の「name」の部分)は「@」で表す

サンプルスクリプト

  • ramen_list.pl
#!/usr/bin/perl

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

my $parser  = XML::LibXML->new();
my $dom     = $parser->parse_file("/home/amaya/ramens.xml");

# ルートノード(<Ramens>)の下にある<Ramen>ノードを取得
my @ramens = $dom->findnodes('//Ramen');

# <Ramen>ノードを展開
foreach my $ramen (@ramens) {

    # <Ramen><Shop name="*">の値を取得
    my $shop_name = $ramen->findvalue('Shop/@name');

    print <<"HEADER";
----------------------------------
Shop: $shop_name
----------------------------------
HEADER

    # <Ramen><Comment>の値を取得
    printf("[Comment] %s\n", $ramen->findvalue('Comment'));

    # <Ramen>の下にある<Menus><Menu>ノードを取得
    my @menus = $ramen->findnodes('Menus/Menu');

    print "[Menu]\n";

    # <Menu>ノードを展開
    foreach my $menu (@menus) {
        # <Menu>ノードを展開
        printf(" - %s\n", $menu->findvalue('.'));
    }
}

print文だらけですみません。

my @elements = $class->findnodes('タグへのXPath')ノード(タグのまとまり)を取得し、さら$elements[0]->findvalue('findnodesで指定したタグ以下の相対的なXPath')という形で、ひとつひとつのタグに含まれる値を取得していきます。

これを実際に走らせると、こんな感じ。


[amaya@localhost ~]$ perl ramen_list.pl

----------------------------------

Shop: Perl

----------------------------------

[Comment]

会社帰りに良く寄るお店

[Menu]

- 野菜ラーメン

- 全部入りラーメン

----------------------------------

Shop: 麺屋CPAN

----------------------------------

[Comment]

床がベタベタしてる

[Menu]

- カレーラーメン

- 餃子


うーむ。だいたい雰囲気はつかめた感じ・・・?


とりあえず今回はここまで。。

同じ処理を慣れないモジュールでやるのって、機種変直後の携帯をいじるくらいもどかしいですな。

もっとエレガントな方法をご存知の方、いらっしゃいましたらツッコミをお願いします・・・

kamawadakamawada 2007/11/17 17:33 処理速度を気にしないんだったらXML::Simpleでよくね?

amayanamayan 2007/11/17 18:45 たしかに・・・。今回の場合はとある事情で大量かつ巨大なXMLをパースする必要があって、その方法としてXML::LibXMLを勧められたのでした。ちょっとした用事ならXML::Simpleかなぁ。

amayanamayan 2007/11/17 18:45 そういえば微妙にコメント欄のレイアウトが変わってる。見やすくていいですねー。

kamawadakamawada 2007/11/17 19:51 ああ、巨大なのだったらXML::LibXMLがいいよね。

drrydrry 2007/11/18 21:03 インストールだけど、yum -y install perl-XML-LibXML 一発かと。

amayanamayan 2007/11/18 23:22 >drry
な、なるほど・・・(恥
cpan2rpmをいま試しているんだけど、あれってどうなんでしょう??

amayanamayan 2008/10/13 12:29 最初にこのエントリーをアップした当初はXML::LibXMLを触りたてだったこともあり、非常に冗長なコードを書いてしまっておりました。。

かれこれ半年たちますが、以前よりもスマート(自称)なコードに書き直してみました。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

リンク元