ハイパーテキストへ

ハイパーカードはその名前を見ても分かるとおりハイパーテキストと密接な関連がある。組み込み機能だけを使って、ハイパーテキストをどこまで実現できるか追求してみる。

ハイパーテキストとは

1962年、テッド・ネルソンはハイパーテキストを提唱した(*注1)。これは、簡単にいってしまえば文書から「順序」という概念を取り除いたものである。書物が基本的に最初から順番に読まれることを前提にしているのに対し、ハイパーテキストは関連する内容を縦横に結び、読者が自由に行きつ戻りつすることができる仕組みだ。情報洪水の中では、このようにして本当に必要なものを効率的に選び出す手段が不可欠になる。オフィスでも、山のような書類から求める情報をうまく見つける方法が欠かせない。

ハイパーカードが1987年に登場したときは、このハイパーテキストがいよいよパーソナルなレベルで実現できると期待が集まったものだ。そして、一部ではハイパーカードを用いて優れたシステムが構築されもしたのだが、意外にこの方面でハイパーカードが広く活用されるには至っていない。むしろ最近インターネットでWWWなどが出現してようやくハイパーテキストらしいものが身近になった。

ハイパーカードではボタンを使って縦横のリンクを簡単に構築できる。これが単なるカードの移動以上に使われていないのは、ハイパーテキストを設計し、きちんとリンクを張っていくのが結構面倒な作業であるということが原因だと思われる。今回は、リンクの設定を簡単にし、ハイパーカードの持ち味を引き出す方法を探ってみよう。

ボタンによるリンクの実践とその限界

ハイパーカードでハイパーテキストを実現する最も分かりやすい方法は、ボタンによるカードのリンクである(画面1)。しかし、このリンクではカードとカードの関係しか表現することができない。フィールドに表示されている特定の言葉に対してリンクを作成するのは、このままでは不可能である。

フィールドに納めるテキストが比較的短く、スクロールさせる必要がないときは、アンカーにする語句の上に透明ボタンを作るという方法もある(画面2)。これは一つの解決策ではあるが、テキストに対する制約が大きくなる上に、多彩なリンクを表現するためにいちいちボタンを作っていては効率が悪い。

ハイパーテキストというからには、テキストそのものがアンカーになって関連するカードにリンクできることが望まれる。ある語句をクリックすると、その語句を説明するカードにジャンプするというような仕組みはできないだろうか。

テキストボタンの実現

フィールドのテキストをアンカーとするためには、the clickText関数を使って、マウスがどの語句(word)をクリックしたかを調べ、その語句とカード名が一致するカードを探せばよい。つまり

go cd the clickText

のようにすれば、あっと言う間にハイパーテキストの出来上がりだ。

ところが、これは英文でしかうまく働かない。日本語ではthe clickTextで単語ではなく文(段落)全体が返されてしまうのである。

そこで目を付けたのが、フィールドのテキストが持つ「グループ」スタイル属性(画面3)だ(*注2)。この属性を使うと、クリックしたときにthe clickTextで得られるまとまりを、wordを越えて直接指定することができる。グループが設定されていれば、日本語でもクリックしたときにthe clickTextが段落全体ではなくそのグループを返してくれるのだ。

これを利用して日本語ハイパーテキストを実現したのがリスト1である。2行目でクリックした部分がグループになっているかどうかを調べ、グループ化されている語句に対してその語句がカード名になっているカードへ移動する(*注3)。

リンクの自動作成

画面 さて、本題はこれからである。最初に、ハイパーカードでハイパーリンクが余り広く使われないのは、設計とリンクの設定が面倒であることが一つの要因であると述べた。前節の方式でも、アンカーとなる語句を一つ一つ選んで「グループ」スタイルを設定していくのは楽な作業ではない。そこで、この作業を何とか自動化してしまおうというのが今回の目論見である。

例によって、材料はHDBスタイルのテキスト(*注4)ということにする。自動化の内容は、

  1. HDBを読み込んでレコードごとにテキストをカードに振り分け
  2. 本文中に別のレコードのタイトルと同じ語句があったら、その語句をグループ化する

というものだ。

最初のレコードの振り分けは、これまで何度も登場した「区切り行」によるHDB処理の応用である。新しいレコードになるたびに新規カードを作成し、カードの名前をタイトルと同じに設定していく(*注5)。自動化のポイントはこのあとのグループの設定である。

