XHTML文書にユーザ独自の要素を追加する方法

[1] はじめに

XHTML文書にはユーザが勝手に考えた別の名前空間に所属する要素を追加することができます。

XHTMLのDTDに手を加えれば簡単にできますが、XTMLのDTDに手を加えずに済む方法もあります。「裏技」とも呼ぶべき感心しない方法なのですが、紹介しておきましょう。

[2] 例題

色を自由に使える環境で文章を書いていると、文中の強調したい箇所や警告の意思を示したい箇所に赤色を使いたいと思うことがあります。 また、とくに意味はなくとも、ここは字を赤や青にしたいと思うこともあるでしょう。

たとえば

鈴木くんは、態度を改めないと、次回はレッドカードだよ~
あれあれ、田中くんの顔が真っ青に変わった。

のような文章です。

※ 上の例で「レッドカードだよ~」は赤色で、「真っ青に」は青色で表示されています。

さてHTMLで文章を作るときに、どうやって色を指定するのでしょうか。 ホームページビルダーのようなHTMLオーサリングソフトなら選択した箇所に色を指定するのは簡単な作業です。HTMLやCSSの文法の知識は要りません。GUIでカラーパレットを出してきて、指定したい色をマウスでクリックするだけです。しかしテキストエディタで色指定をやろうとすると、色のRGB値をHTMLまたはCSSファイルのなかに書き込むという面倒な作業が必要です。たとえば上の文は埋め込み又は読み込みのスタイルシート(CSS)で

span.red {
  color: #ff0000;
}

span.blue {
  color: #0000ff;
}

のように span 要素の字色を定義した上で、HTMLで

鈴木くんは、態度を改めないと、次回は<span class="red">レッドカードだよ~</span>。
あれあれ、田中くんの顔が<span class="blue">真っ青に</span>変わった。

と書いて指定します。

けれどもHTMLで <span class="red">レッドカードだよ~</span> と書くのは凡長な気がします。いちいちclass 属性を書くのは面倒であり、ソースも読みにくくなります。 そこでユーザ独自の要素を使って、たとえば

鈴木くんは、態度を改めないと、次回は<e:red>レッドカードだよ~</e:red>。
あれあれ、田中くんの顔が<e:blue>真っ青に</e:blue>変わった。

のようにできれば、入力がしやすく、読みやすくもなるので、問題は解決します。

ここで <e:red><e:blue> の e は「名前空間接頭辞」と呼ばれるもので、HTMLの要素名とユーザの勝手につくった要素名とを区別する役目をします。 e に限る必要はありませんが、ここでは e という接頭辞を用いることにします。 HTML を拡張(extend)するという意味をこめて e としました。

このようにユーザ固有の要素を含んだXHTML文書はもはやXHTMLとはいえませんが、あとでXSLTスタイルシートで
<e:red>...</e:red> を <span class="red">...</span> に
<e:blue>...</e:blue> を <span class="blue">...</span> に
変換すれば、HTML文書に仕上がります。

[3] DTD の設計

PSGML はDTDを読み込むことでXML文書の入力支援を行います。

純正のXHTML文書を作成するならば、XHTML 1.0 Strict のDTDを使えばいいですが、上の例のようにユーザ固有の要素を含んだXHTML文書を作成するには、ユーザがDTDを作成する必要があります。

これには二通り方法があって、ひとつはXHTML 1.0 Strict に手を加えて、それを自分のDTDにするという、方法です。具体的に言うと、テキストエディタで xhtml1-strict.dtd を開き、ユーザ独自の要素を含むように必要な修正を加えて、それを別名で保存するというやり方です。

もう一つはまず自分のDTDを作って、その中で XHTML 1.0 Strict のDTDを読み込み、必要な修正を前後に加えるというやり方です。

ここでは第二の方法を紹介します。

まず、独自要素や独自属性の名前の属する名前空間を決める必要があります。

ここでは名前空間として http://somehost/someuser/home という架空のURLを用いることにします。

次に名前空間接頭辞を決めます。これは上の例のように e にします。

ただしDTDでは後で自由に接頭辞を変えることができるようにしておきます。

これらのことを決めるとユーザの作るべきDTDは下のような感じになります。

<!ENTITY % prefix "e">
<!ENTITY % _prefix "%prefix;:">
<!ENTITY % xmlns_prefix "xmlns:%prefix;">

