属性か内容か?それは問題ではない

檜山正幸 (HIYAMA Masayuki)
Tue Apr 05 2005:start
Tue Apr 05 2005:draft

「属性と内容をどう使い分けるか」が重要な判断となることがあるのは事実だ。 が、いつもでそうだとは言い切れない。この記事では、マークアップ手法の選 択がむしろ恣意的判断となる事例を取り上げる。

目次

1. はじめに

XMLボキャブラリに関して、僕が今までにうけた質問のなかで一番 多かったのは、「属性と内容(子要素)は、どう使い分けるのですか?」とい うたぐいのものだ。当然に、この話題については何度も話した/書いたことが ある。お決まりの(無難な)答はだいたい次のようなものだ。

だがしかし、別にどっちでもいいケースは確かにある。たとえば、RDB的なレ コードデータをXMLエンコードする場合は、フィールドを属性にしても子要素 にしてもどっちでもいいだろう。このへんのことは、 「XMLボキャブラリのデザイ ン・パターン」の「(2)レコード類似の構造 」でも論じている。

レコード類似構造、特にフィールド値がスカラー型(アトミックな単純型) だと決まっている場合は、好みとか手作業タギングの手間以外には、属性と内容 (子要素)のあいだに顕著な優劣は見いだせない。このようなケースでは、 「属性か内容か」のマークアップ上の違いよりはむしろ、マークアップからは 独立したデータ構造定義のほうが本質的課題となるだろう。

そこでこの記事では、マークアップ手法からは独立したデータ定義/制約記 述について例を出して説明する。そのような事例から導かれる教訓や主張 (implication)が重要であるが、それはまた他の記事にまとめることにして、 この記事では事例の提示のみ。

記事の題名は人目を引くためのジョークだ。多くのケースでは「属性か内容 か?それが問題だ」となる。だが、すべてのケースで「それが問題だ」となる わけではない。応用領域/分野によっては「問題ではない」こともある。

2. 事例

簡単な、そしてありきたりの例を出す。次のような項目で構成されるデータ を考える(アンケートのデータなどをイメージして欲しい)。

TABLE: データの構成
項目名 意味 データ型
givenName 名前の名string
familyName 名前の性string
sex性別 {male, female}
married 既婚か boolean
partnersName 配偶者の名 string

これらのデータ項目にはさらに次の制約があるとしよう。

  1. givenNameとfamilyNameは必須であるが、その他の項目は省略可能である。
  2. marriedの値が真のときはpartnersNameが存在してもよいが、marriedの値が 偽のときはpartnersNameがあってはならない。

いま、これら5つのデータ項目を同名の5つの属性を使ってXMLエンコードする としよう。例えば、次はXMLエンコードされたデータの例である。

<person givenName="トン吉" familyName="板東" sex="male" married="false"/>

3. 制約の表現

この節では、「属性のための正規表現」で導入した 集合正規表現を使う。構文的演算子「|」「&」「?」は、集合正規表現の意味 で解釈する。

まず記号の使い方を(「属性のための正規表現」の繰り返しになるが)説 明する。givenName=string、married=boolean のような、「属性=型」という 表記によって、属性のパターンを表すことにする。givenName=string は、属 性名がgivenNameであり属性値のデータ型がstringである属性を一般的に表す。 2つ以上の属性パターンをまとめるときはブラケットで囲むことにする。例え ば、[sex={male, female} married=boolean] -- この属性パターン とマッチするすべてのインスタンス(属性の組)を列挙できる。

  1. sex="male" married="true"
  2. sex="male" married="false"
  3. sex="female" married="true"
  4. sex="female" married="false"

[sex="male" married=boolean]のように、属性値を定数に固定したパターン も使えるとする。この例は、sex="male" married="true" か sex="male" married="false"のどちらかにマッチする。

givenName=string、sex={male, female} のような単一属性に関するパターン を、最初が大文字の名前で代表させることにする。つまり、次のように書ける。

 GivenName = [givenName=string]
 Sex = [sex={male, female}]

また次にように、任意の属性パターンに名前を付けてもよい。

 Name = [givenName=string familyName=string]

さて、GivenName、Sexなどの記号を使って、許される属性出現パターンを集 合正規表現を使って記述しよう。GivenName、FamilyName、Sexに関しては、 GivenName & FamilyName & Sex? とすればよいが、既婚未婚の別と配偶者名が 依存しているので、この制約が少しやっかい。次のパターンを補助的に導入し よう。

 NotMarried = [married="false"]
 Married = [married="true"]

NotMarried、Marriedはパターンであるが、そのパターンに一致する(単一) 属性は1つしかない。これらを使えば、データ全体の制約を次のように書ける。

 GivenName & FamilyName & Sex? & (NotMarried | (Married & PartnersName?))?

4. 属性でも要素でも同じこと

いま扱っている事例は、「属性と内容(子要素)のあいだに顕著な優劣は見 いだせない」ケースであるから、属性をすべて子要素に置き換えても不都合はな い。属性の出現パターンを表していたGivenName、Sex、NotMarried、Married などを、子要素の出現パターンを表すと解釈し直してみよう。次の表記は臨時に でっち上げた書き方だが、意味はとれるだろう。

 GivenName = <givenName>string</givenName>
 Sex = <sex>{male, female}</sex>
 NotMarried = <married>"false"</married>
 Married = <married>"true"</married>

このように約束したとき、 GivenName & FamilyName & Sex? & (NotMarried | (Married & PartnersName?))? という集合正規表現は、属性で はなくて内容、つまり子要素の出現パターンとして使用できる。

この事例では、レコード的なデータを表現する手段としてXMLを使ったのであ り、属性方式マークアップと子要素方式マークアップのあいだに完全な対応 があるのだから、属性/内容にかかわりなく同じ制約が働くのは当然である。

現実には、内容をこのように解釈するケースは少なくない。それどころか、 このような解釈しかしない人も見受けられる -- それが悪いと言っているわけ ではないから、念のため。応用においてフォーカスされる問題はXML構文では なくて、XMLによる表現の“向こう”に人が何を見ているかだから、どう解釈 しようとトヤカク言うべきことではない。