リスト2を見てみよう。引数のtitleListは、(1)のレコード切り分けのときに記録しておいたタイトルのリストである。これを使って、タイトルと同じ語句(検索語句)が本文フィールドに含まれているかどうかを順に調べていく。5〜19行のループでは、find string命令で検索語句を繰り返し調べている。目指す言葉を発見したら、17行目でその部分のスタイルを「グループ」に設定するのである(*注6)。

これを実行してみると画面4のようなスタックができあがった。グループ化された語句は、リスト1によって該当するカードへのハイパーリンクを持つことになる。

ダイナミックなリンクを考える

前節のHDBの自動リンク設定では、あらかじめよく考えてタイトルを付けないと、全くリンクが作られなかったり、逆に不要なリンクだらけになったりする可能性がある(画面5)。しかも、このようなリンクを前提に作成した文書は、あとから構造を変えることが難しくなってしまう。

文書からハイパーリンクのシステムを作る場合、内容が更新される可能性のあるものについては、オリジナル文書を変更してもリンクが維持できる仕組みの方が望ましい。そこで、一歩進んで本文そのものにリンクの指示を埋め込む拡張HDBを考えることにしよう。前節の方法が静的なリンクであったのに対し、こちらはいわば動的なリンクを作成するわけである。

このような機能を実現するには、HyperDBのように、スタックには見出し一覧だけ持ち、本文はその都度テキストファイルから読み込んで表示する形式が扱いやすい。外部からレコードを取り込んでフィールドに書き込むときに、合わせてリンクの情報も調べて表示する。こうすれば、いくらテキストを書き直しても最新のリンク情報を反映させることが可能なはずだ。

拡張HyperDBの実現

具体的には、リンクの元(アンカー)となるべき語句を、何らかの記号で識別できるようにしておく。この記号は何でもよいのだが、単純にテキストとして読んだときに邪魔にならず、できれば他のブラウザ上でも何らかの機能を果たせるものがよい。ここでは、EasyViewで下線を表示できる_(アンダースコア)を使うことにする。アンカーにする語句を_で囲み、更にその両側に半角スペースを置く(*注7)。つまりハ_アンカーの語句_ハのようになる。

これを動的にホットテキストにするにはリスト3のようなスクリプトを使う。showDataはHyperDBのタイトルフィールドをクリックしたときに呼び出されるハンドラで、1〜5行は従来通り、選択したレコードをフィールドに書き込む部分。今回の新機軸は6行目で登場するhotPos関数である。これは、フィールドのレコードの中でアンカーとなっているところを調べ(13, 15行目)その位置を返すもの。17行目で自分を再帰的に呼び出して、全てのアンカーを探すようになっている。この結果を使って、7〜9行目でフィールドのテキストのアンカー部分を「グループ」に設定していく。これでレコードを読むたびにリンクが用意されるというわけだ。

このホットリンクを実行するフィールドのハンドラは基本的にリスト1と同じものだが、カードにレコードを振り分けているわけではないので、リスト4のようにタイトル一覧から該当するものを検索して、もう一度リスト3のshowDataを呼ぶようにした。以上でダイナミック・ハイパーリンクの完成である(画面6)。

*   *   *

オフィスにおけるハイパーテキストの実現は、9月号で検討したようなHTMLへの変換によるWEBブラウザの活用という方法もある(1995/9号:HyperDBとの連動)。ただ、こうした変換による方法では、オリジナルに変更があるといちいちHTML文書も作りなおさなければならない。拡張HDBは機能は単純ながら、オリジナルファイルをそのままハイパーテキストにできるというところが強みである。文書の性質に応じて、これらの手法を使い分ければ、強力なハイパーオフィスが構築できるだろう。

*注1

ハイパーテキストの概念自体は1945年のヴァネヴァー・ブッシュによって提唱されたMEMEXにまでさかのぼる。このあたりの参考文献は多数あるが、たとえば奧出直人『思考のエンジン』などを参照。

*注2

もともとは英文をクリックしたとき2つ以上のwordを得るために、それらの単語をグループ化しておくスタイル。show groupsとすると、グループ化された語句にグレーの下線が付き、一目で分かるようになる。

*注3

製品版のハイパーカードに含まれる「ヘルプ」も同様の仕組みで関連するトピックを次々に調べられるようになっている。

*注4

1995/7号:7月号で作成したHyperDB形式のデータのこと。レコードをハイフン2つの行(--)で区切り、各レコードの最初の1行を見出しとするテキストファイル。

*注5