<!ENTITY % _red "%_prefix;red">
<!ENTITY % _blue "%_prefix;blue">

<!ENTITY % ext.inline "%_red; | %_blue;">

<!-- Override XHTML Entities as below -->
<!ENTITY % misc.inline "ins | del | script | %ext.inline;">

<!-- Import XHTML DTD -->
<!ENTITY % XHTML SYSTEM "xhtml1-strict.dtd">
%XHTML;

<!-- Add namespace declarations to document element -->
<!ATTLIST html
  %xmlns_prefix; %URI; #FIXED "http://somehost/someuser/home" >

<!-- Define the extended elements, attributes -->
<!ENTITY % coreattrs-without-class
 "id          ID             #IMPLIED
  style       %StyleSheet;   #IMPLIED
  title       %Text;         #IMPLIED"
  >
<!ENTITY % attrs-without-class
 "%coreattrs-without-class; %i18n; %events;">

<!ELEMENT %_red; %Inline;>
<!ATTLIST %_red; %attrs-without-class;>

<!ELEMENT %_blue; %Inline;>
<!ATTLIST %_blue; %attrs-without-class;>

これを xhtml1-strict-ext1.dtd として保存します。

[4] 解説 1. エンティティ宣言

<e:red></e:red><e:blue></e:blue> は あとでそれぞれ <span class="red"></span><span class="blue"></span> に変換されるべき要素なので、span 要素と同じようにインライン要素とします。それには XHTML 1.0 Strict DTD の misc.inline エンティティに加えておくのが便利です。

<!ENTITY % ext.inline "%_red; | %_blue;">

と書いて e:red e:blue を エンティティ ext.inline にまとめてから

<!ENTITY % misc.inline "ins | del | script | %ext.inline;"> 

で既存のmisc.inline エンティティの中味に加えます。これで結果的に

<!ENTITY % misc.inline "ins | del | script | e:red | e:blue"> 

と書いたのと同じことになります。

[5] 解説 2. XHTML1.0 Strict DTD の読み込み

次に

<!ENTITY % XHTML SYSTEM "xhtml1-strict.dtd">
%XHTML;

と書いて、XHTML1.0 Strict DTD を読み込みます。DTDでは同じエンティティに関する二つの宣言があった場合、先に書いたものが優先されますから、misc.inline エンティティは xhtml1-strict.dtd の186行目にある

186: <!ENTITY % misc.inline "ins | del | script">

ではなく、ユーザの xhtml1-strict-ext1.dtd に書いた

<!ENTITY % misc.inline "ins | del | script | %ext.inline;"> 

が有効になることに注意してください。

[6] 解説 3. 名前空間宣言の追加

それから名前空間宣言をXHTML文書の文書要素 <html></html> に付け加えます。

<!ATTLIST html
  %xmlns_prefix; %URI; #FIXED "http://somehost/someuser/home" >

%URI; エンティティは xhtml1-strict.dtd の70行目で

<!ENTITY % URI "CDATA">

として定義されています。

[7] 解説 4. 独自要素の定義

いよいよ独自要素の定義です。

e:red e:blue は span に変換されるべきものなので、xhtml1-strict.dtd の span の定義(520行目)に倣って

<!ELEMENT %_red; %Inline;>
<!ATTLIST %_red; %attrs;>

としても十分です。(後注:これで十分、以下は削除予定。)

しかし %attrs; エンティティの中には class 属性も含まれています。もし例えば

<e:red class="larger">レッドカードだよ~</e:red>

というように class 属性を指定しまうと、あとで e:red span class="red" に変換する際に、class="larger" と class="red" が衝突してしまいます。 そこで衝突が起きないように e:red e:blue の持つべき属性から class 属性を除くことにします。

<!ENTITY % coreattrs-without-class
 "id          ID             #IMPLIED
  style       %StyleSheet;   #IMPLIED
  title       %Text;         #IMPLIED"
  >
<!ENTITY % attrs-without-class
 "%coreattrs-without-class; %i18n; %events;">

の部分がそれです。 xhtml1-strict.dtd の112行目にある %coreattrs; エンティティの定義から

  class       CDATA          #IMPLIED

を除いたものが coreattrs-without-class エンティティになっています。