この文書「文書型定義(DTD)とその設計」は、1998年に書かれた雑誌記事の原稿です。HTMLファイルは(タイムスタンプを見る限り)1999年に作成されたようです。かなりの期間サイエンス社のWebサイトで公開されていましたが、現在はWeb上に見あたらないようです。そこで、キマイラ・サイトで公開を続けることにしました。
当時の檜山のメールアドレスと、本文中に不自然に含まれていた空白を削除した以外は、文面もマークアップも一切変更していません。リンクは無効なものが多いでしょう。図版(画像)は紛失しています。もとの雑誌からスキャンすることは可能ですが、その雑誌がどうも見つからないのです(苦笑)。もし見つかれば図版を補うつもりです。
この文書の最後のほうに、パラメータ実体を使ったDTDの例がありますが、必要なら、実際の事例「SMIL 1.0のモジュラー化DTD」も参照してください。(Wed Jun 28 2006:檜山)
これは、『Computer Todday』1998年9月号の記事「文書型定義(DTD)とその設計」のオリジナル原稿をHTML化したものです。『Computer Todday』に掲載された記事は、この原稿の一部を削除し、若干の編集上の修正を加えたものです。
この文書(ページ)では、次のHTML機能を使用しています。
以上の機能をサポートしてない(または実装が不完全な)ブラウザでは、表示上の不具合が生じる可能性があります。
量的な問題で、雑誌掲載時にこの原稿から削除された部分は、(CSSが正常に機能すれば) 濃いブルーで表示されます。また、その前後に水平罫線を入れて区切ってあります。
SGML/XMLにおけるDTD(Document Type Definition)の重要性はしばしば指摘される。それにもかかわらず、DTD設計者の仕事が「文書の論理構造を正規表現で書き下すこと」という程度にしか理解されてないフシがある。もちろんそんなわけはなく、参考文献[1]にも述べられているように、調査、分析、交渉、啓蒙、教育などにもDTD設計者が関わらざるを得ない。
本稿では、話が散漫にならないように、DTD設計とシステム設計との関係を中心に述べる。このため、プログラミング寄りの話が多いような印象を持たれるかもしれないが、システムに対するある程度の理解は、DTD設計の(多数ある)基礎教養のひとつである。他にも関連する分野は多岐に渡るが、最後に項目を挙げるのみ、あるいはまったく触れられない話題も多い。宣言を書き並べることは、DTD設計の微々たる一片であることを注意したい。
このリレー連載がはじまって数ヶ月。この短い期間でXML(*1)は急速に認知され、相対的にSGMLフルセットの重要性は減っている。このような状況を考慮して、この記事では、XMLにおける文書型設計に話題をしぼる(それでも、ほとんどの事項はSGMLにも通用する)。SGMLベースの著名なDTDである、TEI(*2)、DocBook(*3)、CALS(*4)(特にtable)などは相変わらず重要だし、それらを素材に文書型設計手法を学習するのは無駄ではない。しかし、一部のSGML機能はXMLでは使えなくなっているし、ISO 12083(*5)のように、古典的な出版モデルに依拠したDTDは、現在の環境では適用が困難となっている(図1 )。そこで、目線をもっぱら現在から将来に向けて、今後の文書型設計のスタンスについて語りたい。
*1 XML :XMLについては、本誌1998年5月号の村田氏の記事を参照。
*2 TEI(Text Encoding Initiative) : 文学作品なども含め、広範囲な文献をSGML化することを意図したプロジェクト。そのために、大規模なDTDが準備された。(TEIホームページ)
*3 DocBook : コンピュータ書籍の出版社であるO'Reilly Associates を中心に開発された、書籍やマニュアル向けのDTD。(DocBookホームページ)
*4 CALS : アメリカ国防省が開始し、その後、商務省管轄に移った国家プロジェクト。ネットワークとコンピュータ技術を使ったの産業構造の改革を目指すもので、その文書技術としてSGMLが採用された。軍や産業界で使われる典型的文書のDTDも準備された。特に表(table)DTDは有名。(CALSホームページ)
*5 ISO 12083 : アメリカ出版協会のDTDをベースとして、ISO規格となったDTD。伝統的な紙の書籍を対象としている。
また、この記事では、文書型やDTDの導入的な解説は割愛する。幸いにも、最近では日本語で読めるXMLの本(参考文献[2])も出版され、DTDの初歩的説明はそれらを参照できる。私も、雑誌でDTD入門を数ページにまとめたことがある(参考文献[3])。ここでは、実際にDTDを読んだり変更したり作成する方々に対して、いくつかの注意とヒントを述べる。それらの事項は、プロジェクト管理者、ソフトウェアやシステムの設計者にも有用な情報のはずだ。
このような執筆方針は、この記事の読者を減らしてしまう危惧がある。だが、DTDとその設計に対する認識不足、あるいは誤った認識を是正するほうが緊急の課題であるので、読者および編集部にはご肝要を願いたい。とはいえ、いくぶん類推を働かせれば、少ない予備知識でも読み通せるように気を配ったつもりである。どうか、お読みいただきたい。そして、進行中および将来の計画において、システム構築・運用上の問題が発生しないように、DTD設計を再検討していただきたい。
目次へまず、文書という言葉をきわめて広い意味で解釈することを注意しておく。ワープロで書くような普通の文書に限らず、構造をもつデジタルデータはなんであれ文書と呼ぶ。
文書がSGML/XMLの形式で表現されると、それは、入れ子になった要素の木構造に編成される。この木構造のどこに、どんな情報項目を配置すべきかを決定することが、文書型設計の主題といってよいだろう(図2)。木を構成する1つの要素を取ってみても、情報項目を入れる場所として、内容と属性がある。これらの場所(スロット)をどう利用すべきだろうか。
例として次の情報を考えよう(*6)。
名前: 大津健一 性別: 男 年齢: 27歳
*6 : データベースの場合は、年齢を項目とするのは非常にまずい設計である。この例は、新聞記事の人名表記などを想定していただきたい。
この情報をXML要素で表す方法は色々ある。いくつか挙げてみよう(例1)。それぞれに対応するDTD宣言はリスト1にまとめた。
<person> <name>大津健一</name> <sex>男</sex> <age>27歳</age> </person>
<person name="大津健一" sex="MALE" age="27" />
<person> <name>大津健一</name> <sex value="MALE"/> <age value="27"/> </person>
<person sex-age="MALE 27">大津健一</person>
<person>大津健一,男,27歳 </person>
例1-1、例1-2、例1-3では、内容または属性値から直接に情報項目を取り出せる。例1−4では、属性値をトークンに分離して、性別と年齢を取り出す。例1-5のように、字句的(レキシカル)パターンに頼るのも悪くはない。簡単な字句処理により、情報項目を分離抽出できる。
他にも表現法はいくらもあるし、タグ名(要素型名、共通識別子)や属性名の選び方まで考えると無数のバリエーションがある。
<!-- 例1-1 --> <!ELEMENT person (name, sex, age)> <!ELEMENT name (#PCDATA)> <!ELEMENT sex (#PCDATA)> <!ELEMENT age (#PCDATA)>
<!-- 例1-2 --> <!ELEMENT person EMPTY> <!ATTLIST person name CDATA #REQUIRED sex (MALE|FEMALE) #REQUIRED age NMTOKEN #REQUIRED >
<!-- 例1-3 --> <!ELEMENT person (name, sex, age)> <!ELEMENT name (#PCDATA)> <!ELEMENT sex EMPTY> <!ATTLIST sex value (MALE|FEMALE) #REQUIRED > <!ELEMENT age EMPTY> <!ATTLIST age value NMTOKEN #REQUIRED >
<!-- 例1-4 --> <!ELEMENT person (#PCDATA)> <!ATTLIST person sex-age NMTOKENS #REQUIRED > <!-- ただし、sex-ageの第1トークンはMALEかFEMALE、 第2トークンは数値 -->
<!-- 例1-5 --> <!ELEMENT person (#PCDATA)> <!-- ただし、名前、性別、年齢をカンマで区切る。 内容文字列のパターンは、 (人名文字列+, ",", ("男"|"女"), ",", 数字+, "歳") -->
以上の簡単な例からも、いくつかの教訓が得られる。すぐにわかることは、表現すべき情報項目が定まっていても、具体的な表現形式には任意性が残ることだ。仮に重要な理由(例えば処理系の都合など)があっても、論理的な構造表現の観点からは優劣が付けられない多様な変形がある。最良の選択があるとすれば、それは、処理システムや運用環境、利用者集団、規格・業界標準や他のDTDとの関連などを考慮した上でのことなのだ。つまり、文書が持つ論理構造がとりあえず写し取れた程度のDTDでは、実用的な利用には不安が残る。
また、DTDでは、抽象データ型を表現できないことに注意しよう。プログラミングにおいては、実際のプログラムコードでアルゴリズムを記述する部分は実装(インプリメンテーション)と呼び、外部からその機能を利用する際の作法はインターフェースと呼ばれる。DTDは、どちらかというと実装、つまり具体的な表現形式を定義するものであり、データアクセスのインターフェースを十分抽象的には記述できない。だから、DTDと共に、抽象データ型を想定したり、 他の表記方法を用いてインターフェースを記述しておく必要もある(図3)。
もちろん、DTDは処理プログラム(保存、転送、表示・印刷、検索、加工など)のことばかり考えているわけにはいかない。人間が情報や構造をどう認識しているかにも思いをはせる必要がある (*7) 。ユーザーインターフェースも重要な問題だ。より正確に言えば、ユーザー(人間)の相手をするプログラムであるユーザーエージェント(たとえばブラウザ)を考慮すると共に、人間に対する解説書やヘルプなどのドキュメンテーションも準備せねばならない。
*7 : 人間が一切介在しない応用もある。例えば、計測器と分析装置の間のプロトコルにXMLを使う場合、人間に対する配慮はあまり必要ないだろう。
"文書と処理プログラムとのインターフェース"、"文書とユーザーエージェントとのインターフェース"、"文書とユーザーそのもの(人間)とのインターフェース"が、いずれもDTDを中心として派生していく(図4)。
ユーザーへの配慮の延長として、利用者集団の文書文化やオーサリングのリテラシー、データ互換性なども視点に入れる必要がある。論理的・技術的な判断と共に、ときには政治的、戦略的な判断・決定さえもDTDに盛り込まれることがある。
目次へ「プログラム」と「人間」、DTDはこの2つの側面を考慮してバランスをとる必要がある。本稿ではプログラムとDTDの関連に焦点をあてる。文学作品の分析手段に使うような特別な例を除けば、DTDはソフトウェアシステムにより運用される。DTDは、文書とシステムのインターフェースを規定することになる。
「DTDはプログラムやシステムから独立であるべきである」とは、まったくそのとおりなのだが、だからといって、プログラムに対するインターフェースを提示しなくてよいことにはならない。特定の実装に依存することが好ましくないのであって、一般的なプログラミングインターフェースは必要である。現実問題としては、許されたコストと時間でシステムを実現する要求があるのだから、「システムから独立したDTD」は書きにくい。システムの構造や制約に影響を受けるのは、いたしかたないことだ。DTDだけが理想を求めると、処理システムの設計者はひどく苦しむことになり、最悪の場合はシステムが実現不可能となる。無理をした歪んだ実装は、ユーザーに多大な迷惑をかける。
プログラマがDTDをどのように参照するかを簡単な例で見よう。いま、文書のタイトル(TITLE要素)を取り出したいとしよう。リスト2-1のDTDのもとでは、単純に、"最初の要素の最初の子要素"を抽出すればよい。リスト2-2のDTDでは、最初の要素がHEADであるかどうかを確認し、HEADの子要素を調べ上げなくてはならない。リスト3はJavaScriptによるプログラム例だが、DTDが保証してくれる構造によりアクセス方法が変わることがわかるだろう。例3-2のDTDでは、HEAD中の TITLE、AUTHOR, DATEを、自由に省略し好きな順序で記述してよいから、文書を書くほうは気楽でよい。が、その分、プログラムは注意深く作らねばならない。
<!-- 例2-1 --> <!ELEMENT DOC (HEAD, BODY)> <!ELEMENT HEAD (TITLE, AUTHOR, DATE)> <!ELEMENT TITLE (#PCDATA)> ... (以下省略) ...
<!-- 例2-2 --> <!ELEMENT DOC (HEAD?, BODY)> <!ELEMENT HEAD ( (TITLE?, AUTHOR?, DATE?) | (TITLE?, DATE?, AUTHOR?) | (AUTHOR?, TITLE?, DATE?) | (AUTHOR?, DATE?, TITLE?) | (DATE?, TITLE?, AUTHOR?) | (DATE?, AUTHOR?, TITLE?) ) > <!ELEMENT TITLE (#PCDATA)> ... (以下省略) ...
// 例2-1のDTDを前提とする // docは文書のルート要素だとする head = doc.children.item(0); title = head.children.item(0); // titleにタイトル要素が必ず入る
// 例2-2のDTDを前提とする // docは文書のルート要素だとする title = null; firstChild = doc.children.item(0); if (firstChild.tagName == "HEAD") { elements = firstChild.children; for (i = 0; i < elements.length; i++) { x = elements.item(i); if (x.tagName == "TITLE") { title = x; } } } // タイトル要素があればtitleに入る、なければnull
DTD設計者は、各情報項目へのアクセス手順を想定し、その処理負荷があまりに大き過ぎたりアクセス不可能となることがないように注意すべきである。もちろん、アクセス容易性と、オーサリング(文書生成)の自由度・柔軟さはトレードオフの関係にある。うまくバランス点を見いださなくてはならない。
目次へXML文書から編成されるツリー状データ構造は、XML文書オブジェクトモデル(DOM: Document Object Model) として定義されつつある。現時点(1998年6月) では、DOMの先行きは不透明だが、いずれにしてもXML文書が木の形になることに変わりはない。木やその部分をオブジェクトとみなして、次のようなメソッドにより必要な情報にアクセスすることになる。
このようなアクセッサ(あるいは、リーダブルなプロパティ)は、一般的な共通プリミティブを提供するだけで、文書型やシステムに固有な状況は表現できない。
特定応用目的のアクセッサの例として、文書管理を行うサブシステム(システム全体のなかで管理機能を担う部分)を考えよう。この文書管理サブシステムは、*8 : この形のインターフェースでは、アクセッサがvalidな値を返すことが必須かどうかが明確でない。validでないときはnullを返すとか、例外を投げる(throws exception)などの規約を決める必要がある。
interface ManagableDocument { /* 文書IDの命名方式を表す定数 */ int RCS_ID = 0; // Revision Control System int SCCS_ID = 1; // Source Code Control System int UUID_ID = 2; // Universally Unique Identifier int MANUAL_ID = 3; // 人手で適宜付けたID /* 状態を表す定数 */ int DRAFT_STATUS = 0; // 草稿 int ON_REVIEW_STATUS = 1; // レビュー中 int FINAL_STATUS = 2; // 完了 /* アクセッサメソッド */ String getDocumentID(); // 文書ID int getDocumentIDNamingScheme(); // 文書ID命名方式 String getDocumentTitle(); // タイトル int getDocumentStatus(); // 状態 }
文書管理サブシステムは、文書を、このインターフェースを介して見ることになる。サブシステムの管理対象となる文書オブジェクトのクラスは、これらのインターフェースをインプリメントする必要があり、そのインプリメンテーションはDTDに依存する。たとえば、リスト5のDTDのもとでは、getDocumentIDNamingScheme()のインプリメンテーションはリスト6のようになる。
<!ELEMENT DOC (HEAD, BODY)> <!ATTLIST DOC status (DRAFT|ON_REVIEW|FINAL) #REQUIRED > <!ELEMENT HEAD (DOC-ID, TITLE, AUTHOR?, DATE?)> <!ELEMENT DOC-ID (#PCDATA)> <!ATTLIST DOC-ID naming-scheme (RCS|SCCS|UUID|MANUAL) 'RCS' > ... (省略) ...
class MyDocument extends TXDocument implements ManagableDocument { ... (省略) ... public int getDocumentIDNamingScheme() { // 文書要素(ルート)を得る Element doc = getDocumentElement(); // ルートの最初の子 Node firstChild = doc.getChildNodes().toFirstNode(); // 最初の子の最初の子 Node firstChildOfFirstChild = firstChild.getChildNodes().toFirstNode(); // それは DOC-ID要素であり、naming-scheme属性を持つ Element docId = (Element)firstChildOfFirstChild; String docIdSchemeName = docId.getAttribute("naming-scheme"); // naming-scheme属性値を整数値に変換して返す int docIdSchemeVal = -1; if (docIdSchemeName.equals("RCS")) { docIdSchemeVal = RCS_ID; } else if (docIdSchemeName.equals("SCCS")) { docIdSchemeVal = SCCS_ID; } else if (docIdSchemeName.equals("UUID")) { docIdSchemeVal = UUID_ID; } else if (docIdSchemeName.equals("MANUAL")) { docIdSchemeVal = MANUAL_ID; } return docIdSchemeVal; } ... (省略) ... }
上記文書管理サブシステムの例で紹介した方法では、文書インスタンスの構造をサブシステム要件にマップするために、アクセッサが使われる(図5)。処理対象文書の文書型の違いは、アクセッサセットを変更することにより吸収できる。同じサブシステムをいくつかの文書型(のインスタンス群)に適用可能だ。(図6)。
*9 : アーキテクチャ形式(architectural form)に関しては、この連載の今郷氏の記事「8. SGML関連規格 - HyTime - 」(1998年7月号)に、メタDTDとして説明されている。今郷氏、そして他の多くの著者も、"architecture"に「体系」という訳語をあてているが、私は(個人的な感覚の問題だが)どうしてもなじめないので、「アーキテクチャ」を使用した。
文書管理サブシステムの例題をアーキテクチャ形式で記述してみよう(とはいっても、アーキテクチャ形式の正確な定義を述べる紙幅がないのだが)。まず、文書管理エンジンは、リスト8のDTDで規定されるインスタンスを入力とする。この入力インスタンス(リスト9はその例)は、文書管理エンジンが興味を持つ要素(表1)しか含まず、必要な項目へのアクセスは自明である。
文書の状態 | ドラフト、レビュー中、完成のいずれか。 |
文書ID | 文書を識別する番号や名前。バージョン管理システムや人手で付与される。 |
文書IDの命名方式 | 文書IDがどんな方式で命名されているか。 |
題名 | その文書を的確に表す文字列。 |
<!ELEMENT DOC (HEAD) > <!ATTLIST DOC status (DRAFT|ON_REVIEW|FINAL) #REQUIRED > <!ELEMENT HEAD (DOC-ID, TITLE)> <!ELEMENT DOC-ID (#PCDATA)> <!ATTLIST DOC-ID naming-scheme (RCS|SCCS|UUID|MANUAL) #REQUIRED > <!ELEMENT TITLE (#PCDATA)>
<DOC status="DRAFT"> <HEAD> <DOC-ID naming-scheme="UUID"> 0cc0da40-09bd-11d2-b5e5-00609778c9fa </DOC-ID> <TITLE>文書型定義(DTD)とその設計</TITL> </HEAD> </DOC>
文書管理エンジンのために、一般のインスタンスを再編成してあげる汎用プログラムがアーキテクチャプロセッサ (*10) である。アーキテクチャプロセッサは、特定の属性に注目してこの仕事を行う。たとえば次のような手順となる。
<!-- 文書管理(DocMan)アーキテクチャに適合するDTDのための ガイドライン --> <!ELEMENT DOC的要素 (他の要素*, HEAD的要素, 他の要素*) > <!ATTLIST DOC的要素 DocMan NMTOKEN #FIXED 'DOC' status (DRAFT|ON_REVIEW|FINAL) #REQUIRED 他の属性 > <!ELEMENT HEAD的要素 (他の要素*, DOC-ID的要素, 他の要素*, TITLE的要素, 他の要素*) > <!ATTLIST HEAD的要素 DocMan NMTOKEN #FIXED 'HEAD' 他の属性 > <!ELEMENT DOC-ID的要素 (#PCDATA)> <!ATTLIST DOC-ID的要素 DocMan NMTOKEN #FIXED 'DOC-ID' naming-scheme (RCS|SCCS|UUID|MANUAL) #REQUIRED 他の属性 > <!ELEMENT TITLE的要素 (#PCDATA)> <!ATTLIST TITLE的要素 DocMan NMTOKEN #FIXED 'TITLE' 他の属性 > <!ELEMENT 他の要素 ANY> <!ATTLIST 他の要素 DocMan (OTHER) #IMPLIED 他の属性 >
一長一短と言える。実のところは、どちらも中途半端なのだ。おそらく、この中間にもっとよい構造記述と変換のクラスが存在するのだろう。木構造の領域に働くオペレータの集合で、(できれば)美しい代数系を構成するものを見い出す試みに期待したい (*11) 。
ともあれ、現代の文書型設計では、具体的なクライアントDTDは、パーサーを動かすために書き下すようもので、本質的な(より概念的ともいえる)構造記述は、インターフェースのパッケージや、アーキテクチャ形式のモジュール(メタDTD)の形で提示すべきである。このような、より強力な記述方法を使ったところで、タグや属性の意味/使用法を記述し切れるわけはないから、自然言語による説明もどうしても必要となる。たとえば、HTML 4.0の仕様書は、(普通にプリントアウトして)コメントが付いたDTDの宣言本体は37ページ、全体では約360ページである。DTD設計の成果物は宣言だけではない。
アクセッサセットとアーキテクチャプロセッサという処理上の概念を今回紹介したのは、それらが、インターフェース定義、アーキテクチャ形式という記述方法の背景だからだ。そして、宣言をならべた狭義のDTDでは表現力が不足なのは明らかなのだから、広義のDTDとして、インターフェース定義やアーキテクチャ形式を積極的に利用することを強くお奨めする。
目次へ分析や概念構成が、DTD設計で大きなウェイトを占めることを述べたが、宣言を書き下すにも、それなりのコツやワザがある。DTD構文では、抽象化やモジュール化がサポートされてないので、トリッキーなこともしなくてはならない。トリックやハックのネタはTEIやDocBookのなかに山ほどある。
コツ、ワザ、トリック、ハックとは言ったが、使える道具はただひとつ。パラメータ実体を使いこなす以外にやれることはない。実際、TEIやDocBookのDTD は、パラメータ実体参照のパーセントまみれになっている。私は、この状況はきわめてマズイと思っている。非力なテキスト置換機能しか提供しないパラメータ実体に頼ることは不健全である。
しかしとはいえ、パラメータ実体以外にまったく手段がないので、DTDの抽象化やモジュール化のためには、(不本意ながら)パラメータ実体を使うしかない。リスト10はパラメータ実体を使った例である。パラメータ実体は単なる文字列で、構文的タイプを持たないが、リスト10では、接尾辞(ピリオドに続く名前) で、パラメータ実体の用法を区別している。
パラメータ実体を多用すれば、一応の抽象化やモジュール化ができるが、多段階の抽象化や徹底したモジュール化はあまりにも煩雑になり、事実上不可能である。パラメータ実体は使える範囲で使って、もっとよい機構の登場を待つしかない。
<?xml encoding = "Shift_JIS" ?> <!-- このDTDのバージョン文字列 --> <!ENTITY % dtd-version.lit "'DOC Mon Jun 22 1998'"> <!-- 略記用のマクロ --> <!ENTITY % DocManForm "DocMan NMTOKEN #FIXED"> <!-- まずユーザーカスタム化ファイルを読み込む --> <!ENTITY % user-customization.mod SYSTEM "custom.mod"> %user-customization.mod; <!-- デフォルトの設定 --> <!-- ブール値スイッチ --> <!ENTITY % strict-header.sw "IGNORE"> <!ENTITY % additional-decls.sw "IGNORE"> <!-- 列挙値、属性デフォルト値 --> <!ENTITY % status.enum.x "" > <!ENTITY % status.enum "DRAFT|ON_REVIEW|FINAL %status.enum.x;" > <!ENTITY % status.dv "#REQUIRED"> <!ENTITY % naming-scheme.enum.x "" > <!ENTITY % naming-scheme.enum "RCS|SCCS|UUID|MANUAL %naming-scheme.enum.x;" > <!ENTITY % naming-scheme.dv "#REQUIRED"> <!-- 共通属性 --> <!ENTITY % xml.attrs " xml:lang CDATA 'ja-JP'" > <!ENTITY % common.attrs.x ""> <!ENTITY % common.attrs " %xml.attrs; id ID #IMPLIED %common.attrs.x;" > <!-- 要素構造の定義 --> <!ELEMENT DOC (HEAD, BODY) > <!ENTITY % DOC.attrs.x ""> <!ATTLIST DOC %DocManForm; 'DOC' status (%status.enum;) %status.dv; dtd-version CDATA #FIXED %dtd-version.lit; %common.attrs; %DOC.attrs.x; > <!ENTITY % HEAD-other-subelements.mx.x ""> <!-- if --> <![%strict-header.sw;[ <!ENTITY % HEAD-other-subelements.mx "AUTHOR, TITLE %HEAD-other-subelements.mx.x;"> ]]><!-- else --> <!ENTITY % HEAD-other-subelements.mx "AUTHOR?, TITLE? %HEAD-other-subelements.mx.x;"> <!-- endif --> <!ELEMENT HEAD (DOC-ID, TITLE, %HEAD-other-subelements.mx;) > <!ENTITY % HEAD.attrs.x ""> <!ATTLIST HEAD %DocManForm; 'HEAD' %common.attrs; %HEAD.attrs.x; > ... (省略) ... <![%additional-decls.sw;[ %additional-decls.mod; ]]>
<?xml encoding = "Shift_JIS" ?> <!ENTITY % strict-header.sw "INCLUDE"> <!ENTITY % additional-decls.sw "INCLUDE"> <!ENTITY % status.enum.x "|PREFINAL" > <!ENTITY % naming-scheme.dv "RCS"> <!ENTITY % common.attrs.x " style CDATA #IMPLIED" > <!ENTITY % DOC.attrs.x " scope (IN_HOUSE|PUBLIC) 'IN_HOUSE'" > <!ENTITY % HEAD-other-subelements.mx.x ", HISTORY"> <!ENTITY % additional-decls.mod SYSTEM "history.mod">
ここで、「そもそもDTDが何を記述・表現しようとしているのか」をあらためて考えてみよう。
SGML/XMLをデータ表現として使うときは、外部実世界(つまり、この世)に存在する実在としての情報構造を写し取ることになる。タグは情報項目を区分し識別するために使われる。この場合は、設計の基本態度は伝統的なデータベーススキーマ設計のときと同じである。比較的フラットな構造を使って、文書内に実在物の代理(サロゲート)を表現したいときは、データベース設計論が参考になる。ただし、完全にデータベース向きの課題をXML技術で解決しようとするのは止めたほうがいい。汎用技術が、特定目的にチューニングされた技術にかなうわけはない。
一方、ふつうに文書と呼ばれているもの、報告書、企画書、論文、マニュアルなどでは、段落、見出し、章・節・項などがタグ付けの対象となる。段落や見出しは、実世界の存在物とは思えない。これらは、文書の記述様式である。国語教育や読み書きの経験で習得され、社会や特定集団内で共有される規範である。この規範を写し取るには、目的の文書文化(読み書きの習慣と形式の総体) のなかに身を置き、経験するしかないだろう。もちろん、「〜文書の書き方」や「文章読本」などで勉強するのも役に立つ。
数式や化学式などの半人工言語をXMLで表現することは、ある面ではやさしいとも言える。なぜなら、数式や化学式は既に形式的な文法を持っている体系だからだ。この文法をXMLに変換すればよい。もっとも、MathML(Mathematical Markup Language)やCML(Chemical Markup Language)の制定に大きな労力がかかっているところを見ると、「やさしい」というのも相対的なもので、曖昧模糊とした対象世界から構造を切り出すよりは楽というに過ぎない。
DTDはまた、文書処理システムや文書処理アーキテクチャを表現する。HyTime や、XLinkは、純粋にシステムの機能やアーキテクチャを定義している。既に注意したように、情報的実在や文書記述様式を定式化したDTDであっても、アーキテクチャ(処理方式)を前提にするのが普通だ。「システムが文書に要求するもの」と「文書がシステムに要求するもの」を明確化することも、DTD設計上の重要な作業だ。
もはや紙幅も尽きてきた。残った話題は項目を挙げることしかできない。
DTDにより定義されるものは要素構造だけではない。実体セットや記法(ノーテーション)もある。これらの定義もシステムや運用環境と密接に関連する。表示や印刷の設計もDTDと無関係とは言えない。実体管理やハイパーリンクも、その構文はDTDが提供する。
設計の際に使用する分析手法や概念モデル、DTDの直接間接のユーザーとなる人間、組織環境などの問題についても述べるべきことは多々ある。以下に一言だけ注意を付け加えておく。
要素の処理や表示に対しては、まがりなりにも記述言語がある。しかし、要素の(人間にとっての)意味や使用法を形式的に記述する方法はない。自然言語によるコミュニケーションだけが伝達手段である。微妙な意味的差の使い分け(例えば、強調の程度とか、「ファイル名」と「パス名」の区別など)や、細かい粒度の精密なマークアップを徹底するのはきわめて困難である。ある種のルーズさを許容し、マークアップにゆらぎがあっても破綻しないタグセットを設計することが重要ではないかと私は感じている。
目次へDTD設計の問題点ばかりを指摘したようだが、これは安易な設計による不幸な経験により、私が「アツモノに懲りて」いるせいかもしれない。しかし一方で、DTD設計は、魅力的でチャレンジャブルな分野であるとも思っている。実務上の手法の開発や理論的基盤の整備にアタックする人材の出現を期待したい。
目次へ