人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

perlでのxmlの勉強中です。
以前も同じような質問をさせて頂いのですが、
今回は以下のXMLデータから
http://live-e.naist.jp/data/getLatestDataAll/
属性temperatureを取得して、
属性のjptimeと
親ノードの属性のlatitude、longitude
を取得し、CSVに保存するプログラムを作成していただけいないでしょうか。


親ノード、属性、子ノード、属性のアクセスの仕方の勉強がしたいので宜しくおねがいいたします。

環境:windows xp、active perl
表示文字コード jis,
エディターは秀丸でプログラムを書く文字コードはeucです。
汎用性の高い出力結果でおねがいいたします。

●質問者: いまよ
●カテゴリ:コンピュータ
✍キーワード:Active CSV EUC JIS Perl
○ 状態 :終了
└ 回答数 : 2/2件

▽最新の回答へ

1 ● ゆう
●82ポイント

この要件であれば、XPathを使用すると良いと思います。

XML::XPathというモジュールを使いますが、

インストールしてないようであれば、Perl Package Managerでインストールしてください。

1つのsensorGroupは、sensorTypeがTemperatureのsensor要素を複数持つことがあるので、二重ループになります。

詳細はソースのコメントを参照してください。

#!/usr/bin/perl
use strict;
use LWP::Simple;
use URI;
use XML::XPath;

#xmlを取得
my $uri = URI->new('http://live-e.naist.jp/data/getLatestDataAll/');
my $response_string = get($uri);

#XPathオブジェクトを作成
my $xp = XML::XPath -> new( xml => $response_string );

#出力ファイルの定義
open(OUT, ">data.csv");

#sensorType属性にTemperatureを持つsensorGroup要素を取得する
foreach my $node ( $xp -> find('/sensorGroup[@class="collection"]/sensorGroup[sensor[@sensorType="Temperature"]]') -> get_nodelist ){
my $id = $node -> findvalue('@id');
my $latitude = $node -> findvalue('@latitude');
my $longitude = $node -> findvalue('@longitude');

#sensorType属性にTemperatureを持つsensor要素を取得する
foreach my $nodeInner ( $node -> find('sensor[@sensorType="Temperature"]') -> get_nodelist ){
my $sensorid = $nodeInner -> findvalue('@id');
my $jptime = $nodeInner -> findvalue('value/@jptime');

#以下の形式でCSV出力する
#センサーグループID,緯度,経度,センサーID,日本時間
print OUT $id . "," . $latitude . "," . $longitude. "," . $sensorid . "," . $jptime . "\n";
}
}
◎質問者からの返答

ありがとうございました。

xpathというものを利用すると、かなり多くのことができるみたいですね。

みなさん、perlのxml処理をどんな本とか、HPみて勉強しているのでしょうか。

ジュンク堂で本をあさって見ても、あまり詳細な記述は載ってなかったので。


2 ● うぃんど
●82ポイント
#!/usr/bin/perl
#
# あまり原型をとどめていませんが前回質問 http://q.hatena.ne.jp/1279820516 を改造する形で対応
# 出力は指定によりsjisからjisに変更
# 時刻表記は正規表現を用いて少し整形
# ソート処理やXML形式での出力を行う場合は s1 の結果を直接printするのではなく配列変数に入れてsortしてから出力する必要あり
# 要素が複数の場合は$key2を出力しているが、間違いであれば$key1(親のid)に変更が必要
#
use strict;
use warnings;
use LWP::Simple;
use Encode;
use XML::Simple;
#
sub s1 {
 ( my $temp1, my $temp2 ) = @_;
 $temp2 =~ s|^(\d+)-(\d+)-(\d+)T((\d+):(\d+):(\d{2})).*$|$1/$2/$3 $4|;
 return $temp1 . ',' . $temp2 . "\n";
}
#
my $readXML = XML::Simple -> new -> XMLin( get( 'http://live-e.naist.jp/data/getLatestDataAll/' ), SuppressEmpty => '' );
foreach my $key1 ( keys %{ $readXML->{ 'sensorGroup' } } ) {
 if ($key1 ne '') {
 my $ref1 = $$readXML{ 'sensorGroup' }{ $key1 };
 if ( $$ref1{ 'sensor' }{ 'sensorType' } ) {
 # 要素が1つの場合
 if ( ( $$ref1{ 'sensor' }{ 'sensorType' } eq 'Temperature' ) && ( $$ref1{ 'value' }{ 'jptime' } ) ) {
 print s1( '"' . encode( 'jis', $key1 ) . '"' . ',' . $$ref1{ 'latitude' } . ',' . $$ref1{ 'longitude' }, $$ref1{ 'value' }{ 'jptime' } );
 };
 } elsif ( $$ref1{ 'sensor' } ) {
 # 要素が複数の場合
 foreach my $key2 ( keys %{ $$ref1{ 'sensor' } } ) {
 my $ref2 = $$ref1{ 'sensor' }{ $key2 };
 if ( ( $$ref2{ 'sensorType' } ) && ( $$ref2{ 'value' }{ 'jptime' } ) ) {
 if ( $$ref2{ 'sensorType' } eq 'Temperature' ) {
 print s1( '"' . encode( 'jis', $key2 ) . '"' . ',' . $$ref1{ 'latitude' } . ',' . $$ref1{ 'longitude' }, $$ref2{ 'value' }{ 'jptime' } );
 }
 }
 }
 }
 }
}
◎質問者からの返答

連答ありがとうございました。

simpleだとこのようになるんですね。

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