本文へジャンプ

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

送信されたすべての情報は安全です。

  • 閉じる [x]

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


送信されたすべての情報は安全です。

  • 閉じる [x]

拡張機能によるXSLの拡張

XSLのコア機能を拡張するのに役立つ技法

Jared Jackson, Research Associate, FIT Team, IBM China Development Lab 
Jared Jacksonは、IBM Almaden Research Centerのリサーチ提携者であり、Harvey Mudd大学でコンピューター・サイエンス学位を取得した新卒者です。

概要: XMLとXSLを組み合わせて使用すると、Web上でデータを表現し、操作し、表示する分野や、異なるアプリケーション間でデータを共用する分野で、大きな威力を発揮しますが、このことは、これらのテクノロジーが急速に受け入れられ、幅広く利用されていることによって明らかに実証されてきました。それでも、XMLとXSLの基本に習熟している大部分の開発者たちは、この能力を完全に活用しているとは言えません。この記事では、開発者が拡張機能 (XSLの機能を拡張できる技法) を利用する方法を紹介します。

日付:  2002年 4月 01日
レベル:  上級 この記事の原文:  英語
アクティビティー: 2079 ビュー
お気軽にご意見・ご感想をお寄せください: 


XMLとXSLの組み合わせは、その能力と簡明さの点で、SQLデータベース言語を使用していた初期の時代以来これまでになかった仕方で、データの格納と操作の分野に革命を起こしました。XMLは、データを記録するための明快で独立した方法を提供し、そのデータは容易に共有し、理解できます。同様に、XSLも、読みやすく、記述しやすく、理解しやすいと多くの人々が感じています。明らかに、この強力なコンビは、テクノロジー業界に関与するすべての人にとって不可欠な知識です。

XSL変換の基本的な要素は、適用範囲の広さと頂の低い学習曲線を特徴としていますが、このことが時として両刃の剣になります。核となるテクノロジーは幅広く利用されるものの、XSLを学習する開発者の大部分は、より高度で強力な機能を調査して利用するところまではなかなか足を踏み入れないのです。

この記事の対象読者は、XMLとXSLの基本を既に理解しており、その上にさらに知識を積み上げていく用意のできている開発者です。これらのテクノロジーにまだ習熟していない読者は、developerWorks やその他のWebサイトから、優れた入門記事やチュートリアルを見つけることができます。この記事では、拡張機能 (大部分のXSLプロセッサーに存在する技法) を使用する方法を紹介します。この機能を利用すると、XSLのコア機能の既存の能力をほとんど無限に拡張できます。この記事では、まず拡張機能をコードで記述する方法について全般的に説明し、続いて、3つの具体的かつ幅広く応用可能な実例を紹介します。

XSLの拡張機能 (extension) とは何か

最初に理解しておいていただきたい点として、XSLは、他のすべてのプログラミング言語と同じように、単に文法の仕様に過ぎず、インプリメンテーションが必要です。幸いにも、XSLは非常にポピュラーになったため、いくつかのインプリメンテーションを選択できます。拡張機能は文法の中の必須機能ではないため、その構文は言語のその他の構造ほど明確には定義されていません。しかし、拡張機能は、W3CのXSLT勧告に含まれています。この記事で紹介する実例は、その勧告のフォーマットに従っています。

簡単に言えば、拡張機能とは、他の何らかのプログラミング言語で記述されたメソッドをXSL文書内から呼び出す手段のことです。拡張メソッドは、通常、XSLプロセッサーを記述しているのと同じ言語で記述します。もっとも、このルールには例外があります。たとえば、Javaでは、JavaScriptやPerlなどの別の言語内でプログラムを実行することができます。したがって、XSLの拡張機能をJavaScript、Perl、またはその他の言語で記述して、それをJavaベースのXSLプロセッサーから利用することが可能です。

XSLは既に多くの機能を備えているのに、なぜ拡張機能に意味があるのでしょうか。XSLは、変換を簡単に実行できて、その機能も豊富である反面、変換とは無関係の機能を効率的に実行するのは苦手である場合がほとんどです。たとえば、システムの5,000人のユーザーを列挙したXML文書があるとします。各ユーザーのユーザー名、実名、およびEメール・アドレスが、XML文書内の Users ノードの下に列挙されています。その後、そのXML文書に、別個のサブツリーとして Interests ノードを追加し、曲芸、サイクリング、パソコンなどの特定の趣味ごとにグループ分けしてユーザー名を列挙します。最終的には、このデータを変換して、ユーザーを趣味ごとにグループ分けして、同じ趣味を持つ人のEメール・アドレスを掲載したHTMLページを生成したいと思います。XSLでは、次のようなコードによって、その処理を手軽に実行できます。



