XMLフロンティア探訪
第8回 XHTMLモジュールを利用した言語開発
(前編)

川俣 晶
株式会社ピーデー
2002/1/8

今回の主な内容
A君と報告書作成言語
XMLで新しい言語を作る
新しい言語を作る難しさ
既存の言語を利用できないか
モジュールを取り入れる
XHTMLのモジュール
属性のコレクション
要素のコレクション

A君と報告書記述言語

 ある日、A君は上司から呼び出された。A君の会社では情報システムを構築中なのだが、そこで問題が起きたという。ある報告書を入力するシステムと、それを処理するシステムの開発業者が違っていて、意思の疎通がうまくいっていないという。

 報告書は長期保存するものなので、この際XMLで報告書の記述言語を作って、それを共通言語としてデータをやりとりし、保存するようにしたらどうかと上司は考えた。しかし、開発業者の方は社内慣習をよく知らないので、言語は作れないという。そこで、A君にお鉢が回ってきたというわけだ。しかし、A君はXMLのベテランというわけではない。にもかかわらず、A君はほんの1週間でXMLによる言語を作り上げ、みんなが納得するような成果を挙げた。果たして、A君はどんなマジックを使ったのだろうか。

 このようなモデルケースを想定して、A君が使った方法とはいかなるものかを、具体的に実践できるように解説したいと思う。ポイントとなるキーワードはモジュールである。とはいえ、具体的にA君のやったことの説明まで今回1回だけの説明ではたどり着けないので、そこは次回にご期待いただきたい。今回は、A君がやることになる作業を理解するための知識の解説である。

XMLで新しい言語を作る

 XMLの世界には、新しい言語を作り出す、という事例がたくさんある。XMLが「言語を作る言語」(メタ言語)である以上、これは当然の成り行きといえる。中でも、マスコミで話題になるような重要な分野での新しい言語は、複数の人物や組織が関係する場面で利用されることを意図して標準化される場合が多い。そのような言語であれば開発のためにそれなりの人材や予算が投入され、新しい言語が生まれてくることだろう。

 こうした言語の一方で、そうではない言語もある。これは、大した社会的影響力のない言語であったり、特定の組織内だけで利用する言語だったりする。場合によっては、特定のアプリケーションソフトでのみ利用され、そのソフトの開発者しか内容を知らない言語というものも存在する。マスコミで取り上げられる言語と、取り上げられない言語の数を比較すれば、おそらく後者の方が圧倒的大多数だろう。

 この分類で重要なことがもう一点ある。マスコミに取り上げられない種類の言語の多くは、開発されるとしても、そこに投入される人材や予算は限られたものになるだろう。十分な知識を持った人材がそれに当たるとは限らないし、潤沢な予算もないだろう。

新しい言語を作る難しさ

 言語を作るという作業は、XMLにおいては以下のような作業を行うことをいう。

  1. 要素や属性の名前や意味を決定する
  2. 要素や属性の正しい並び順を決定する
  3. 要素や属性が所属する名前空間を決定する
  4. スキーマを記述する
  5. 仕様書を執筆する

 この中で一見、4番目が最も難しい作業のように思えるかもしれないが、実はそうではない。技術者なら5番目が苦手という人もいるだろうが、これも真の苦労のうちには入らない。実は、1番目と2番目の作業がとてつもなく難しいのだ。これらの作業は一見、専門家でなくてもできそうな気がするかもしれないが、簡単そうな見掛けにこそ落とし穴がある。

 例えば、人間の子どもを表す<子供>要素というのがあったとき、それは常に<親>要素の子要素になると考えるのは常識的な判断だろう。どう考えても、子どもは親がいないと生まれないのだから、この定義で何の問題も起きないように思えるかもしれない。ところが実際の子どもには、親に関する情報が不明というケースもある。このような構造だと、親の情報は不明のまま、取りあえず子どものデータを入力しておくということができない。

 このような、運用して初めて気付く「言語の問題点」というものがあちこちに地雷のように潜むのが、言語作りの難しいところなのだ。これに比べれば、スキーマや仕様書を書くというのは専門のノウハウが必要になるとしても、学べば済む問題である。しかし、地雷型の問題点は、「このノウハウさえ学べば完璧に回避できる」という良策がない。

