本文へジャンプ

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


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

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

  • 閉じる [x]

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

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

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


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

  • 閉じる [x]

Tip:XSLTでの再帰によるループ

XSLTの機能を拡張するテクニック

Elliotte Rusty Harold (elharo@metalab.unc.edu), Adjunct Professor, Polytechnic University
Photo of Elliot Rusty Harold
Elliotte Rusty Haroldはニューオーリンズ出身であり、時たま、おいしいgumbo(オクラ入りのスープ)を食べに帰っています。ただし現在はニューヨークのブルックリン近郊のProspect Heightsに、妻のBethと猫のCharm(charmed quarkからとりました)とMarjorie(義理の母の名前からとりました)と一緒に住んでいます。彼はPolytechnic Universityのコンピューター・サイエンスの非常勤教授として、Java技術とオブジェクト指向プログラミングを教えています。彼のCafe au Lait Webサイトは、インターネット上で最も人気のある独立系Javaサイトの一つです。また、そこから派生したCafe con Lecheは、最も人気のあるXMLサイトの一つです。彼の著作には Effective XML Processing XML with Java Java Network Programming 、それに The XML 1.1 Bible があります。現在はXML処理用のXOM APIやJaxen XPathエンジン、Jesterテスト・カバレッジ・ツールなどに取り組んでいます。

概要: XSLTはHaskellやSchemeに似た関数型プログラミング言語であり、CやFortranには似ていません。したがって、ループもなければ、mutable変数もありません。代わりに、これらの構成体を再帰とパラメーターに置き換える必要があります。このTipでは、名前付きテンプレートとxsl:call-template、xsl:with-param、およびxsl:param要素を使用してこの機能を備える方法を説明します。

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


XSLTはチューリング完備です。つまり、十分なメモリーさえあれば、XSLTは他のチューリング完備言語(C++など)で計算できるものなら何でも計算できます。これは、より伝統的な言語に慣れているプログラマーにとって、ちょっとした驚きです。結局、XSLTには、ループやmutable変数も含めて、多くのアルゴリズムにとって重要ないくつかの機能が欠けています。

:XSLTで変数と呼ばれるものは、他のほとんどの言語では定数と呼ばれています。従来のプログラミングでの変数よりは代数変数に近いものです。


関数型プログラミング

先ほど述べた欠落は、過失によるものではありません。XSLTは、手続き型言語ではなく関数型言語です。CやPascalなどの手続き型言語では、プログラムは一連のステップとして定義され、それらを指定された順序で実行することによって、シーケンスの最終ステップとして最終結果が生成されます。関数型言語では、プログラムは他の関数から成る関数として定義され、それらを評価することで最終結果が導き出されます。関数型言語の大きな利点は、実行の順序は問題ではないということです。単純な例として、次のような2つの(代数)関数を考えてみましょう。

f(x) = 2*x
g(x) = x - 3

関数h(x)はfとgの合成であるとします。

h(x) = f(g(x))

この関数は、gを先に評価してもかまいませんし、

h(x) = f(x - 3) = 2 * (x - 3) = 2x - 6

fを先に評価してもかまいません。

h(x) = 2 * g(x) = 2 * (x - 3) = 2x - 6

どちらも同じ答えになります。言語の関数性は、言語を並列処理になじみやすくします。どの部分を他の部分より先に評価するか気にせずに、プログラムの複数の部分を同時に評価できるからです。当然、スレッドセーフです。

関数型言語は、XSLTも含めて、従来のループを含むことができません。ループには時間的な前後関係があるからです。すなわち、典型的なループは、i==1がi==2よりも前に起こるように作成され、コンパイルされます。もちろん、ループを前方ではなく後方に実行したり、ループ・カウンターを1以外の値で増分したり、あるいは、while文のようにループ・カウンターを完全になくすこともできます。しかし、ループの種類に関係なく、実行の順序が重要であり、この点が関数型プログラミングとは対照的です。


再帰

関数型言語では、従来の言語ではループで行われているタスクのほとんどが、代わりに再帰によって行われます。パラメーターが変数の代わりです。たとえば、最近、私は、コンパイル時には個数がわからないが、一定の数のドット(ピリオド)をプリントする方法を尋ねられました。これは、たとえばレストランのメニューを書式化するときに便利です。メニューでは、料理名と価格の間のドットの数を料理によって変えなければならないことが多いからです。

Crawfish Etoufee.......$9.95
Fried Chicken..........$6.95

Cでは、次のような単純な関数を使います。

void printDots(int n) {

  int i;

  for (i = 0; i < n; i++) {
    printf(".");
  }
  
}

しかし、これが問題を解決する唯一の方法ではありません。ループの代わりに、次のような再帰を使うこともできます。

void printDotsRecursively(int n) {

  if (n > 0) {
    printf(".");
    printDots(n-1);
  }
  
}

