TOP XML & CGI 目次

XMLでデータベース
XMLデータのクリーニング
CGIプログラムには配列@dataに以下のように収納されます。
配列0番はXML宣言文があるところなので表示に用いない。(0番にはXML宣言が入ってます)
配列1番にはルート要素+子要素(この場合<新聞雑誌記事>+<記事>)があります。他の配列にそろえるためにルート要素<新聞雑誌記事>は除きます。
配列1番以下データトップに子要素(この場合<記事>)が来ますのでこれを除きます。但し、要素の属性もそれぞれの配列に納める必要があります。

実際に、下のようなデータを配列に入れてみます。
用いたプログラムは次のようなものです。青字部分はタグがあると画面に表示されないのでタグをエスケープしました(これは後で取り去りました)。
各レコードの行末の改行コードを除去します。
test01.cgi
#!/usr/bin/perl

#HTML文を出力するための宣言
print "Content-type: text/html\n\n";

open (IN,"dtb.xml");
@data=<IN>;
close(IN);

$n=0;
foreach(@data){
$data[$n] =~ s/</&lt\;/g; #htmlタグを禁止する
$data[$n] =~ s/>/&gt\;/g; #htmlタグを禁止する
$data[$n] =~ s/\n//g; #改行コードを除く

print "\$data\[$n\]\="."$data[$n]<BR>\n";
$n++;
print "<P>\n";
}

exit;
ルート要素<新聞雑誌記事>を取り除きます。test02b.cgi
#!/usr/bin/perl

#HTML文を出力するための宣言
print "Content-type: text/html\n\n";

open (IN,"dtb.xml");
@data=<IN>;
close(IN);

$n=0;
foreach(@data){
$data[$n] =~ s/\<$element_root\>//g; #ルート要素始めを除く
$data[$n] =~ s/\<\/$element_root\>//g; #ルート要素終わりを除く

$data[$n] =~ s/</&lt\;/g; #htmlタグを禁止する
$data[$n] =~ s/>/&gt\;/g; #htmlタグを禁止する
$data[$n] =~ s/\n//g; #改行コードを除く
print "\$data\[$n\]\="."$data[$n]<BR>\n";
$n++;
print "<P>\n";
}

exit;
次に<記事>要素の属性の名前と値を取り出す。各々の属性の間にはスペースがひとつあるのでこれで切り分けます。しかし、属性の値の中にもスペースがある可能性があるので "+スペースで区切ります。
あとあと使いやすくするためにサブルーチンにしました。
test02c.cgi
#!/usr/bin/perl

#HTML文を出力するための宣言
print "Content-type: text/html\n\n";

#データを配列に入れる
&data;

$n = 1;
foreach(@data){
print "\$data\[$n\]\="."$data[$n]<BR>\n";
#属性要素を配列に入れる
&zokusei;
$m = 0;
foreach(@zokusei){
print "  "."\$zokusei\[$m\]\="."$zokusei[$m]<BR>\n";
$m++;
}
print "<P>\n";
$n++;
}


exit;

#==========サブルーチン==========

#データを配列に入れる
sub data{
open (IN,"dtb.xml");
@data=<IN>;
close(IN);

$n=0;
foreach(@data){
$data[$n] =~ s/\<新聞雑誌記事\>//g; #ルート要素を除く
$data[$n] =~ s/</&lt\;/g; #htmlタグを禁止する
$data[$n] =~ s/>/&gt\;/g; #htmlタグを禁止する
chop($data[$n]); #行末の改行コードを除く
$n++;
}
}