既存の言語を利用できないか

 このような問題を回避する1つの方法は、新しい言語を作る代わりに、実績ある既存の言語を利用することである。しかし、既存の言語で済むぐらいなら最初から言語の新規作成などしないだろう。既存の言語がそのまま使えないからこそ、新しい言語が必要とされるのだ。だが、そこであきらめるのは早い。新しく作られる言語に含まれる個々の機能については、既存の言語がすでに備えている可能性が高いのだ。それを利用すればよい。

 そこで、既存言語の仕様書にある要素や属性と同じものを、自分の言語にも入れることを考えてみよう。実際に、このように考える人は多いようで、独自の言語の中に、HTMLで見たような要素や属性が並んでいるものを実際に見掛けることがある。しかし、このアイデアが万全だというわけではない。

 例えば、HTMLでパラグラフを表現する<p>要素を自分の言語にも入れようとするケースでも、HTMLの仕様書から<p>要素の定義をそのままコピーして自分の仕様書に持ってきているかというと、必ずしもそうではない。その代わり、<p>要素についての定義や説明を、自分の言葉で書いてしまっているのだ。この段階で、オリジナルの<p>要素は似て非なるものになることが多い。また名前空間も自分で新しいものを割り当ててしまう場合がある。

 このように作られた独自の言語が増えていくと、一見同じように見えるが厳密には同じではない<p>要素がいくつも生まれてしまう。そうなると、XHTMLの<p>要素を処理するライブラリがあったとしても、厳密に同じではないのでそれらの言語には使えないし、さまざまな言語で書かれたデータ処理を自動化しようとしても、似て非なる<p>要素を何種類も受け付けなければならず、容易には処理を一本化できなくなる。

 このような問題を解決するには、独自の<p>要素を作る、という行為をやめる必要がある。その代わりに、「この言語では、XHTMLの<p>要素を流用する」ということをはっきりと示せばいい。パラグラフによる表現を必要とするすべての言語が、XHTMLの<p>要素を利用していれば、この要素の処理はどんな言語でデータを受け取った場合でも、一元化できることになる。

モジュールを取り入れる

 そこで問題になるのは、XHTMLの中の<p>要素だけを自分の独自言語の中で使いたい、というような限定的な利用方法を、XHTML側が許しているかということだ。その答えは、イエスでもありノーでもある。<p>要素だけの利用は許していないが、部分利用する方法は明確に示されている。実は、XHTMLは、「Modularization of XHTML」という仕様書により、部分利用可能な部分に区切られている。この部分をモジュールという。<p>要素はテキストモジュールに属しているので、テキストモジュールを利用するという選択が可能だ。そして、テキストモジュールだけを取り込めば、そこに属さないXHMLの画像やテーブルの機能までは取り込まない。

 このような方法で、世の中に存在する使えるモジュールをかき集めて言語を作れば、似て非なる要素を作り出してしまうリスクを軽減できるだけではない。何より、時間の節約にもなるし、予算も少なくて済む。しかし、時間や予算が節約できるからといって、手抜きをするための方法というわけでもない。手抜きどころか、この方が良い結果をもたらすのである。すべてを自分で作ろうとするよりも、既存のモジュールを活用する方が、ずっと好ましい結果を生むのである。

 ということで、XHTMLのモジュールとは何か、どうやって利用するのかを解説していこう。

XHTMLのモジュール

 まずは、便利なモジュールの宝庫であるModularization of XHTMLから見てみよう。具体的にどんな要素や属性が、モジュールになっているかを見ておけば、いつか役に立つだろう。

属性のコレクション

 その前に、解説しておくべきものがある。それは、属性のコレクション(Attribute Collections)である。それぞれのモジュールは共通に定義される属性のコレクションを参照する。以下が一覧表である。 各表のタイトルには、W3Cの該当Webページへのリンクを張っておいたので、正確な仕様はそちらを参照いただきたい。