この部分のスクリプトの構造は何度も解説したので省略する。サンプルスタック「HDB-HyperText」のボタン「HDB->HyperLink」のスクリプトにある関数parseRecords()を参照(1995/7号:タイトルの抽出1995/11号:テキストデータベースとしてのメッセージなども参考に)。

*注6

自分に対してリンクを設定しても意味がないので、リスト3の14行目でカードのタイトルが検索語句そのものでないかどうかを確認しておく。

なお、このループは繰り返し回数を指定せず、変数foundFirstに検索語句が最初に見つかった場所を記録しておき(9〜10行目)、検索を続けてfoundFirstに記録した場所に戻ってきたら終了するという設定になっている(11行目)。

*注7

EasyView上で下線を表現する場合、単語をアンダースコアで囲むのだが、日本語の場合単語の切れ目がないため、半角スペースを置いてアンカーを独立させる必要がある。

リスト

リスト1

 1: on mouseUp
 2:   if the textStyle of the clickChunk contains "group" then
 3:     get the clickText
 4:     go cd it
 5:   end if
 6: end mouseUp

リスト2

 1: on setLink titleList
 2:   repeat with i=1 to number of lines of titleList
 3:     put line i of titleリストinto tgStr
 4:     put "" into foundFirst
 5:     repeat
 6:       find string tgStr in fld "myText"
 7:       get the foundChunk
 8:       if it is "" then exit repeat
 9:       else if foundFirst is "" then
10:         put it & short name of this cd into foundFirst
11:       else if it & short name of this cd is foundFirst then
12:         exit repeat
13:       end if
14:       if short name of this cd is tgStr then
15:         go next cd
16:       else
17:         set textStyle of the foundChunk to "Group"
18:       end if
19:     end repeat
20:   end repeat
21: end setLink

リスト3

 1: on showData lineNo
 2:   put line lineNo to LineNo+1 of fld "Index" into POS
 3:   put ReadFile(line 2 of fld "FileInfo") into str
 4:   get line (line 1 of POS +1) to (line 2 of POS -1) of str
 5:   put it into fld "TEXT"
 6:   put hotPos(it) into hotPositions
 7:   repeat with i=1 to number of lines of hotPositions
 8:     set textStyle of char item 1 of line i of hotPositions to item 2 of line i of hotPositions of fld "TEXT" to "group"
 9:   end repeat
10: end showData

11: function hotPos str, stOff
12:   get number of chars of str
13:   put offset(" _", str) into hot1
14:   if hot1 is 0 then return ""
15:   put offset("_ ", char hot1 + 1 to it of str) + hot1 into hot2
16:   put stOff + hot1+2 & "," & stOff + hot2-1 & RETURN into res
17:   put hotPos(char hot2+1 to it of str, stOff + hot2) after res
18:   return res
19: end hotPos

リスト4

 1: on mouseUp
 2:   if the textStyle of the clickChunk contains "group" then
 3:     get the clickText
 4:     find it in fld "Title"
 5:     showData (word 2 of the foundLine)
 6:   end if
 7: end mouseUp

用語

word

ハイパーカードで言うwordはスペースや改行で区切られた、もしくは""で囲まれた一連の文字列をさす。日本語の場合は、仮名漢字の違いや句読点に関係なく、全角文字の連なり全体がwordとして扱われてしまう。このため、wordを利用したHyperTalkを使う場合に注意が必要になる。

the clickText

テキストをロックしたフィールドをクリックすると、クリックした部分のテキストに関する情報を得ることができる。このthe clickTextではクリック位置にある語句(word)が直接返される。ポジションを調べるにはthe clickChunkを使う。この場合にはchar 10 to 20 of bkgnd field 1のような結果になる。いずれも本文で説明したように日本語では語句ではなく段落全体が返されてしまうので、「グループ」スタイルを設定しておく必要がある。また、the clickLineではline 3 of bkgnd field 1のような結果が得られる。

find string

英文の場合、find "MacUser Japan"とすると、MacUserという単語とJapanという単語がAND検索され、必ずしも連続していなくてもこの2語がカード上にあればヒットしてしまうので、"MacUser Japan"を一まとまりとして検索する場合にはfind stringとしなければならない。日本語の場合は、wordの扱いが異なるのでfindとしても実質的には違いはない。

the foundChunk

find命令で見つかった文字列の位置をchar 10 to 20 of bkgnd field 1のようなかたちで返す。the foundField、the foundLine、the foundTextのようなバリエーションでは、それぞれ見つかったフィールド、行、テキストそのものが得られる。

(MacUser Japan, December 1995)