#要素属性を配列に入れる
sub zokusei{
@zokusei=split(/" /,$data[$n]);
}
タイトル左端の<記事を取り除く。(赤字)テキスト端末の</記事>を取り除く。(赤字)
コメントにぶら下がっているテキスト(本文)を取り出す。$zokusei[11]の中で、テキストの前には必ず "> があるのでこれを目印にすればいい。(青字)
コメントからテキストを除く。(青字ボールド)
あとは属性の値の左端の”を取り除く。(黒字ボールド)
test03b.cgi
#!/usr/bin/perl

#HTML文を出力するための宣言
print "Content-type: text/html\n\n";

#データを配列に入れる
&data;

$n = 1;
foreach(@data){
print "\$data\[$n\]\="."$data[$n]<BR>\n";
&zokusei;
$m = 0;
foreach(@zokusei){
print "  "."\$zokusei\[$m\]\="."$zokusei[$m]<BR>\n";
$m++;
}
print "  "."\$text\[$n\]\="."$text[$n]<BR>\n";
print "<P>\n";
$n++;
}


exit;

#==========サブルーチン==========

#データを配列に入れる
sub data{
open (IN,"dtb.xml");
@data=<IN>;
close(IN);

$n=0;
foreach(@data){
$data[$n] =~ s/\<新聞雑誌記事\>//g; #ルート要素を除く
$data[$n] =~ s/</&lt\;/g; #htmlタグを禁止する
$data[$n] =~ s/>/&gt\;/g; #htmlタグを禁止する
chop($data[$n]); #行末の改行コードを除く
$n++;
}
}

#要素属性を配列に入れる/テキストの抽出
sub zokusei{
@zokusei = split(/" /,$data[$n]); #属性を各配列に納める
$zokusei[0] =~ s/&lt\;記事 //; #タイトルから<記事 を取り除く
$zokusei[11] =~ s/&lt\;\/記事&gt\;//g; #コメントから</記事>を取り除く

$l = index($zokusei[11],"\"&gt\;");
$text[$n] = substr($zokusei[11],$l+5); #テキストを取り出す

$zokusei[11] = substr($zokusei[11],0,$l-1); #属性の値を取り出す
$m = 0;
foreach(@zokusei){
$zokusei[$m] =~ s/"//g; #最後に残った " を取り除く
$m++;
}

}
コメントの末尾の文字が化けてしまう問題が生じる。
データの区切れが図のように違っていた。
左の場合はコメント・データが一部削られてしまったようだ。
$zokusei[11] = substr($zokusei[11],0,$l-1);
最後の-1が間違っていたようでした。(これは要らない)文字列を取り出す時の考え方の誤解でした。(index($○○○,□□)の返す値は文字を数えるのではなく、文字と文字の間を数えるのでした)
 
@zokuseiには配列0〜11番まで「属性名」と「値」が入っています。「属性名」は必要ないので「値」だけにします。「属性名」と「値」の間には = があり、これで区切ることができます。test03c.cgi
#!/usr/bin/perl

#HTML文を出力するための宣言
print "Content-type: text/html\n\n";

#データを配列に入れる
&data;

$n = 1;
foreach(@data){
print "\$data\[$n\]\="."$data[$n]<BR>\n";
&zokusei;
$m = 0;
foreach(@zokusei){
print "  "."\$zokusei\[$m\]\="."$zokusei[$m]<BR>\n";
$m++;
}
print "  "."\$text\[$n\]\="."$text[$n]<BR>\n";
print "<P>\n";
$n++;
}


exit;

#==========サブルーチン==========

#データを配列に入れる
sub data{
open (IN,"dtb.xml");
@data=<IN>;
close(IN);

$n=0;
foreach(@data){
$data[$n] =~ s/\<新聞雑誌記事\>//g; #ルート要素を除く
$data[$n] =~ s/</&lt\;/g; #htmlタグを禁止する
$data[$n] =~ s/>/&gt\;/g; #htmlタグを禁止する
chop($data[$n]); #行末の改行コードを除く
$n++;
}
}

#要素属性を配列に入れる/テキストの抽出
sub zokusei{
@zokusei = split(/" /,$data[$n]); #属性を各配列に納める
$zokusei[0] =~ s/&lt\;記事 //; #タイトルから<記事 を取り除く
$zokusei[11] =~ s/&lt\;\/記事&gt\;//g; #コメントから</記事>を取り除く
$l = index($zokusei[11],"\"&gt\;");
$text[$n] = substr($zokusei[11],$l+5); #テキストを取り出す
$zokusei[11] = substr($zokusei[11],0,$l-1); #属性の値を取り出す
$m = 0;
foreach(@zokusei){
$zokusei[$m] =~ s/"//g; #最後に残った " を取り除く
$l=index($zokusei[$m],"\="); #属性名を除く
$zokusei[$m]=substr($zokusei[$m],$l+1,length($zokusei[$m])-$l);

$m++;
}
}
上の図で書式が崩れているところを見つけました。データを見ると$zokusei[11]の値と区切りの"(クォーテーション)がくっついていました。他のデータはスペースがあります。これはどういう事だろう??どうもそれはスペースではなく、上の文字化けに見られるように<BR>のエスケープコードの一部が残ってしまったものだろうか。(下は直ったもの)