Attribute Collections
  • Core:class、id、title
  • I18N:xml:lang
  • Events:onclick、ondblclick、onmousedown、onmouseup、onmouseover、onmousemove、onmouseout、onkeypress、onkeydown、onkeyup
  • Style:style
  • Common:(Core + Events + I18N + Style)

 Coreという名前のコレクションには、class、 id、titleの3種類の属性が含まれる。後のリストで属性としてCoreを使用できるというときには、Coreという名前の属性が使用できるのではなく、この3種類の属性が使用できることを意味する。

 なお、EventsコレクションはIntrinsic Events Moduleが使用されたときのみ定義される。StyleコレクションはStyle Attribute Moduleが使用されたときのみ定義される。

要素のコレクション

 さて、ここでは、それぞれのモジュールにどのような要素と属性があるかを紹介するわけだが、これはModularization of XHTMLの5章の表から主要な情報を取り出して要約したものだ。ここでは、要素と属性についてまとめてあるが、元の仕様書には、このほかに内容モデルについても表で記載されている。実際に利用する場合は、それも参照していただきたい。

 以下の要素のリストは、先頭が要素名で、それに続く名前が属性または属性のコレクションの名前である。

Structure Module
  • body:Common
  • head:I18N、profile (URI)、title
  • html:I18N、version (CDATA)、xmlns (URI = "http://www.w3.org/1999/xhtml") 、head、body
  • title:I18N、PCDATA

 最初のモジュールは、XHTML文書の全体の構造を記述するためのStructure Moduleである。おなじみのbodyやheadなどが含まれている。これらの要素は必須のように思われるかもしれないが、全体の構造がXHTMLと大きく食い違う場合、このモジュールを使わず、別の要素を使うという選択もあり得るのである。

Text Module
  • abbr:Common
  • acronym:Common
  • address:Common
  • blockquote:Common、cite (URI)
  • br:Core
  • cite:Common
  • code:Common
  • dfn:Common
  • div:Common
  • em:Common
  • h1:Common
  • h2:Common
  • h3:Common
  • h4:Common
  • h5:Common
  • h6:Common
  • kbd:Common
  • p:Common
  • pre:Common、xml:space="preserve"
  • q:Common、cite (URI)
  • samp:Common
  • span:Common
  • strong:Common
  • var:Common

 Text Moduleは文字に関する基本的な要素を集めたものだ。strong要素のような文字の強調や、<p>要素のような段落の表現はよく必要とされるので、このモジュールを使う機会は多いだろう。このモジュールに属する要素はいくつかに分類できる。大きく3つに分けることができる。

 1つは、ヘディング(見出し)用要素。h1、h2、h3、h4、h5、h6がこれに当たる。これらは見出しを記述するために使用する。見出しはスタイルシートで目立つ特別な外見を与えられたり、見出しだけを抽出して目次を生成したりするために使われる。

 次は、ブロック要素である。address、blockquote、div、p、preがこれに当たる。これらは、文章の一塊りを表現する要素である。いくつかの(1行以上の)行の集まりがブロックと要素と考えてもよいだろう。つまり、同じ行の中に複数のブロック要素が同居することはできない。

 最後は、インライン要素である。abbr、acronym、br、cite、code、dfn、em、kbd、q、samp、span、strong、varがこれに当たる。これは1行の中の一部に適用するもので、強調する単語を指定するなどの目的で使う。つまり、インライン要素は、ブロック要素の子要素(あるいは間接的な子孫)として使うのが、最も基本的である。

 実際にこのモジュールを使うときには、ブロック要素やインライン要素がこれだけということはあまりなく、独自にブロック要素やインライン要素を増やしていく必要に迫られることもある。つまり、このモジュールを使うといっても、これがすべてというわけではない。

Hypertext Module

  • a:Common、accesskey (Character)、charset (Charset)、href (URI)、hreflang (LanguageCode)、rel (LinkTypes)、rev (LinkTypes)、tabindex (Number)、type (ContentType)

 たった1つの要素しか含まれていないが、かなり重要度の高いモジュールである。Hypertext Moduleは、おなじみのハイパーリンクを実現するa要素を含む。主にインターネット上のほかのリソースを参照する機能を自分の言語に取り込みたいときは、このモジュールを取り込めばよい。文書系の言語でない場合はText Moduleは使わないが、Hypertext Moduleだけは利用する、というシチュエーションもあり得るだろう。なお、外部リソースの参照でも、画像をインラインに表示させたい場合は、後述のImage Moduleの方を使う。

