トップ » 技術記事 » オリジナル Wiki を作ってみよう!(3) - どんな技術要素が必要になるのか

オリジナル Wiki を作ってみよう!(3) - どんな技術要素が必要になるのか

タグ: PHP Wiki

PHP を用いて Wiki アプリケーションを作る手順を解説しています。ゼロから Wiki を作ることで、Wiki がどんな仕組みで動いているのか、どんな技術要素が必要になるのかを解説します。

前回までのおさらい

第1回目では、Wiki とは何か、どうして Wiki を作ることにしたのか、どんな Wiki を作るのかということを考えてみました。そして、KonaWiki という名前の Wiki を作ることに決めました。

第2回目では、手軽にPHPのテスト環境が揃えることが可能なXAMPPを利用して、開発環境を構築してみました。そして、恥ずかしながら、開発途中の KonaWiki を見てもらいました。

KonaWiki の画面

  • KonaWiki の動作画面

今回は、今まで実装したところで、Wiki を作る上で必要となる部分を紹介したいと思います。

Wiki パーサの作成

まずは、Wikiパーサの仕組みから紹介しましょう。Wikiを使うと、手軽に Web 上で情報共有を行うサイトを構築することができます。Wiki がこれほど、手軽に使えるのは、Wiki 記法を用いることで、ページ同士のつながりを手軽に記述できたり、タイトルや箇条書きのテキストを簡単に記述できる部分にあります。

Wiki パーサの働きは、Wiki 記法で書かれたテキストを、HTML に変換するというものです。KonaWiki のパーサは、KonaWikiのソースファイルで言うと、<lib>ディレクトリの中の「konawiki_parser.php」に記述されています。

プログラムのメインとなる関数が以下の「konawiki_parser_convert」関数です。この関数に、Wiki記法のテキストを指定すると、HTMLに変換したものを返します。

function konawiki_parser_convert($text)
{
    $tokens = konawiki_parser_parse($text);
    return konawiki_parser_render($tokens);
}

関数の内容は、一行目で、テキストをトークンの配列に変換し、二行目では、トークン情報を元にHTMLに変換しています。トークンとは、文字列を意味のある語句ごとにバラバラに区切ったものです。

なぜ、一度トークンに分割してから、HTMLに変換するようにしているのでしょうか。もちろん、こんな面倒なことをせず、Wiki記法を直接HTMLに変換することもできました。しかし、パース(語句を意味ごとに区切る作業)と レンダリング(データを元に描画する作業)を分離することで、将来的に、Wiki 記法で書かれたデータを、HTML 以外のデータに変換する余力を持たせたのです。

PHP の PEAR ライブラリにある Wiki パーサの「Text_Wiki」も、同じような仕組みになっており、Parser と Render を用意しておき、Parser でテキストの解析を行い、Render で HTML に変換するという仕組みになっています。

Text_Wiki のページ

Wikiをパースするにあたって、いくつか代表的な Wiki のコマンドを見ておきましょう。文章のタイトルを指定するのが「*」コマンドです。Wikiで、「*大見出し」や「**中見出し」のように書くと、これを「<h1>大見出し</h1>」や「<h2>中見出し</h2>」のようなHTMLに変換します。「*」の数により、大見出し、中見出し、小見出しのように見出しの大きさを指定します。

そして、文章中に箇条書きを作るのが「-」コマンドです。これは「-箇条書き1」「–箇条書き2」のように書きます。すると「<ul><li>箇条書き</li><ul><li>箇条書き</li></ul></ul>」のようなHTMLに変換します。

例えば、以下のような Wiki 記法のテキストがあります。

* 大見出し

- 箇条書き1
- 箇条書き2
- 箇条書き3

このようなデータを解釈するには、一行ずつデータを解析していけば良い事に気付きます。データを改行を区切り文字にして分割するのが簡単で良いのですが、KonaWikiでは、「{{」から「}}」までのテキストをソースファイルとして扱うようにしたり、また、プラグインの引数に改行を含んだテキストを渡せるようにするために、一度に区切ってしまうことはせず、ちょっとずつテキストを読み出して、その度ごとに処理するようにしています。

