半端なゲーマーSEの戯言

ゲーマーとしてもSEとしても半端な人間が書いています


【Perl】XML 形式のデータの変換

こんばんは。つおしです。

副業では、Perl を使うことが多い今日この頃。
最近、XML を加工する処理を作成したのですが、忘れそうなので備忘のために記載。

XML変換

CPAN について

使った CPAN はこれ

XML::Rules - search.cpan.org

まあ使い方や詳細は全部 ↑ここに書いてあるんだけど、読むのめんどくせぇよって人のためにざっくり使い方まとめます。
初めて使ったので、間違って理解しているところもあると思いますが、見つけたらご指摘お願いします。

使い方

基本的な使い方は以下。

  1. パースの形式を配列で指定する。
  2. 1. で指定した配列のリファレンスを渡して、パースを実行!

物は試し。まずはインストールmac

% cpanm XML::Rules

Windows の場合は、サイトからtar.gz をダウンロード後、解凍。読み込めるところに置いてください。

使ってみる
xml_parser.pl

#!/usr/bin/perl
use strict;
use warnings FATAL => 'all';
use lib qw(/XML::Rules 置いたパス/);
use XML::Rules;
use Data::Dumper;

my $xml = <<TEST_XML;
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<hoge>
	<huga>aaaaa</huga>
	<piyo>123</piyo>
</hoge>
TEST_XML

#パースの形式を配列で指定する。
my @rules = (
		hoge => sub { hoge => {
			huga => $_[1]->{huga}->{_content},
			piyo => $_[1]->{piyo}->{_content}
			}}
	);

#配列のリファレンスを渡して、パースを実行!
my $parser = XML::Rules->new( rules => \@rules );
print Dumper $parser->parse( $xml );

__END__

実行結果

% perl xml_parser.pl
$VAR1 = {
          'hoge' => {
                      'piyo' => '123',
                      'huga' => 'aaaaa'
                    }
        };

いい感じにハッシュのリファレンスになりました!

ルールについて

パースのルールについてもう少し詳しく

my @rules = (
		hoge => sub { hoge => {
			huga => $_[1]->{huga}->{_content},
			piyo => $_[1]->{piyo}->{_content}
			}}
	);

最初の hogehogeタグどーすんの?って意味です。で、sub の中でそれを定義してます。(sub の中の hoge はキー名です)
$_[1] には hogeタグで挟んでいる中身が全部ハッシュになって入っています。
$_[1] を Dumper するとこんな感じ

$VAR1 = {
          'piyo' => {
                      '_content' => '123'
                    },
          'huga' => {
                      '_content' => 'aaaaa'
                    },
          '_content' => '
	
	
'
        };

これ見ると、まあこういうルールになるよね!って感じです。
子タグをもたないタグ(例でいうと、huga, piyo)をパースをすると、コンテンツが _contents というキーに対応したバリューにセットされるようです。
逆に、子タグを持っているタグ(hoge)をパースすると、_contents キーに対応するバリューは空で、子タグの名前のキーにそれぞれバリューがセットされます。


個人的に、ハッシュのリファレンスにしたほうがやりやすいと思ったので、ルールをそうなるように書きましたが他の書き方も全然できると思います。
配列のリファレンス

my @rules = (
		hoge => sub {[
			$_[1]->{huga}->{_content},
			$_[1]->{piyo}->{_content}
			]}
	);

実行結果

$VAR1 = [
          'aaaaa',
          '123'
        ];

JSON っぽいテキスト

my @rules = (
		huga => sub { huga => "{\"huga\":\"".$_[1]->{_content}."\"}" },
		piyo => sub { piyo => "{\"piyo\":".$_[1]->{_content}."}" },
		hoge => sub {"{\"hoge\":[".$_[1]->{huga}.", ".$_[1]->{piyo}."]}"}
	);

実行結果

$VAR1 = '{"hoge":[{"huga":"aaaaa"}, {"piyo":123}]}';

JSON はただそれっぽくくっつけただけだけどね!笑

タグに属性が付いていた場合

タグに属性が付いている xml をパースしてみました。

my $xml = <<TEST_XML;
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<hoge>
  <huga id="a">aaa</huga>
  <huga id="b">bbb</huga>
  <piyo>123</piyo>
</hoge>
TEST_XML

パースのルールはこんな感じ

my @rules = (
		huga => sub { $_[1]->{id} => $_[1]->{_content}},
		hoge => sub { 
			huga => { a =>$_[1]->{a}, b => $_[1]->{b} },
			piyo => $_[1]->{piyo}->{_content}
		}
	);

実行結果はこんな感じになりました。

$VAR1 = {
          'piyo' => '123',
          'huga' => {
                      'b' => 'bbb',
                      'a' => 'aaa'
                    }
        };

これまたいい感じのハッシュのリファレンス!
属性が付いてるタグの属性を無視してパースすると、一番最後のコンテンツしかとれませんでした。

さくっと終わらせるつもりがだいぶ長くなったな!笑

以上、また次回!