これはCでは珍しいやり方かもしれません。しかし、XSLTでは、再帰が唯一の選択肢です。

次のテンプレートは、countパラメーターの値として渡された正確な数のドットを生成します。ロジックは簡単です。$countの値がゼロより大きければ、ピリオドを出力し、countパラメーターを1だけ減らして、関数を再び呼び出します。そうでない場合は何もしません。これは基本的に、printDotsRecursively関数で使用されているのと同じアルゴリズムであり、CではなくXSLTで実装されているだけのことです。

<xsl:template name="dots">
  
      <xsl:param name="count" select="1"/>

      <xsl:if test="$count > 0">
        <xsl:text>.</xsl:text>
        <xsl:call-template name="dots">
          <xsl:with-param name="count" select="$count - 1"/>
        </xsl:call-template>
      </xsl:if>
      
  </xsl:template>

たとえば、ドットを100個プリントするには、countパラメーターの値として100を指定してテンプレートを呼び出します。

    <xsl:call-template name="dots">
      <xsl:with-param name="count" select="100"/>
    </xsl:call-template>
			

定数値を渡す代わりに、プリントするドットの数を何か他の値に基づいて計算することもできます。たとえば、次の命令は、価格と料理名の長さ(より具体的に言うと、コンテキスト・ノードのpriceおよびentree子要素の文字列値の長さ)を除いて、メニューの1行80文字を埋めるのに必要な数のドットをプリントします。

    <xsl:call-template name="dots">
      <xsl:with-param name="count" 
                select="80 - string-length(entree) - string-length(price)"/>
    </xsl:call-template>
			


まとめ

ループを再帰に置き換えるには、C、XSLT、またはSchemeのいずれでも、ある程度の慣れが必要です。しかし、このテクニックにはエレガンスさがあります。XSLTで頻繁に使用する必要があるわけではありませんが、標準のXSLTでは他に方法がない厄介なタスクを成し遂げることができます。



参考文献

  • Wikipediaにある、関数型プログラミングに関する記事を読んでください。ここでは、チューリング完備に関しても学ぶことができます。

  • Michael Kay著によるXSLTへの標準的な入門記事、XSLT Programmer's Referenceを読んでください。彼はdeveloperWorksにもXSLTに関する2本の記事、「XSLTはどのような言語か」(2005年4月)と「Saxon: XSLTプロセッサーの解体新書」(2005年4月)を書いています。

  • XMLテンプレートの基礎を解説したElliotte Haroldの著書、Processing XML with JavaのChapter 17で、再帰について詳しく学んでください。

  • W3CのXSLT 2.0仕様を読むと、この記事でXSLT 1.0での再帰を使って行ったタスクを、もっと容易に行う方法が他にも幾つかあることが分かります。しかしXSLT 2.0は、XSLTの基本的な機能は変えていません。ですから多くのタスクでは、やはり再帰が必要になります。

  • ここで議論したメニューの問題を解決するために、EXSLTのパディング機能を試してみてください。ただしこれは、一つのことしかできない代物で、再帰によって解決できるような他の多くの問題には対応していません。EXSLTパディング機能の純粋なXSLT実装では、この記事で紹介した、もう少し効率的な再帰アルゴリズムを使用しています。

  • developerWorksのXMLゾーンでは、XMLに関する資料が他にも豊富に用意されています。

  • XMLおよび関連技術においてIBM認証開発者になる方法については こちら を参照してください。

著者について

Photo of Elliot Rusty Harold

Elliotte Rusty Haroldはニューオーリンズ出身であり、時たま、おいしいgumbo(オクラ入りのスープ)を食べに帰っています。ただし現在はニューヨークのブルックリン近郊のProspect Heightsに、妻のBethと猫のCharm(charmed quarkからとりました)とMarjorie(義理の母の名前からとりました)と一緒に住んでいます。彼はPolytechnic Universityのコンピューター・サイエンスの非常勤教授として、Java技術とオブジェクト指向プログラミングを教えています。彼のCafe au Lait Webサイトは、インターネット上で最も人気のある独立系Javaサイトの一つです。また、そこから派生したCafe con Lecheは、最も人気のあるXMLサイトの一つです。彼の著作には Effective XML Processing XML with Java Java Network Programming 、それに The XML 1.1 Bible があります。現在はXML処理用のXOM APIやJaxen XPathエンジン、Jesterテスト・カバレッジ・ツールなどに取り組んでいます。

不正使用の報告のヘルプ

不正使用の報告

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


不正使用の報告のヘルプ

不正使用の報告

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


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=242460
ArticleTitle=Tip:XSLTでの再帰によるループ
publish-date=06292005
author1-email=elharo@metalab.unc.edu
author1-email-cc=dwxed@us.ibm.com

タグ

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

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

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

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

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