List Module

  • dl:Common
  • dt:Common
  • dd:Common
  • ol:Common
  • ul:Common
  • li:Common

 リストを扱う機能を集めたものである。一覧表を規則的な形にまとめる必要があるときに活用できるだろう。

Applet Module

  • applet:Core、alt* (Text)、archive (CDATA)、code (CDATA)、codebase (URI)、height* (Length)、object (CDATA)、width* (Length)
  • param:id (ID)、name* (CDATA)、type (ContentType)、value (CDATA)、valuetype ("data"* | "ref" | "object")

 外部アプリケーション、より具体的にいえばJava Appletなどを参照する機能を実現するモジュールである。静的な報告書のようなものだけを扱うなら、なくても構わないものといえる。そういう場合は、このモジュールを取り去ってしまうと対応プログラムの開発が楽になる。

Presentation Module

  • b:Common
  • big:Common
  • hr:Common
  • i:Common
  • small:Common
  • sub:Common
  • sup:Common
  • tt:Common

 基本的な、文書の体裁を表記するためのモジュールである。hr要素はブロックの区切りになるものだが、subなどはインライン要素の一種ということになる。

Edit Module

  • del:Common、cite (URI)、datetime (Datetime)
  • ins:Common、cite (URI)、datetime (Datetime)

 編集による追加や削除を表現するモジュールである。必要な場合には必要だが、必要がないときは必要のないモジュールなので、まさに必要に応じて選択するのにふさわしいといえるだろう。

Bi-directional Text Module

  • bdo:Core、dir* ("ltr" | "rtl")

 アラビア語のように双方向に記述する言語で、記述する向きを指定するモジュールである。絶対に日本語しか使わないなら、外してしまうこともできる。

Basic Forms Module
  • form:Common、action* (URI)、method ("get"* | "post")、enctype (ContentType)
  • input:Common、accesskey (Character)、checked ("checked")、maxlength (Number)、name (CDATA)、size (Number)、src (URI)、type ("text"* | "password" | "checkbox" | "radio" | "submit" | "reset" | "hidden" )、value (CDATA)
  • label:Common、accesskey (Character)、for (IDREF)
  • select:Common、multiple ("multiple")、name (CDATA)、size (Number)
  • option:Common、selected ("selected")、value (CDATA)
  • textarea:Common、accesskey (Character)、cols* (Number)、name (CDATA)、 rows* (Number)

 基本的な、入力フォームを記述するための機能を持つモジュール。例えば、報告書記述言語のような静的な文書のための言語なら、このような対話的機能はいらないだろう。

Forms Module
  • form:Common、accept (ContentTypes)、accept-charset (Charsets)、action* (URI)、method ("get"* | "post")、enctype (ContentType)
  • input:Common、accept (ContentTypes)、accesskey (Character)、alt (CDATA)、 checked ("checked")、disabled ("disabled")、maxlength (Number)、name (CDATA)、readonly ("readonly")、size (Number)、src (URI)、tabindex (Number)、 type ("text"* | "password" | "checkbox" | "button" | "radio" | "submit" | "reset" | "file" | "hidden" | "image")、value (CDATA)
  • select:Common、disabled ("disabled")、multiple ("multiple")、name (CDATA)、size (Number)、tabindex (Number)
  • option:Common、disabled ("disabled")、label (Text)、selected ("selected")、value (CDATA)
  • textarea:Common、accesskey (Character)、cols* (Number)、disabled ("disabled")、name (CDATA)、readonly ("readonly")、rows* (Number)、tabindex (Number)
  • button:Common、accesskey (Character)、disabled ("disabled")、name (CDATA)、tabindex (Number)、type ("button" | "submit"* | "reset")、value (CDATA)
  • fieldset:Common
  • label:Common、accesskey (Character)、for (IDREF)
  • legend:Common、accesskey (Character)
  • optgroup:Common、disabled ("disabled")、label* (Text)

 本格的な入力フォームを記述するための機能を持つモジュール。見て分かるとおり、目的はBasic Forms Moduleと同じだが、機能ははるかに充実している。Forms Moduleは、Basic Forms Moduleのスーパーセットであり、上位版と考えられる。Basic Forms ModuleとForms Moduleを両方同時に使う意味はないので、必要に応じてどちらかを使うとよいだろう。

