倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

要素の概要 (7) -- 外部参照

今回は外部参照をする要素。

  • <externalRef>
  • <include>

どちらも参照する外部ファイルを指定する属性「@href 属性」を持たなければなりません。

<externalRef> 要素


<externalRef> 要素は、外部ファイルに定義されているパターンをそのまま読み込む要素です。 パターンが書けるところには何処にでも書けます。 また、外部ファイルは RELAX NG パターンが定義されていればどんなものでも構いません。

簡単なサンプルを見てみましょう。 まず、以下のように <child> 要素を定義するスキーマがあったとします(ファイル名は「child.rng」とします):

<!-- child.rng -->
<element name="child" xmlns="http://relaxng.org/ns/structure/1.0">
  <empty/>
</element>

他のスキーマ定義からこの要素の定義をそのまま読み込みたい場合、以下のように <externalRef> 要素を書きます:

<element name="parent" xmlns="http://relaxng.org/ns/structure/1.0">
  <externalRef href="child.rng"/>
</element>

この結果、以下のようなスキーマ定義と同じと見なされます:

<element name="parent" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="child">
    <empty/>
  </element>
</element>

<externalRef> 要素の箇所が参照されているスキーマ定義で単純に置き換えられるだけです。

★@ns 属性★

<externalRef> 要素は単に参照先のスキーマ定義に置き換えられるだけですが、@ns 属性がある場合はそれが参照先のスキーマ定義に付加されます。 詳しくはそのうちに。

<include> 要素


<include> 要素は外部ファイルのパターン定義(<define> 要素)を読み込む要素です。 <grammar> 要素の子要素として用います。 また、<externalRef> 要素と違って、参照先のスキーマ定義は <grammar> 要素でなければいけません。

サンプルを見てみましょう。 参照先のファイル「child-def.rng」は以下のようであったとします:

<!-- child-def.rng -->
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <define name="child1">...</define>
  <define name="child2">...</define>
  <define name="child3">...</define>
</grammar>

このとき、<include> 要素を含むスキーマ定義以下のように書くと

<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <include href="child-def.rng"/>

  <define name="parent1">...</define>
  <define name="parent2">...</define>
  <define name="parent3">...</define>
</grammar>

以下のようなスキーマ定義と同じになります:

<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <define name="child1">...</define>
  <define name="child2">...</define>
  <define name="child3">...</define>

  <define name="parent1">...</define>
  <define name="parent2">...</define>
  <define name="parent3">...</define>
</grammar>

★同名の <define> 要素がある場合★

参照先にも参照元にも同名の <define> 要素がある場合、それらの複数の定義は @combine 属性を用いて適切に結合されます。 詳しくはそのうちに。 複数の同名の <define> 要素に @combine 属性がない場合はエラーになります。

★子要素としての <start>, <define> 要素★

<include> 要素には、子要素として <start>, <define> 要素を書くことができます*1。 これによって、参照先の <start> 要素や <define> 要素を上書きすることができます。

<include> 要素下に <define> 要素があるサンプルを見てみましょう。 参照元のスキーマ定義を以下のように書くと(「child-def.rng」の内容は上記のサンプルと同じとします)、

<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <include href="child-def.rng">
    <define name="child1">○○○</define>
  </include>
  ...
</grammar>

以下のスキーマ定義と同じになります:

<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <define name="child1">○○○</define>
  <define name="child2">...</define>
  <define name="child3">...</define>
  ...
</grammar>

<include> 要素下に <start> 要素を書いた場合も、参照先の <grammar> 要素下の <start> 要素がそのまま上書きされます。 

注意しなければならないのは、この「上書き」方法には「上書きされる相手」が無ければいけないことです。 <include> 要素下に <define> 要素を書いた場合、参照先のスキーマ定義に同名(@name 属性の値が同じ)の <define> 要素が定義されていなければいけません*2

*1:その他、&ls;div> 要素も書くことができます。

*2:同様に、<include> 要素下に <start> 要素を書いた場合、参照先のスキーマ定義にも <start> 要素が無ければいけません。