リスト1. ユーザーの趣味のXSL変換 (拡張機能を使わない場合)
                
<xsl:for-each select="Interests/Interest">
  <b><xsl:value-of select="@InterestName"/></b>
  <ul>
    <xsl:for-each select="User">
      <xsl:variable name="userName" select="@userName"/>
      <xsl:variable name="userNode" select="/Root/Users/User[@userName = 
		$userName]"/>
      <li>
		<xsl:value-of select="$userNode/@realName"/> 
		<xsl:value-of select="concat(' ',$userName/@email"/>
	 </li>
    </xsl:for-each>
  </ul>
</xsl:for-each>
			

残念ながら、この変換を実行すると、それぞれの趣味グループ内の各ユーザーごとに、5,000ユーザーのリスト全体が調査されることになります。これでは、このWebページが要求されるたびに、サーバーに過剰な負荷が掛かります。

拡張機能は、小さくないデータ・セットに対してXSLを使用する際に直面するこのような問題点や、その他のいくつかの問題点を回避する便利な方法を提供します。上記の例では、単純なハッシュ・マップまたは二分探索ツリーを使えば問題を簡単に解決できますが、それらのデータ構造をXSLでインプリメントするのは不便で非現実的です。より適切なデータ型を持つ言語への拡張機能を使えば、問題をより簡単に解決できます。(ちなみに、この後の最初の実例で、この解決策のコードを紹介します。)


この記事で使用するテクノロジー

すべてのXSLプロセッサーを列挙し、それぞれについて拡張機能をインプリメントする方法を記載するのは、困難な仕事です。この記事では、JavaバージョンのXalan (Apache Projectから無料で入手できる人気の高いXSLプロセッサー) を使って、拡張機能を記述する具体的な方法を説明します。この後の実例はすべて、そのプラットフォームを対象にしています。(XMLパーサーとしては、これもApacheの製品であるXercesを使用します。XalanとXercesは、 参考文献 のリンクからダウンロードできます。)ポピュラーなXSLインプリメンテーションのほとんども、拡張機能のメカニズムを提供しています。しかし、具体的な方法の違いについて、それぞれのインプリメンテーションの資料を調べる必要があります。

XMLとXSLの操作を簡略化するために、一般的なXML操作の一部についてもJavaコードを用意しました。そのコードや、すべての実例を実行するのに必要なコードとデータは、 参考文献 にあるZIPファイルに含まれています。ただし、このファイルには、XalanやXercesなどの外部ライブラリーは含まれていません。これらのライブラリーは、 参考文献 のリンクから入手した後 (バージョン: Xalan - Java 2.3.1、Xerces 1.4.4)、そのjarファイルをZIPファイルから抽出してlibディレクトリーに置いてください。すぐに実例を調べたい読者のために情報を記載しておきます。すべてのJavaコードはsrcディレクトリーに、XMLデータはXMLディレクトリーに、XSL変換はXSLディレクトリーに、バッチ・ファイルはbinディレクトリーに、そしてコンパイル済みコードはlibディレクトリーにあります。


拡張機能の作成

XSLからメソッドを呼び出すためには、まずメソッドを記述し、そのコンパイル済みの形式を、XSL変換を実行するアプリケーションのクラスパスに置かなければなりません。メソッドは、自分で設計することも、Javaの標準ライブラリーから提供することも、その他のJavaライブラリーから取ることもできます。Xalanをはじめとする一部のXSLプロセッサーでは、プロセッサーに直接組み込まれている拡張機能メソッドさえ存在します。

これらのメソッドを記述したり使用したりするときに最初に意識しておくべき点は、XSLとJavaとの間のデータ型のマッピングです。次の表に、Xalanにおけるマッピングを掲載します。


表1, 2. データ型のマッピング

パラメーターのマッピング
XSLTの型Javaの型
ノード・セット org.w3c.dom.traversal.NodeIterator
文字列java.lang.String
ブール値java.lang.Boolean
数値java.lang.Double
結果のツリー・フラグメントorg.w3c.dom.DocumentFragment

戻りの型のマッピング
Javaの型SLTの型
org.w3c.dom.traversal.NodeIterator
org.apache.xml.dtm.DTM
org.apache.xml.dtm.DTMAxisIterator
org.apache.xml.dtm.DTMIterator
org.w3c.dom.Node
ノード・セット
java.lang.String文字列
java.lang.Booleanブール値
java.lang.Number数値
org.w3c.dom.DocumentFragment 結果のツリー・フラグメント

メソッドを記述した後、それをXSLに取り込むのはかなり簡単です。最初のステップは、 <xsl:stylesheet> 要素の中でメソッドの名前空間を宣言することです。たとえば、パッケージ com.myCompany.XSLExtensions 内の foo というクラスからメソッドを実行したい場合は、XSLファイルのルートに次のような行を含めます。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:extension="xalan://com.myCompany.XSLExtensions.foo"/>

