members.jcom.home.ne.jpへの変更により、ご迷惑をおかけして申し訳ありません

目次へ

不定期連載準特別テーマ

「UNIX USER」INDEXを作ろう

このページは、別にソフトバンク社出版の月刊誌「UNIX USER」の広告ページではありません。ただ、個人的にこの雑誌を非常に重宝しているので、書いております。
この月刊誌を買い続けて早くも4年。だがわたしがようやくUNIXを勉強しはじめて約1年。今頃になって去年や一昨年の号が役に立ったりすることがしょっちゅうです。あの記事、何年何月号だったっけ?・・・それを我が家のWebでさっと検索できるようにするシステムを作りました。

結果をちゃっちゃとごらんになりたい方は、こちら:

入力フォーム

検索結果


必要な情報は

必要になるのは、UNIX USERの特集と連載、そのうちトピック的なものは除き、実践方法が具体的に書いてあるものだ。
特集はたとえば「Sambaで行こう」というメインタイトルのもとに「インストール法」「活用法」「セキュリティ」のような2,3の記事がまとめられている(たとえばであって実際の記事名ではありません)。
連載はたとえばメインタイトル「Solaris道を行く」の「第4回」が「システムのアップデートと保守管理」になっている(ちょうど手元にあった2000年9月号)。

PostgreSQL

そこで、PostgreSQLにuuindexというテーブルを作った。
フィールドは、

年と月を6桁で表すmserial(int),
メインタイトル title(text),
連載回数 no(int), ただし特集は0回とする
サブタイトル content(text), ただし特集は各記事のタイトルを「インストール法、活用法、セキュリティ」のように列挙する
others(text) サブタイトルにさらにサブられたりしたときの備考欄

からなる。

それから、連載のタイトルを追加したり削除したりするテーブルも作る。名前はshowtitleにして、これは1行1列の簡単なテーブルだ。

入力フォーム

まず、何年何月号の目次かをインプットする。それで8桁のmserialパラメータを取得する。
同誌の連載はものによるが2,3ヶ月から数ヶ月続く。よって、タイトルの入力にはtextfieldを最大20個ほど用意し、そのうちの十いくつに規定値として今連載中のタイトルを入れておく。タイトルの規定値は一定のファイルから読み込ませるようにする。そうして連載が終わったり始まったりするたびにそのファイルを書き換える。
さて、一定のファイルからタイトルを一個ずつ読み込んではそれを規定値としたtextfieldを表示させる、というPerlのCGIプログラムである。

for ($j=0; $j<21; $j++)
{
 $titlej="title".$j;  (1)
 $noj="no".$j;
・・・・・・ 

 print textfield (
  -name => $titlej,         (2)
  -value => $showtitle[$j],    (3)
  -size => 30,
 );
 print textfield (
  -name => $noj,
  -size => 3,
  -OVERRIDE =>1,
 );
・・・・・
}

ここでは、titleとnoを入力するためのコードを例として示した。
問題だったのは、20個のテキストフィールドを表示させるんだからやっぱりfor文で一気にループさせたいと思ったものの、各フィールドに規定値として表示させる値が違うし、各フィールドの入力結果の受け皿も別々のものにしたいというところなのだ。

まず、「各フィールドに規定値として表示させる値」の話である。上のコードで、(3)にあたる
$showtilte[$j]
だ。これはあらかじめPostgreSQLのテーブルshowtitleからPerlの配列@showtitleに読み込んでおく。コードは以下のとおりだ。もちろん、この前にはデータベースに接続するコードを書いておくことが必要だが。

my $listselectstr="select * from showtitle";
$result = $conn->exec($listselectstr);

$n = $result->ntuples;

for ($i=0; $i < $n; $i++) {
@showtitle = (@showtitle, $result->getvalue($i,0));
}

このようにしてすでに配列に読み込んでから表示に持っていくので、これで問題ない。だが、入力フォームから送信する -nameパラメータのほうが問題だ。
というのも、これらは$title[j]とか$no[j]のように、配列要素で書くとエラーになる。なぜか?たぶんこのようなことだ。
配列@title,@noがあったとして、それらの要素は送信されて初めて有限の値として入ってくる。送信される前は、未定義値。それをtextfieldの-nameパラメータとして置くわけにはいかないようなのだ。
ここは具体的なスカラー変数として置いておかなければならないようだ。そこで、(1)の部分のようにjに依存する名前のついたスカラー変数を定義し、それらを-nameパラメータに置く。
実はこれでもコンパイラ様からは「あなたの名前の付け方は数値と文字列をごっちゃにしているようで芳しくないですネ」と警告を出される。だが一応、わたしの言いたいことはわかってもらえてるようで結果はちゃんとでてくる。

こうして値が送信されたら初めて、

my $insertstr;

for ($i=0; $i<21; $i++) {

my $titlei="title".$i     (1)
my $noi="no".$i;

・・・・・・・

if (param($contenti)) {

my $title=param($titlei);      (2)
my $no=param($noi);
my $content=param($contenti);
my $others=param($othersi);

print p ("$title(第$no回)「$content」");
$insertstr="insert into $tablename values($mserial,'$title', $no, '$content','$others')";
$result = $conn->exec($insertstr);

これは、送信されたパラメータを1個1個受け取って処理していくループだ。配列にため込むようなことはしないので、やはりiに依存させて無理矢理スカラー変数を定義している。ええと、
$titlei
というのはiの字まで含めた、「たいとるあい」という名の変数だ。ループ一回目には(1)の部分で
$titlei="title0"
という文字列を代入される。それを(2)に引き渡すだけの役目だ。つまり(2)の部分で
my $title=param("title0");
というステートメントを実現させたいわけだ。ちょっとくどいかなー?一度送信されたパラメータをすべて何かの配列に読み込んだ方がむしろわかりやすかったかも知れないが・・・これらの変数は全てiが変わる(増える)ごとに初期化されてiに依存する新しい値に置き換えられる。
こうして入力された年月番号、タイトル、内容・・・といったものがテーブルに入力される。

タイトルの規定値

テーブルshowtilteにおさめられ、目次入力フォームで読み込まれ規定値として取り出される連載タイトルは、もちろんときどき増えたり減ったりする。showtitleテーブルの値を追加したり削除したりする必要がある。これもウェブから入力できるようにフォームを作る。作り方は「家計簿DB」でデータの表示と削除を行わせるために作ったものと同じで、

my $selectstr="select * from $tablename";
$result = $conn->exec($selectstr);

my $n = $result->ntuples;

my @record;
for ($i=0; $i < $n; $i++) {

@record = (@record, $result->getvalue($i,0));

と、現存のテーブルshowtitleから値を全部読み込んで配列@recordに入れておいて、

print "Titles Recorded";
print scrolling_list (
-name => 'titled',
-values => \@record,
-size =>15,
-override =>1,
);

と、値をスクローリングリストに乗っける。削除したい場合はこのリストから選んで送信するというわけ。もちろん新しい値の追加には普通のtextfiledを用意してやる。

検索

検索フォームはCGI上でデータベースにselect文をかまし、でてきた結果を表示するだけだ。
これを作ってから、わたくしは次は「スレッド式掲示板」を作りたいと思った。でもどうやって作ればいいかしら・・・あれ?!確かUNIX USERに、載ってなかったっけか?!
さっそく、今作ったばかりの検索アプリで探してみた。

あるじゃん。

役に立つなー。さっそく本棚から該当号を探して、勉強開始!

おわり

2001年12月09日