以下は、Wikiコマンドの解析部分ですが、「substr」関数を用いて、先頭の1文字を調べて、コマンドが決定したところまでをデータ(変数$text)から切り取っていくことで、データが空になるまで繰り返しながら解析します。

$text = "Wiki記法データ..";
while ($text != "") {
    $c = substr($text, 0, 1);
    if ($c == "*") { // title
        // ...
    }
    else if ($c == "-") { // list
        // ...
    }
    // ...
}

切り取ったデータは、以下のような形式でコマンドとトークン文字列とその他の引数のような形でトークン結果に追加していきます。以下の例では、大見出しを表すコマンドを追加する例です。

$tok = konawiki_parser_token($text, $eol);
$tokens[] = array("cmd"=>"*", "text"=>$tok, "level"=>1);

そして、次にレンダリングの処理ですが、こちらは、渡されたトークンデータを元にして、HTMLを出力するものです。トークン分割の時点でかなり変換しやすいデータになっているので、コマンドが「*」なら「h1」でテキストを括るなどの処理を行うようになっています。そのため、レンダリングは基本的に非常に単純なプログラムになっています。

それから、「[ [ 」から「] ]」までを Wiki へのリンク、「http : //」から始まる文字列をリンクタグに置換するようになっています。

これを実現しているのは、「konawiki_parser_tohtml」関数です。この中でも、1文字ずつタグや置換条件がないかどうかを判別してリンクを生成しています。以前は、「preg_replace」関数を用いて、正規表現でリンクなどをHTMLに置換していました。「preg_replace」関数を使うと正規表現で任意の部分を取り出して自由に置換することができます。特に、正規表現に「e」オプションをつけておくと、取り出したテキストにPHPの関数のフィルタをかけることもできるので、かなり細かい処理を行うことができます。

// リンクの置換(簡易版)
$text = "aaaabbbb http://oto.chu.jp?x=333&c=%050505 cccc";
$text = preg_replace('@(https?://[a-zA-Z0-9\.\#\&amp;\?\-\_\~\,\/\%\=]+)@e',
  "'<a href=\"\$1\">'.mb_strimwidth('$1',0,8,'..').'</a>'", $text);
echo $text;

上のプログラムは、URLをリンクタグに置換します。その際に、URLが長すぎるとき、文字数を「..」と省略した形にしています。

KonaWikiで正規表現での置換を止めて、1文字ずつ調べていく方法を採用しています。この方法を採用したのは、置換条件が複雑になりすぎたためです。正規表現はただでさえ見づらくなりがちです。正規表現で頑張りすぎると、訳が分からなくなってしまいます。そこで、1文字ずつ確実に置換する方法にしました。ですがこの方法だとかなりプログラムを書かないといけないのが欠点です。正規表現一発で間に合うなら、この方法を採用するのがスマートでしょう。

まとめ

今回は、Wikiパーサの部分に関して解説しました。プログラミング言語(なでしこ等)を開発している私としては、パーサを書くのがとても楽しくて没頭してしまいました。こうした処理を面倒と感じる人は、素直に Pear で用意されているライブラリなどを使うと良いですね。実は、今回の私のブログエントリも、KonaWiki のパーサを用いて、HTMLに変換してみました。次回は、Wikiのページ書き換え処理について書こうと思っています。お楽しみに。

KonaWiki - http://aoikujira.com/wiki/konawiki/

Series Navigation«開発環境のセットアップURLを工夫しよう»

執筆者紹介

クジラ飛行机

クジラ飛行机

くじらはんど(http://kujirahand/)にて、日本語プログラミング言語「なでしこ」(IPA未踏ユース採択)、テキスト音楽「サクラ」(OSPオンラインソフト大賞入賞)など多くのオンラインソフトを開発。著書に「Flexプロフェッショナルガイド」「なでしこ公式バイブル」、「一週間でマスターするActionScript3.0」など。

TrackBack URL :