レコードとしてのXML要素

檜山正幸 (HIYAMA Masayuki)
Wed Jun 15 2005:start
Wed Jun 15 2005:draft

レコードデータとXML要素の相互変換(むしろ相互解釈)について述べる。い くつかの方法/事例を列挙するが、それらの優劣を論じることはしない。

目次

1. はじめに

「XML要素をレコードとして解釈したい」、あるいは逆に 「レコードをXML構文でエンコードしたい」という要望がある。だが、要素の レコード解釈(あるいはレコードの要素解釈)が一意的に決まるわけではない。 要素-レコード対応は複数ありえるし、それらの対応に絶対的な優劣はない。

この記事では、要素-レコード対応の例をいくつか出して、それらを比較して みることにする。

2. レコード

名前・値ペア(name-value pair)をいくつか集めたデータを‘レコード’と 呼ぶ。レコードを構成している個々の名前・値ペアを‘フィールド’と呼ぶ。 レコードは、構造体、(RDBテーブルの)行(ロウ)、素性構造、プロパティ セットなどとも呼ばれる。使える名前(キー)を実行時に変更できるなら、マッ プと呼ぶこともある。その他にも、このようなデータ構造の呼び名があるかも しれないが、ここでは、細かい差異は無視して一律に「レコード」「フィール ド」という言葉を使うことにする。

レコードの型を定義・記述するには、次の形式を使う。

record Person {
 date birthDate;
 string givenName;
 string familyName;
}

3. 要素-レコード対応の論点 -- タグ名の解釈

XMLの要素をレコードとみなすとき、属性名をフィールド名、属性値をフィー ルド値に対応させる事には異論は少ない。だが、XML要素は属性だけで出来上 がっているわけではない。要素にはタグ名と内容がある。したがって、タグ名 と内容をどのようにレコードにマップするかは意見が別れる。

本記事では特に、タグ名に対する次の3つの解釈を取り上げて論じる。

  1. タグ名を型の名前だとみなす。
  2. タグ名をフィールド値だとみなす。
  3. タグ名を内容データに対するフィールド名だとみなす。

この3つの解釈を簡単に解説した後で、その他の問題点も取り上げる。

4. タグ名を型の名前だとみなす

例として出したPerson型レコードに対して、次のようなXML表現を 考えることは自然である。

<Person 
 date birthDate="1976-09-11"
 givenName="健夫"
 familyName="園部" />

この場合、型の名前がタグ名によりエンコードされていることになる。した がって、タグ名により型の判別ができ、その型を定義する規則(スキーマ)と の照合も可能である。

要素内容は無名のフィールドとなるが、例えば#contentのような特殊な名前 を持つフィールドと解釈すれば、内容に対する制限も型定義に含めることができる。

record Person {
 date birthDate;
 string givenName;
 string familyName;
 string #content; /* 自由にコメントを書いてよい */
}

あるいは、通常のフィールドと同様に名前を持たせ、そのフィールドが内容に マップされることをアノテーション(ここでは@Contentとする)で示してもよ い。

record Person {
 date birthDate;
 string givenName;
 string familyName;
 string @Content comment;
}

5. タグ名をフィールド値だとみなす

タグ名もデータとして使われることもある。例えば次のように。

<園部健夫 生年月日="1976-09-11">釣りと盆栽が趣味です。</園部健夫>

この例のようなマークアップは“好ましくない”とされているが、現実には使わ れることもある。このケースでは、タグ名も一種のフィールドとみなすしか ない。タグ名を値とするフィールドのフィールド名を#tagNameとしよう。 すると、次のような型定義ができる。

record Person {
 Name #tagNmae; /* 人の名前 */
 date birthDate;
 string givenName;
 string familyName;
 string #content; /* 自由にコメントを書いてよい */
}

あるいは、アノテーション@TagNameを使ってみれば、次のような定義となる。

record Person {
 Name @TagName name;
 date birthDate;
 string givenName;
 string familyName;
 string @Content comment;
}

このマークアップでは、型名がXMLインスタンスにエンコードされないので、 環境から型情報を得るしかない。

6. タグ名を内容データに対するフィールド名だとみなす

もう一度次の例を考える。

record Person {
 date birthDate;
 string givenName;
 string familyName;
 string @Content comment;
}

型定義の段階では存在するフィールド名commentは、XMLインスタンスでは消 えてしまう。そこで、タグ名を内容に対する名前(キー)として使うなら、次 のようなマークアップとなる。

<comment 
 birthDate="1976-09-11"
 givenName="健夫"
 familyName="園部">釣りと盆栽が趣味です。</comment>

上の事例では、かなり不自然な印象があるが、次ならひどい違和感はないだろう。

<comment personName="園部健夫">釣りと盆栽が趣味です。</comment>

7. フィールドを子要素にマップする

「フィールドを属性に対応させる事には異論は少ない」と述べたが、属性を 使わないXMLエンコーディングでは、フィールドが子要素にマップされる。
<Person>
 <birthDate>1976-09-11</birthDate>
 <givenName>健夫</givenName>
 <familyName>園部</familyName>
</Person>

この方式では、親のタグ名は型名を表している(と思える)が、子のタグ名 はフィールド名に対応する。つまり、親と子ではタグ名の解釈が異なる。もっ とも、要素は単一のフィールドで、Personがフィールド名、内容はレコードデー タを記述しているという解釈もできなくはない(そのとき、型名はエンコード されない。)

8. フィールドのマッピング法と型情報の取得

以上の事例から、フィールド(名前と値)のXMLへのマッピング法は次 のように分類できそうである。

  1. 属性名と属性値にマップ
  2. 要素タグ名と内容にマップ
  3. 名前は失われ、値を内容にマップ
  4. 名前は失われ、値をタグ名にマップ

レコードの型名をXMLインスタンスに埋め込むには、次の方法があり得る。

  1. タグ名を型名とする。(ただし、他の目的でタグ名が使われているとき は適用できない。)
  2. 特定の属性の値として型名を指定する。

要素の型を知るには、次の方法があり得る。

  1. 「タグ名が型名」という前提により、タグ名から型を判定する。
  2. 「特定の属性値が型名」という前提により、属性値から型を判定する。
  3. 要素自体からは型の情報は得られないので、外部環境から要素の型を知る。