後ほど、ここで宣言したクラスのメソッドを呼び出すときには、 <xsl:stylesheet> 要素の中で宣言した名前空間を使用します。引き続きこの例で考えていきましょう。パラメーターとして String を取り、 String を返す、 bar() というメソッドを実行するには、次のようなコードを使用します。

<xsl:variable name="myParam" select="'theParameter'"/>
<xsl:variable name="myResult" select="extension:bar($myParam)"/>

このように簡単です。 myResult 変数に、Javaクラスの bar メソッドを呼び出した結果が入ります。次に、この技法をさらによく理解するために、3つの実例を検討してみましょう。


例1: ルックアップ・テーブル

この記事の最初に紹介したシナリオは、XML文書の別々のサブツリーにあるデータを標準的なXSLの技法を使って検索すると、必要な計算時間が長くなりすぎるというものでした。この問題を回避する簡単な方法は、文字列を格納して取得するためのメカニズムを提供する、汎用のハッシュ・テーブルを作成することです。ハッシュ・テーブルは標準のJavaライブラリーに直接組み込まれているため、それを利用する拡張機能を記述することにそれほど労力は掛からないはずです。

ハッシュ・テーブルのJavaコードは、 参考文献 のZIPファイルに含まれているsrc/StringHash.javaファイルに入っています。ここで注目したいメソッドは、次の2つです。

  1. addString(String tableName, String key, String value)
  2. getString(String tableName, String key)

最初のメソッドでは、指定されたテーブル名でハッシュ・テーブルを作成し、キーに対応する文字列値を挿入できます。2番目のメソッドは、格納した値を検索する手段を提供します。

XMLのデータ・ソースは、XML/user_interests.xmlファイルにあります ( 参考文献 のZIPファイルを参照)。次のような形式になっています。



リスト2. ユーザーの趣味のXMLフラグメント
                
<Users>
  <User userName="aragorn" realName="Aragorn" 
	email="aragorn@middleEarth.fict"/>
  <User userName="boromir" realName="Boromir" 
	email="boromir@middleEarth.fict"/>
  ...
</Users>
<Interests>
  <Interest name="archery">
    <User userName="legolas"/>
    ...
  </Interest>
  ...
</Interests>
			

参考文献 のZIPファイルには、結果のWebページを生成するためのXSLファイルが2つ入っています。最初のXSLファイルはXSL/user_interests_xsl_only.xslで、 リスト1 に示されているコードを基にしています。2つ目のXSLファイルはXSL/user_interests_extensions.xslで、最初のXSLファイルをリスト3に示されているコードに修正したものです。このXSL変換をWindowsで簡単に実行するには、bin/Example_1*.batバッチ・ファイルを使用します。UNIXとMacの開発者は、これらのバッチ・ファイルを調べれば、それほど苦労せずにこの例を実行できるはずです。



リスト3. ユーザーの趣味のXSL変換 (拡張機能を使う場合)
                
<xsl:stylesheet xmlns:lookup="xalan://StringHash">
...
<xsl:for-each select="Users/User">
  <xsl:value-of select="lookup:addString('realName', string(@userName), 
	string(@realName))"/>
  <xsl:value-of select="lookup:addString('email', string(@userName), 
	string(@email))"/>
</xsl:for-each>
...
<li>
  <xsl:value-of select="lookup:getString('realName',$userName)"/>
  <xsl:value-of select="concat(' - ',lookup:getString('email',
	$userName))"/>
</li>
			


例2: 正規表現

現行のXSL標準では、すべてのパターン・マッチングを実行するためにXPathテクノロジーを使用しています。XPathは、XMLツリーをトラバースするための簡潔で洗練された手段を提供していますが、パターン・マッチングの機能は比較的限られています。(XPathでブール値を返すマッチングを実行する文字列関数は、 starts-with()ends-with() 、および contains() がすべてです。また、文字列を自動的に数値として解析することもできます。)正規表現は、テキストの文字列に対してさらに豊富なパターン・マッチング機能を提供していますが、XMLツリーなどのデータ構造をトラバースするときに、XPathと同じように簡単に利用できます。正規表現についてさらに詳しくは、 参考文献 を参照してください。

理想的なソリューションは、この2つのテクノロジーを組み合わせることです。次バージョンのXSL変換言語 (現在まだ開発および検討中) には、言語に正規表現を追加する提案が組み込まれます。しかし、このテクノロジーを今利用したい開発者に対しては、拡張機能がそのためのメカニズムを提供してくれます。

