レベル: 初級 Kevin Williams (kevin@blueoxide.com), CEO, Blue Oxide Technologies, LLC
2002年 5月 01日 この記事では、コラムニストのKevin Williams氏が、XSLスタイル・シートの作成に使われる 最も一般的な2つのオーサリング・スタイルである、プッシュ・スタイルとプル・スタイルについて調べます。いくつかの簡単なXMLとXSLの例を引き合いに出しながら、それぞれのアプローチの利点と欠点を説明します。
XSLスタイル・シートをオーサリングするときには、次の2つの主要なオーサリング・スタイルのどちらかを採用できます。
- プッシュ・スタイル。出力文書内に出力を生成するハンドラー を中心に構築します。出力は、ソース文書内に出現する要素の種類に基づいて生成されます。つまり、要素の内容を、該当するハンドラーにプッシュ します (押し込む)。
- プル・スタイル。ソース文書から、必要に応じて内容をプル する (引き出す) ことによって出力文書を構築します。
どちらのスタイルを選ぶかによって、コードの複雑さと、スタイル・シートの保守容易性が大きく変わります。
プッシュ・スタイル・シート
プッシュ・スタイル・シートは、古典的な 形式のスタイル・シートです。主要なXSL生成ツールは、このスタイルを生成します。また、XSLの解説書で説明されているものも、多くの場合、このスタイルです。この形式のスタイル・シートは、一連のxsl:template 要素で構成され、それぞれの要素が文書内の特定の要素タイプを処理します。たとえば、次のようなソース文書があるとします。
リスト1. サンプル・データ文書
<Orders>
<Invoice>
<CustomerName>Kevin Williams</CustomerName>
<Address>100 Nowhere Lane</Address>
<City>Nowheresville</City>
<State>VA</State>
<Zip>24182</Zip>
<Item>
<ID>E38-19273</ID>
<Description>3-inch Grommets</Description>
<Count>37</Count>
<TotalCost>37.00</TotalCost>
</Item>
<Item>
<ID>E22-18272</ID>
<Description>2-inch Widgets</Description>
<Count>22</Count>
<TotalCost>11.00</TotalCost>
</Item>
</Invoice>
<Invoice>
<CustomerName>John Public</CustomerName>
<Address>200 Anywhere Street</Address>
<City>Anytown</City>
<State>VA</State>
<Zip>24177</Zip>
<Item>
<ID>E22-18272</ID>
<Description>2-inch Widgets</Description>
<Count>27</Count>
<TotalCost>13.50</TotalCost>
</Item>
<Item>
<ID>E19-28376</ID>
<Description>1-inch Bolts</Description>
<Count>16</Count>
<TotalCost>4.00</TotalCost>
</Item>
</Invoice>
</Orders>
|
そして、この文書を、次のようなXHTML文書に変換するとします。
リスト2. サンプル・データ出力
<html>
<body>
<h1>Kevin Williams</h1>
<p>100 Nowhere Lane<br />
Nowheresville, VA 24182</p>
<table>
<tr>
<th>Description</th>
<th>Cost</th>
</tr>
<tr>
<td>3-inch Grommets</td>
<td>37.00</td>
</tr>
<tr>
<td>2-inch Widgets</td>
<td>11.00</td>
</tr>
</table>
<p />
<h1>John Public</h1>
<p>200 Anywhere Street<br />
Anytown, VA 24177</p>
<table>
<tr>
<th>Description</th>
<th>Cost</th>
</tr>
<tr>
<td>2-inch Widgets</td>
<td>13.50</td>
</tr>
<tr>
<td>1-inch Bolts</td>
<td>4.00</td>
</tr>
</table>
</body>
</html>
|
スタイル・シートには、一連のテンプレートを作成する必要があります。各テンプレートでは、出力文書に持って行きたい各種の要素を処理します。さらに各テンプレートでは、テーブルのヘッダーや行など、サポートするXHTML要素の構造も生成する必要があります。ソース文書 (リスト1) から、リスト2に示されている出力を生成するための、プッシュ方式のスタイル・シートは、次のようになります。
リスト3. データ用のプッシュ・スタイル・シートのサンプル
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="Orders">
<html>
<body>
<xsl:apply-templates select="Invoice"/>
</body>
</html>
</xsl:template>
<xsl:template match="Invoice">
<xsl:apply-templates select="CustomerName" />
<p>
<xsl:apply-templates select="Address" />
<xsl:apply-templates select="City" />
<xsl:apply-templates select="State" />
<xsl:apply-templates select="Zip" />
</p>
<table>
<tr>
<th>Description</th>
<th>Cost</th>
</tr>
<xsl:apply-templates select="Item" />
</table>
<p />
</xsl:template>
<xsl:template match="CustomerName">
<h1><xsl:value-of select="." /></h1>
</xsl:template>
<xsl:template match="Address">
<xsl:value-of select="." /><br />
</xsl:template>
<xsl:template match="City">
<xsl:value-of select="." />
<xsl:text>, </xsl:text>
</xsl:template>
<xsl:template match="State">
<xsl:value-of select="." />
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="Zip">
<xsl:value-of select="." />
</xsl:template>
<xsl:template match="Item">
<tr>
<xsl:apply-templates />
</tr>
</xsl:template>
<xsl:template match="Description">
<td><xsl:value-of select="." /></td>
</xsl:template>
<xsl:template match="TotalCost">
<td><xsl:value-of select="." /></td>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="text()" />
</xsl:stylesheet>
|
スタイル・シートに組み込む必要のある、次の2つの興味深い追加項目に注目してください。
- 最後にあるヌル・テンプレートは、不要な情報 (たとえば、伝票にある品目の単価など) が出力文書から確実に省略されるようにします。
- すべての子要素を文書順で処理するテンプレートを書くことによって、ソース・ツリーに沿って確実に処理が行われるようにします。これにより、特定の伝票のテンプレートがないというだけの理由で、いずれかの伝票の内容が処理されないということがなくなります。
このスタイル・シートを見てお気付きのとおり、この構造はあまり美しくありません。コードをオーサリングする作業はかなり簡単ですが、コードを保守するのは手の込んだ作業になることがあります。この非常に簡単な例の場合でさえ、XHTMLのテーブルにどのようにデータが埋め込まれるかを調べるには、テンプレートからテンプレートへと目を移しながら、どこでtd オブジェクトが生成されているかを見つけ出さなければなりません。もっと複雑な例であれば、何ページ分ものテンプレートがあり、その多くは他のテンプレートから呼び出されることになります。そのようなコードの保守作業は、さらに難しいでしょう。
プル・スタイル・シート
一方、プル・スタイル・シートでは、ソース文書内でどの要素が次に出現するかをコード作成者が知っていることが重要です。このコードでは、繰り返し出現する要素を明示的に反復し、適切な構造を出力内に生成し、必要に応じてソース文書から値を引き出します。次に示すのは、リスト2 のスタイル・シートと同じ変換を実行するスタイル・シートですが、プッシュ戦略ではなくプル戦略を採用しています。
リスト4. データ用のプル・スタイル・シートのサンプル
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="Orders">
<html>
<body>
<xsl:for-each select="Invoice">
<h1>
<xsl:value-of select="CustomerName" />
</h1>
<p>
<xsl:value-of select="Address" /><br />
<xsl:value-of select="City" />
<xsl:text>, </xsl:text>
<xsl:value-of select="State" />
<xsl:text> </xsl:text>
<xsl:value-of select="Zip" />
</p>
<table>
<tr>
<th>Description</th>
<th>Cost</th>
</tr>
<xsl:for-each select="Item">
<tr>
<td><xsl:value-of select="Description" /></td>
<td><xsl:value-of select="TotalCost" /></td>
</tr>
</xsl:for-each>
</table>
<p /> </xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
|
この形式のスタイル・シートでは、テンプレートは1つだけであり、取得しようとしている情報のルートに対応するテンプレートです。ソース文書に埋め込まれたネストされた情報は、xsl:for-each 要素を使って取得されて、現在のノードの特定のタイプの子要素すべてが処理されます。このリストを見てお気付きのとおり、このスタイル・シートはずっと読みやすくなっています。プッシュ形式のスタイル・シートより短くなっているほか、そのレイアウトも、出力文書の最終的なレイアウトにかなりの程度まで対応しています。プル形式でコーディングするときには、最終的な出力のサンプルを参考にして、最上位レベルのテンプレートにその構造を追加することができます。その後、サンプルの中の値を、ソース文書から値を取得するための該当するコードに置き換えます。
プル形式の方がいつでもプッシュ形式より優れているということか?
プル形式の方がプッシュ形式より優れている点 (読みやすさ、簡潔さ、および読みやすいレイアウト) が確かにあるとはいえ、スタイル・シートの形式は、ソース文書の特徴に基づいて選ぶ必要があります。架空の医療処置について物語風に記述した内容が含まれている、次のリストの構造例をご覧ください。
リスト5. 物語風な文書のサンプル
<SurgeryLog>
<Narrative>
<section time="13:00:00">First, the surgeon used the <tool>3-inch
scalpel</tool> to make a <procedure>two-inch incision</procedure>
in the patient's <location>lower left abdomen</location>.
<procedure>Cautery</procedure> was then applied to the
<target>severed blood vessels</target> to stop the
bleeding.</section>
<section time="13:14:23">The surgeon then <procedure>cleaned and
dressed the incision</procedure>, using <tool>four two-by-two
sterile gauze pads</tool> and <tool>medium sutures</tool>.</section>
</Narrative>
</SurgeryLog>
|
この物語風な文書では、情報が任意の順序で登場します。文書には、2つのtool 文節に続いてprocedure 文節があるかもしれず、あるいは3つのlocation 文節が並んでいるかもしれません。ここでは、この文書から次のような出力を生成したい場合を考えてみましょう。
リスト6. 物語風な情報の出力サンプル
<html>
<body>
<h1>Surgery Log</h1>
<p><b>13:00:00</b></p>
<p>First, the surgeon used the <i>3-inch scalpel</i> to make a
<font color="#FF8800">two-inch incision</font> in the patient's
lower left abdomen. <font color="#FF8800">Cautery</font> was
then applied to the severed blood vessels to stop the bleeding.</p>
<p><b>13:14:23</b></p>
<p>The surgeon then <font color="#FF8800">cleaned and dressed
the incision</font>, using <i>four two-by-two sterile gauze pads</i>
and <i>medium sutures</i>.
</body>
</html>
|
プッシュ形式のスタイル・シートの優れている点は、情報の出現する順序が問題にならないということです。次のスタイル・シートは、リスト5 のソースXMLを処理して、望みどおりのXHTMLを生成します。
リスト7. 物語風な文書用のプッシュ・スタイル・シート
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="SurgeryLog/Narrative">
<html>
<body>
<h1>Surgery Log</h1>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="section">
<p>
<b>
<xsl:value-of select="@time" />
</b>
</p>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="tool">
<i>
<xsl:apply-templates />
</i>
</xsl:template>
<xsl:template match="procedure">
<font color="#FF8800">
<xsl:apply-templates />
</font>
</xsl:template>
</xsl:stylesheet> |
項目がネストしていても、テンプレートがそれらを正しい順序で処理してくれるため、大きな問題にならないことに注目してください。リスト8のような、もっと複雑なケースでも処理できます。この文書では、procedure 要素の中にtool 要素が含まれています。
リスト8. ネストした要素のある物語風な文書のサンプル
<SurgeryLog>
<Narrative>
<section time="13:00:00">First, the surgeon <procedure>used the
<tool>3-inch scalpel</tool> to make a two-inch incision</procedure>
in the patient's <location>lower left abdomen</location>.
<procedure>Cautery</procedure> was then applied to the
<target>severed blood vessels</target> to stop the
bleeding.</section>
<section time="13:14:23">The surgeon then <procedure>cleaned and
dressed the incision</procedure>, using <tool>four two-by-two
sterile gauze pads</tool> and <tool>medium sutures</tool>.</section>
</Narrative>
</SurgeryLog>
|
このソース文書にスタイル・シートを適用すると、その結果はまさに期待通りになります。つまり、procedure (処置) の内側に埋め込まれたtool (器具) は、イタリック体かつオレンジ色で表示されます。さて、ここで、同じスタイル・シートをプル・スタイルで作成した場合の例を見てみましょう。
リスト9. 物語風な文書用のプル・スタイル・シート
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="SurgeryLog/Narrative">
<html>
<body>
<h1>Surgery Log</h1>
<xsl:for-each select="section">
<p>
<b>
<xsl:value-of select="./@time" />
</b>
</p>
<p>
<xsl:for-each select="*|text()">
<xsl:choose>
<xsl:when test="name()='procedure'">
<font color="#FF8800">
<xsl:value-of select="." />
</font>
</xsl:when>
<xsl:when test="name()='tool'">
<i>
<xsl:value-of select="." />
</i>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</p>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
|
このスタイル・シートがあまり美しくないことに注目してください。各ノードをいちいちチェックする必要があり、特別な処理の必要なノードに対しては、該当するフォーマット設定を追加します。しかも、このスタイル・シートでは、リスト8 に示したような複雑なケースを処理できません。つまり、procedureマークアップの内側のtoolマークアップは無視されます。もし、このスタイル・シートを拡張して、tool、target、procedureなどの考えられるネストをすべて適切に処理できるようにしたとすると、スタイル・シートはすぐに手に負えない (そして保守不能な) サイズに膨れ上がってしまうでしょう。
結論
この記事で紹介した実例は、これまでの私の記事で説明した点を例証しています。つまり、データ文書は、物語風な文書とは本質的に異なっているということです。その違いは、次のような点にあります。
- データ文書内の情報は、コード中で予想できる順序で出現する。
- データ文書にはバラバラの (loose) テキストは含まれていないため、そのようなテキストを出力文書に移すための特別なコードは必要ない。
ソース・データ文書を出力文書にマッピングすることは、通常、要素の名前を変更し、要素を並べ替え、要素を集めてターゲット・ツリーのレベルにする (あるいは、より詳細なレベルにする) ことと、複雑さの点で大差ありません。プル・モデルを使用すれば、マッピングは簡単で、保守しやすいものになります。
他方、物語風な内容がベースになっている文書は、まったく正反対です。
- 情報が出現する順序は、簡単には予想できない。
- 一部のテキストは要素のコンテキスト外にフロート しているため、出力文書に適切に移す必要がある。
物語風な内容を出力文書に正確に再現するには、スタイル・シートにおいて、要素がどこに出現しても処理しなければなりません。その点では、プッシュ・スタイル・シートが優れています。
要約すれば、データ文書用のスタイル・シートを設計するときには、まずはプル・モデルを使用することを検討します。物語風な文書では、可能であれば、プッシュ・モデルを使用します。この両方の種類のスタイル・シートを記述する面で上達すれば、そして、それぞれの長所と短所を学び取れば、これから将来に遭遇するどんなスタイル設定の仕事でも、適切に処理できるようになるでしょう。
参考文献
著者について  | |  | Kevin Wiliams氏は、情報管理システムのためのXML設計を専門とするVeridianの一部門であるEquientの主任XMLアーキテクトです。XMLに関する数冊の共著がWrox Pressから出版されています。彼の連絡先はkevin@realworldxml.comです。Kevin Williams氏のWebサイト www.realworldxml.com では、XMLについて彼が思うこと、ヒント、秘けつ、大胆な主張について知ることができます。 |
記事の評価
|