Basic Tables Module
  • caption:Common
  • table:Common 、summary (Text)、width (Length)
  • td:Common、abbr (Text)、align ("left" | "center" | "right")、axis (CDATA)、colspan (Number)、headers (IDREFS)、rowspan (Number)、scope ("row" | "col")、valign ("top" | "middle" | "bottom")
  • th:Common、abbr (Text)、align ("left" | "center" | "right")、axis (CDATA)、colspan (Number)、headers (IDREFS)、rowspan (Number)、scope ("row" | "col" | "rowgroup" | "colgroup")、valign ("top" | "middle" | "bottom")
  • tr:Common、align ("left" | "center" | "right")、valign

 基本的な表(テーブル)を記述するための機能を持つモジュールである。表組みは比較的よく必要とされるが、いざそれを実現するとなると、けっこうややこしいモノである。このモジュールだけ、自作言語の中で使いたい、という場合もあるだろう。

Tables Module
  • caption:Common
  • table:Common、border (Pixels)、cellpadding (Length)、cellspacing (Length)、datapagesize (CDATA)、frame ("void" | "above" | below" | "hsides" | "lhs" | "rhs" | "vsides" | "box" | "border")、rules ("none" | "groups" | "rows" | "cols" | "all")、summary (Text)、width (Length)
  • td:Common、abbr (Text)、align ("left" | "center" | "right" | "justify" | "char")、axis (CDATA)、char (Character)、charoff (Length)、colspan (Number)、headers (IDREFS)、rowspan (Number)、scope ("row","col","rowgroup", "colgroup")、 valign ("top" | "middle" | "bottom" | "baseline")
  • th:Common、abbr (Text)、align ("left" | "center" | "right" | "justify" | "char")、axis (CDATA)、char (Character)、charoff (Length)、colspan (Number)、headers (IDREFS)、rowspan (Number)、scope ("row", "col", "rowgroup", "colgroup")、valign ("top" | "middle" | "bottom" | "baseline")
  • tr:Common、align ("left" | "center" | "right" | "justify", "char")、 char (Character)、charoff (Length)、valign ("top" | "middle" | "bottom" | "baseline")
  • col:Common、align ("left" | "center" | "right" | "justify", "char")、 char (Character)、charoff (Length)、span (Number)、valign ("top" | "middle" | "bottom" | "baseline")、width (MultiLength)
  • colgroup:Common、align ("left" | "center" | "right" | "justify", "char")、char (Character)、charoff (Length)、span (Number)、valign ("top" | "middle" | "bottom" | "baseline")、width (MultiLength)
  • tbody:Common、align ("left" | "center" | "right" | "justify", "char")、char (Character)、charoff (Length)、valign ("top" | "middle" | "bottom" | "baseline")
  • thead:Common、align ("left" | "center" | "right" | "justify", "char")、char (Character)、charoff (Length)、valign ("top" | "middle" | "bottom" | "baseline")
  • tfoot:Common、align ("left" | "center" | "right" | "justify", "char")、char (Character)、charoff (Length)、valign ("top" | "middle" | "bottom" | "baseline")

 高度な表(テーブル)を記述するための機能を持つモジュールである。Tables ModuleとBasic Tables Moduleの関係は、すでに説明したForms ModuleとBasic Forms Moduleの関係と同じで、どちらか一方を必要に応じて選ぶべきものである。

 というわけで、XHTMLのモジュールを見たところで、次回に続く。請うご期待である。

 

「連載 XMLフロンティア探訪」


XML & SOA フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日月間