拡張機能としてアクセスするJavaメソッドのソース・コードは、この記事に付属のZIPファイルのsrc/PatternMatcher.javaファイルに含まれています。これらのメソッドでは、標準のJavaライブラリーには含まれていない外部コードを利用しています。したがって、この例は、拡張機能で使用するために外部jarファイルをリンクするのに必要な手順を示すものともなっています。この例を実行するには、GNUによって提供されている正規表現のjarファイル ( 参考文献 を参照) を入手して、抽出したlibディレクトリーに置く必要があります。別の正規表現パッケージを見つけて、それに合わせてコードを修正したいようでしたら、ご自由にどうぞ。

2番目の例として、元のソース・ファイルから、ユーザーの名前としてファーストネームとラストネームの両方が含まれているユーザーのリストを生成したい場合のことを考えてみましょう。この例そのものは些細な処理ですが、ユーザーのグループ、製品カタログ、またはリファレンス・データベースなどを対象にしたもっと複雑な処理の例は、簡単に思いつくはずです。この処理を実行するための簡単な方法は、ユーザーの実名を1つずつ調べていき、名前の後にスペースがあり、その後にさらに名前が続いている、というケースを探すことです。そのための正規表現は、 \w* \w* です。したがって、XSLのコードは、リスト4のようになります。



リスト4. XSLにおける正規表現
                
<xsl:stylesheet xmlns:regexp="xalan://PatternMatcher">
...
<ul>
  <xsl:for-each select="Users/User[regexp:containsMatch('\w* \w*',
        string(@realName))]">
    <li>
      <xsl:value-of select="@realName"/>
    </li>
  </xsl:for-each>
</ul>
			

例1と同じように、この例は、bin/Example_2.batファイルを使って実行できます。使用するXSLファイルは、XSL/user_last_names.xslです。この技法は、様々に拡張することができます。


例3: 国際化対応

国際化対応 (ローカライズ または各国語サポート と呼ばれることもある) は、開発者が自分たちの製品を複数の言語および地域で読めるようにする手段のことです。このことは、幅広い視聴者を対象にするWebページを生成する変換の場合に、XML変換のコンテキストで特に重要になります。国際化対応の話題は非常に幅広いので、この例のコンテキストで包括的に紹介するのは困難ですが、後ほど参照するdeveloperWorks のほかの記事の中に、この話題に関する優れた取り扱いの事例が掲載されています。

この例では、リソース・バンドルを使用することにより、国際化対応を取り扱うJavaの標準技法を利用します。このトピックに慣れていない読者は、参照されている記事をお読みください。ここでは、リソース・バンドルは、様々な地域 (正確には、ロケール) 用の翻訳が入ったファイルのコレクションで構成されている、ということだけを述べておきます。Webサーバーは、ユーザーがWebページを要求したときにユーザーが設定しているロケールを読み取り、これらのリソース・バンドルを使って適切に応答できます。XMLベースのアプリケーションは、結果を特定のロケールを対象にすることもできます。

この例のコードの応用範囲は、これまでの例と同様、幅広く、また多種多様です。このテクノロジーを例証するために、bin/Example_3.batファイルによって実行されるコードでは、サンプルのXMLユーザー・データから3通りのWebページを作成します。その3通りのページはデータの同じビューを表していますが、3つの異なる言語で提示されます。使用される変換は、ZIPファイルから抽出されたlibディレクトリー内のプロパティー・ファイルにあります。


結論

XSL変換のごく基本的な構成要素を考えるだけでも、その能力は注目に値します。このコアを拡張機能を利用して拡張し、現代のプログラミング言語の能力を取り込めば、その可能性はほとんど無限に広がります。この記事で紹介したアイデアと実例は、氷山の一角に過ぎません。この記事で紹介した点を読者が理解した後、その他の多くの可能性を探究することは、読者の手にゆだねたいと思います。


参考文献

  • Xerces (XMLパーサーおよびDOMのインプリメンテーション) と、Xalan (XSL変換プログラム) は、 Apache XML Project からダウンロードできます。

  • XML/XSLについては、次の記事をお勧めします。

  • 正規表現 に関する疑問の答えは、このガイドから得られます。

著者について

Jared Jackson

Jared Jacksonは、IBM Almaden Research Centerのリサーチ提携者であり、Harvey Mudd大学でコンピューター・サイエンス学位を取得した新卒者です。

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


developerWorks: サイン・イン


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。 プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。 お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

表示名をお選びください

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

(半角英数字で3文字以上31文字以下にする必要があります)


「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


この記事を評価する

コメント

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML
ArticleID=240093
ArticleTitle=拡張機能によるXSLの拡張
publish-date=04012002
author1-email=jjared@almaden.ibm.com
author1-email-cc=

タグ

Help
このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。

スライダーバーを使用することで、より多く(少なく)タグを表示します。

人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。

マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。

このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。