PerlでXMLの扱いを学ぶための自作ドリル
モジュールはXML::LibXMLを使用。
問題
XML書き出しスクリプト
name, email, addressを入力して、XMLでファイルに書き出す。(項目名はプロンプトとして表示する。)
実行結果
$ perl output_xml.pl name : 山田太郎(改行) email : taro.yamada@xxx.com(改行) address : 東京(改行) name : 田中次郎(改行) email : jiro.tanaka@yyy.com(改行) address : 大阪(改行) name : 阿部三郎(改行) email : saburo.abe@zzz.com(改行) address : 名古屋(改行) name : (Ctrl+Dで終了) $
書き出し結果ファイル(output_xxxxxxxxxx.xml)
<?xml version="1.0" encoding="UTF-8"?> <addressBook> <person> <name>山田太郎</name> <email>taro.yamada@xxx.com</email> <address>東京</address> </person> <person> <name>田中次郎</name> <email>jiro.tanaka@yyy.com</email> <address>大阪</address> </person> <person> <name>阿部三郎</name> <email>saburo.abe@zzz.com</email> <address>名古屋</address> </person> </addressBook>
XML読み込みスクリプト
XMLファイルを読み込み、マップ形式で画面に表示する。
読み込みファイル(output_xxxxxxxxxx.xml)
<?xml version="1.0" encoding="UTF-8"?> <addressBook> <person> <name>山田太郎</name> <email>taro.yamada@xxx.com</email> <address>東京</address> </person> <person> <name>田中次郎</name> <email>jiro.tanaka@yyy.com</email> <address>大阪</address> </person> <person> <name>阿部三郎</name> <email>saburo.abe@zzz.com</email> <address>名古屋</address> </person> </addressBook>
実行結果
$ perl input_xml.pl output_xxxxxxxxxx.xml (1) name : 山田太郎 email : taro.yamada@xxx.com address : 東京 (2) name : 田中次郎 email : jiro.tanaka@yyy.com address : 大阪 (3) name : 阿部三郎 email : saburo.abe@zzz.com address : 名古屋 $
解答例
XML書き出しスクリプト
use strict; use warnings; use utf8; use XML::LibXML; binmode STDIN, ':utf8'; binmode STDOUT, ':utf8'; binmode STDERR, ':utf8'; # 書き出しファイル名 my $xmlout_name = $ARGV[0] || 'output_' . time . '.xml'; # File Check if (-e $xmlout_name) { print STDERR "$xmlout_name already exists.\n"; exit 1; } # Input Data Table my @labels = ('name', 'email', 'address'); my @table = ([]); # XML作成 my $xml = XML::LibXML::Document->new('1.0', 'UTF-8'); # addressBookノードを作成 my $adb = XML::LibXML::Element->new('addressBook'); $xml->addChild($adb); # 先頭のpersonノードを作成 $adb->addChild(XML::LibXML::Element->new('person')); # Input Data my $finish = 0; while ($finish == 0) { # 最後尾のpersonノードを参照 my $node = $adb->lastChild; # personノードに入っている項目数(子ノードの数)を取得 my $cnt = ($node->hasChildNodes()) ? $node->childNodes()->size() : 0; # 項目数から、次の項目名を取得 my $name = $labels[$cnt]; # プロンプト表示 print "$name : "; if (my $param = <STDIN>) { $param =~ s/[\r\n]//go; if ($param ne '') { # 入力データを新しいノードとして、personに追加 my $data = XML::LibXML::Element->new($name); $data->appendText($param); $node->addChild($data); # 入力項目が最後の時、次のpersonノードを追加 if ($cnt + 1 >= @labels) { $adb->addChild(XML::LibXML::Element->new('person')); } } } else { $finish = 1; # 末尾のpersonノードに入力項目(子ノード)が無い時、ノードを除去 $adb->removeChild($node) unless ($node->hasChildNodes()); } } print "\n"; # File Double-check if (-e $xmlout_name) { print STDERR "$xmlout_name already exists.\n"; exit 1; } # XML Output $xml->toFile($xmlout_name, 1); exit 0;
XML読み込みスクリプト
use strict; use warnings; use utf8; use XML::LibXML; binmode STDIN, ':utf8'; binmode STDOUT, ':utf8'; binmode STDERR, ':utf8'; # Input Check if (@ARGV != 1) { print STDERR "Please input XML file name.\n"; exit 1; } # 読み込みファイル名 my $xmlin_name = $ARGV[0]; # File Check unless (-f $xmlin_name) { print STDERR "$xmlin_name is not found.\n"; exit 1; } # Input XML my $xml = XML::LibXML->load_xml(location => $xmlin_name); # 全てのpersonノードをリストで取得 my @persons = $xml->getElementsByTagName('person'); # Output XML Data for (my $cnt = 0; $cnt < @persons; $cnt++) { print '(' . ($cnt + 1) . ')' . "\n"; # personノードの(Textノードを除く)全ての子ノード(項目)をリストで取得 my @params = ($persons[$cnt]->hasChildNodes()) ? map {(ref($_) eq 'XML::LibXML::Element') ? ($_) : ();} ($persons[$cnt]->childNodes()) : (); # 項目を全て表示(項目名 : 項目内容の組で) foreach my $node (@params) { print "\t" . $node->nodeName . ' : ' . $node->textContent . "\n"; } } exit 0;