IBM®
本文へジャンプ
    Japan [変更]    ご利用条件
 
 
検索範囲検索:    
    ホーム    製品    サービス & ソリューション    サポート & ダウンロード    マイアカウント    
skip to main content

developerWorks Japan  >  XML | Open source  >

XSLT 変換パイプラインをサポートするフレームワークの作成

Butterfly フレームワークを使用して XSLT 文書を処理する

developerWorks
ページオプション

JavaScript を要するドキュメントオプションは表示されません

議論する

原文はこちら

原文はこちら


レベル: 中級

Jake Miles, Freelance writer and developer, Twistage Inc.

2008年 11月 18日

この記事で説明するのは、PHP 5 で動作し、ソースである XML 文書に XSLT スタイルシートのチェーンを簡単に適用できるようにするフレームワーク、Butterfly を作成する方法です。このフレームワークを使用することで、XML 文書から変換した結果をそのままキャッシングできるようになります。Java™ ベースの Apache Cocoon プロジェクトに端を発し、ある形式から別の形式へのデータ変換 (毛虫から蝶 (Butterfly) への変身) を管理し、その変換結果を保存することから、この極めて軽量になったフレームワークは Butterfly と呼ばれています (訳注: Apache Cocoon プロジェクトの Cocoon は繭 (まゆ) という意味です)。Butterfly フレームワークでは、スタイルシート変換のチェーンを定義する XML 構成ファイルを設定し、Butterfly オブジェクトをインスタンス化して、そのそれぞれで XSLT 変換チェーンの結果を生成することができます。この記事では、Butterfly フレームワークの概要を具体的に説明することで、フレームワーク設計の本質全般についても検討することになります。

はじめに

PHP 5 の XSL モジュールでは、XSLT スタイルシートを XML 文書に適用して、XML データを他のタイプのテキスト文書に変換することができます。変換後の文書の構造としては、別の XML 構造や HTML にすることも、プレーン・テキストやさらには Java や他のプログラミング言語を含めた他のあらゆる構造にすることができます。またソース・テキストやターゲット文書の構造に関わらず、XSLT の問題に特有のあらゆるプログラムを作成することができます。XSLT プロセッサー・オブジェクトを作成し、変換を適用するには、この記事で使用する PHP コードだけで十分です。

よく使われる頭字語
  • API: application programming interface
  • HTML: Hypertext Markup Language
  • PHP: PHP Hypertext Preprocessor
  • XML: Extensible Markup Language
  • XSL: Extensible Stylesheet
  • XSLT: Extensible Stylesheet Transformations

PHP で XSLT スタイルシートを XML に適用する仕組みは通常は同じなので、ビジネス固有のコードからこのプロセスをリファクタリングして、より再利用しやすいコードにすることが可能です。この記事では、XSLT 文書のチェーンを処理する再利用可能な軽量の PHP フレームワーク、Butterfly の概要を説明します (Butterfly をダウンロードするには、「参考文献」を参照してください)。ただし、ここで説明する Butterfly フレームワークは、http://jakemiles.com/butterfly でホストされているプロジェクトのことで、同じ名前を持つ他の Java ベースの Web アプリケーション・フレームワークとは無関係なのでご注意ください。チェーンはソースである XML 文書から始まり (必ずしも 1 つのファイルとは限りません)、この文書に一連の XSLT スタイルシートを適用して最終的な文書を生成します。この機能は、XSLT スタイルシートのパイプラインを処理して最終文書を生成する Java ベースのフレームワーク、Apache Cocoon プロジェクトが提供する機能のほんの一部です。

最終文書が Web ページの場合、XSLT スタイルシートを処理する際にはパフォーマンスが 1 つの懸念事項となります。文書のデータ量が少なかったり、単純なスタイルシートであればパフォーマンスが問題になることはありませんが、何千もの要素がある大量のデータ・セットの場合、一連のスタイルシートをページがロードされるたびに適用するのでは、ページのロードに時間がかかるだけでなく、メモリーとサーバーの処理能力を大量に消費することになるからです。

このようなパフォーマンス問題に対するソリューションは単純で、キャッシュを使用することです。つまり、Web サーバーがすぐに対応できるように XSLT 変換の結果を静的 HTML ページとしてキャッシュに入れ、XSLT 変換の完全なチェーンを実行するのはソース文書、あるいはスタイルシートのいずれかが変更されたときだけにするというソリューションです。このキャッシング・メカニズムは関連する特定の XML や XSLT に特有のものではないので、このフレームワークでは一般的メカニズムとして処理することができます。

XSLT スタイルシートを処理するときに考えられるもう 1 つの問題は、ソースである XML に関する問題です。XML はファイルから提供されることもあれば、SQL データベースから提供されることもあります。そのため、フレームワークは複数のデータ・ソースに対応できるだけの柔軟性を持ち合わせていなければなりません。




上に戻る


初期段階のフレームワーク

オブジェクト指向のフレームワークを設計するときには、基本的にメソッドとクラスという 2 つの抽象化ツールを使用することができます。継承可能にしなければならないすべてのもの、つまり将来、新しい類の振る舞いを可能にしたいものについては、メソッド呼び出しまたはクラスとして抽象化しなければなりません。そうすることにより、ポリモーフィズムを利用して、実行時に同じメソッドを公開する別のクラスと交換することが可能になります。フレームワークがクラスで溢れかえってきたらファクトリー・クラスを追加し、このファクトリー・クラスによって複数のクラスを共通の組み合わせにまとめ、共通して使える単純化した API を提供することができます。

フレームワークを作成するための実践的な方法は、最初にコアの機能を作成し、それからその機能に構造を適用することで継承可能にし、インターフェースを単純化する方法です。この記事に記載しているような簡潔なコードにするためには、まずコード全体で使用している 2 つのコア・インターフェース、ButterflyDocumentButterflyXmlDocument に注目してください (リスト 1 を参照)。


リスト 1. コア・インターフェース、ButterflyDocumentButterflyXmlDocument

interface ButterflyDocument {
  function getContents();
  function writeContents();
}

interface ButterflyXmlDocument extends ButterflyDocument {
  function getDom();
}

ButterflyDocument は、読み取り/書き込み可能なコンテンツが含まれるテキスト文書を表します。リスト 1 では、この文書のコンテンツを getContents() がストリングとして返し、writeContents() が標準出力に書き込みます。もう一方の ButterflyXmlDocument は XML 文書を表します。ButterflyXmlDocumentButterflyDocument を継承したもので、この文書の XML コンテンツを表す DOMDocument オブジェクトを返す getDom() メソッドが定義されています。

この 2 つのコア・インターフェースとは別に、今度はフレームワークのコア機能である ButterflyTransformer クラスに目を向けてください。このクラスには XSLT スタイルシートを XML 文書に適用するという基本的な役割があります (リスト 2 を参照)。


リスト 2. ButterflyTransformer

class ButterflyTransformer {

  private $processor;

  public function __construct ($xslSource) {
    $this->processor = new XSLTProcessor();
    $this->processor->importStylesheet ($xslSource->getDom());
  }

  public function transformToFile ($xmlSource, $filepath) {
    $file = fopen ($filepath, "w");
    fwrite ($file, $this->processor->transformToXml ($xmlSource->getDom()));
    fclose($file);
  }

  public function transformToString ($xmlSource, $filepath) {
    return $this->processor->transformToXml ($xmlSource->getDom());
  }
}

リスト 2ButterflyTransformer は XSLT スタイルシートを表す ButterflyXmlDocument オブジェクトを取り、PHP 5 の XSL モジュールを使用してこのスタイルシートを XML データ文書に適用します。まずコンストラクターが XSLTProcessor オブジェクトを作成し、指定された XSLT スタイルシートをこのオブジェクトにインポートします。続いて transformToFile() が、別の ButterflyXmlDocument オブジェクトによって表された XML 文書にスタイルシートを適用し、変換後のコンテンツを指定されたファイル・パスに書き込むという流れです。




上に戻る


チェーンとキャッシングの追加

ButterflyTransformer の次に注目するのは、Butterfly クラスです。このクラスは一連のスタイルシート変換 (Apache Cocoon の用語を借りると、パイプライン) に含まれる 1 つのチェーンを表すだけでなく、コアとなるキャッシング・ロジックも扱います (リスト 3 を参照)。


リスト 3. Butterfly クラス

class Butterfly implements ButterflyXmlDocument {
                 
  private $transformer;
  private $xmlDoc;
  private $cache;

  public function __construct ($transformer, $xmlDoc, $cache=null) {
    $this->transformer = $transformer;
    $this->xmlSource = $xmlDoc;
    $this->cache = $cache;
  }

  public function getDom() {
    return $this->getTransformedDoc()->getDom();
  }

  public function getContents() {
    return $this->getTransformedDoc()->getContents();
  }

  public function writeContents() {
    $this->getTransformedDoc()->writeContents();
  }

  protected function getTransformedDoc() {
    return ($this->cache != null
        ? $this->getTransformedCache ()
        : $this->getTransformedString ());
  }
 
  protected function getTransformedCache () {
    if (! $this->cache->isPresent()) {    
      $this->transformer->transformToFile ($this->xmlSource,
                       $this->cache->getFilepath());
    }
    return $this->cache;  
  }

  protected function getTransformedString () {
    return new ButterflyXmlString
      ($this->transformer->transformToString ($xmlDoc));
  }
}

Butterfly クラスのコンストラクターが引数に取るのは、コア XSLT 変換ロジックを操作するための ButterflyTransformer オブジェクト、ソースである XML を表すための ButterflyXmlDocument、そしてキャッシュされた変換済み文書を保管および生成するための ButterflyCache オブジェクト (オプションの引数) です。Butterfly 自体は ButterflyXmlDocument を実装することに注意してください。つまり、getContents()writeContents()getDom() メソッドを公開するということです。そのため、XSLT 変換チェーンを Butterfly オブジェクトのチェーンとして実装し、それぞれのオブジェクトが次のオブジェクトのソース・オブジェクトとして機能させることができます。

Butterfly を使用するには、呼び出し側がこれらのオブジェクトを指定してコンストラクターを呼び出し、次に getContents() または writeContents() のいずれかを呼び出して、変換後の結果ストリングを取得するか、あるいは変換後の結果を直接標準出力に書き込みます。

キャッシング・ロジックを操作するのは getTransformedDoc()getTransformedCache() です。コンストラクターはキャッシュ・オブジェクトをオプションの引数として取ることを思い出してください。そのためこのコンストラクターはキャッシュ・オプションには手を付けずに、呼び出し側がキャッシングやフレームワークの構成を懸念することなく XSLT 変換を適用する Butterfly オブジェクトを作成できるようにしています。つまり、getTransformedDoc() は Butterfly にキャッシュ・オブジェクトが設定されているかどうかを調べ、設定されている場合には getTransformedCache() を呼び出してキャッシュに入れられているものを扱い、設定されていない場合には getTransformedString() を呼び出すということです。いずれのメソッドにしても、ButterflyDocument オブジェクトを返すことに注意してください。




上に戻る


ソース文書

ButterflyTransformer クラスと Butterfly クラスには、フレームワークのコア機能が含まれています。次のステップで実装するのは ButterflyXmlDocument です。ButterflyXmlDocument は Butterfly そのものではないため、デリゲート・チェーンは、Butterfly の writeContents() メソッドまたは getContents() メソッドを呼び出した時点で終了します。最もよくあるケースは、XSLT スタイルシートを XML ファイルに適用するケースなので、このタイプの文書を表す ButterflyFile クラスを作成します (リスト 4 を参照)。


リスト 4. ButterflyFile クラスの作成

class ButterflyFile implements ButterflyDocument {

  private $filepath;

  public function __construct($filepath) {
    $this->filepath = $filepath;
  }

  public function getFilepath() {
    return $this->filepath;
  }

  public function isPresent() {
    return file_exists ($this->filepath);
  }

  public function getContents() {
    return file_get_contents($this->filepath);
  }

  public function writeContents() {
    $file = fopen($this->filepath, "r");
    fpassthru($file);
    fclose($file);
  }

  public function delete() {
    unlink ($this->filepath);
  }
}

上記は、ButterflyXmlDocument クラスの具象実装に向けての第一歩です。このクラスは ButterflyXmlDocument の親インターフェースである ButterflyDocument しか実装しません。なぜなら変換結果が XML にならない可能性を考えると、フレームワークはソースである XML 文書とプレーン・テキスト文書の両方を表す必要があるためです。そこで、ファイルを囲む標準ラッパー・クラスとなるのが ButterflyFile です。ファイルの完全パスを指定して作成するこのクラスは、Butterfly クラスによって呼び出される isPresent()getContents()、および writeContents() メソッドを提供します。isPresent() は、パスで指定されたファイルがディスク上に実際に存在する場合には true を返します。getContents() はファイルの内容を返します。最後の writeContents() は、ファイルの内容を標準出力に書き込むために呼び出されるメソッドで、PHP の fpassthru() 関数を呼び出すことによってコンテンツを書き込みます。

fpassthru の呼び出しは、システムの重要な要素です。XSLT パイプラインの最終結果が計算されると、フレームワークは結果をキャッシュに入れて保管することで、その結果を素早く提供できるようにします。fpassthru() は、この素早い提供を実現するために呼び出されるメソッドです。このメソッドの呼び出しによって、Web サーバーはキャッシュされたファイルの内容を直接標準出力に書き込み、それがユーザーのブラウザーに表示されます。




上に戻る


キャッシュ・ファイルの表現

このキャッシングの振る舞いはシステムの重要な概念であるため、キャッシュに入れられた変換結果を表す ButterflyCache クラスを作成するのは当然のことです (リスト 5 を参照)。


リスト 5. ButterflyCache クラスの作成

class ButterflyCache extends ButterflyFile {

  public function __construct($filepath) {
    parent::__construct ($filepath);
  }  

}

ButterflyCache はただ単に ButterflyFile を継承するだけなので、このクラスの存在理由を疑問に思うのは仕方のないことです。このクラスが存在する目的は、Butterfly システムにおけるファイルの特殊な機能を表すことに他なりません。この表現により、キャッシュ内のファイルを中心とした抽象化層が提供されます。Butterfly でキャッシュに入れられたファイルに追加の振る舞いが必要になった場合や、別のファイルを後でキャッシュに入れる場合 (例えば、データベースでの結果をキャッシュに入れる場合など)、フレームワークの残りのクラスがそれを認識する必要はありません。キャッシュ・オブジェクトを作成するコードだけが新しい類のキャッシュを把握していればよいだけの話となります。コードの呼び出しはコンパイル時のキャッシュ・オブジェクトの型に大きく左右されることから、このような抽象化は Java やその他の強い型付けの言語には特に役立ちます。PHP のような言語の場合には、このようなクラスを組み込むことは、すべての開発者に対して、後でフレームワークを継承するという目的をより明確にするという意味合いがあります。ButterflyFile だけでなく、ButterflyCache も作成するコードは明らかに、変換結果の内容をキャッシングするためのファイルを作成していることになるからです。




上に戻る


ButterflyXmlDocument の具象実装

一方、ButterflyXmlFile クラスはプレーン・ファイルの概念と機能に対し、概念と多少の機能の両方を追加します (リスト 6 を参照)。


リスト 6. ButterflyXmlFile クラス

class ButterflyXmlFile extends ButterflyFile implements 
ButterflyXmlDocument {

  public static function create ($filepath) {
    return new ButterflyXmlFile ($filepath);
  }

  public function __construct($filepath) {
    parent::__construct ($filepath);
  }

  public function getDom() {
    $dom = DOMDocument::load($this->getFilepath());
    if (! $dom) {
      throw new Exception ("Couldn't load DOM object from filepath " . 
$this->getFilepath());
    }
    return $dom;
  }
}

ButterflyCache クラスと ButterflyXmlFile クラスはどちらもディスク上のファイルを表すため、両方とも ButterflyFile を継承します。しかし、ButterflyXmlFile クラスはさらに ButterflyXmlDocument インターフェースを実装することから、その文書の内容を DOMDocument として返す getDom() メソッドを実装します。このメソッドの実装が不可欠なわけは、ButterflyTransformer クラスで使用される PHP の XSLTProcessor オブジェクトは、XML を DOMDocument オブジェクトとしてしか扱わないためです。このクラスはまた、基本 ButterflyFile クラスに定義されている ButterflyXmlDocumentgetContents() メソッドと writeContents() メソッドも暗黙的に実装します。

このシステムにあるもう 1 つの XML ソースのタイプは、プレーン XML ストリングです。この特殊なストリングはシステム内で特別な意味と振る舞いを持つことから、ButterflyXmlString クラスにカプセル化されます (リスト 7 を参照)。


リスト 7. ButterflyXmlString クラス

class ButterflyXmlString implements ButterflyXmlDocument {

  protected $xml;

  public function __construct($xmlString) {
    $this->xml = $xmlString;
  }

  public function getDom() {
    return DOMDocument::load($this->xml);
  }

  public function getContents() {
    return $this->xml;
  }

  public function writeContents() {
    echo ($this->xml);
  }
}

リスト 7ButterflyXmlString は XML ストリングをラップし、ラップした XML ストリングに対して ButterflyXmlDocument インターフェースを実装します。getContents() がストリングを返し、writeContents() がストリングを標準出力 (つまり、ブラウザー) にエコー出力します。getDom() がストリングの XML コンテンツを表す DOMDocument を返すと、XSLTProcessor はこのオブジェクトを XSLT スタイルシート、または変換対象のソースである XML 文書として使用できるようになります。




上に戻る


さらなる継承を可能にするためのクラスの抽象化の使用

オブジェクト指向フレームワークの設計で鍵となるのは、クラスを主要な抽象化手段として使用することです。Butterfly クラスに XML ソースがストリングとファイルのどちらであるかを判断する多数の if 文を含め、その結果に応じて動作させることも可能ですが、そのようなコードには全く柔軟性がなく、継承する余地がありません。ButterflyXmlDocument をインターフェースとして抽象化することにより、既存のコードを変更することなく将来継承することが可能になります。例えば、SQL 文を使用して結果を XML に変換する ButterflyXmlSqlSource クラスを作成する場合、ButterflyXmlSqlSource を作成したら、このクラスを ButterflyXmlFileButterflyXmlString としてではなく、XML のソース・オブジェクトとしてButterfly に渡すことで、システムにこのクラスを追加します。




上に戻る


オブジェクトの作成を単純化するためのファクトリー・クラスの使用

次は、Butterfly システムが XSLT スタイルシート変換のチェーンを適用し、変換チェーンの各ポイント (各 Butterfly オブジェクトが 1 つの XSLT 変換を表現) でキャッシング・メカニズムを提供するようにします。ここで問題となるのは、エンド開発者にとって、Butterfly オブジェクトの作成方法が明確になっていないことです (開発者は関連するそれぞれのクラス、そして各クラスをインスタンス化する方法を理解していなければなりません)。しかも、その方法を明確にするとなると厄介で、開発者が XSLT 変換のチェーンごとに特定のコードを作成したり、あるいは Butterfly のチェーンをアセンブルするコードを作成したりする必要が生じる可能性があります。

このような問題に対するオブジェクト指向のソリューションは、ファクトリー・クラスです。ファクトリー・クラスの目的は、一般には入力基準に応じて他のオブジェクトを作成することですが、Butterfly のファクトリー・クラスである ButterflyFactory の場合は、リスト 8 に記載するような構成ファイルから Butterfly チェーンをアセンブルします。


リスト 8. Butterfly 構成ファイルの例

<butterfly-config>
  <chain>
    <name>resume</name>
    <source type="ButterflyXmlFile">
      <arg>resume.xml</arg>
    </source>
    <xslt file="resume-restructured.xsl"/>
    <xslt file="resume-restructured-to-view.xsl"/>
    <xslt file="resume-view-to-html.xsl"/>
  </chain>
</butterfly-config>

この構成ファイルが、Butterfly 変換チェーンを定義します。それぞれのチェーンには、まずソースが記述され、その後に適用する XSLT スタイルシートが任意の数、記述されます。この例で作成しているチェーンは 1 つで、このチェーンでは履歴書の XML 文書、resume.xml を 3 つのスタイルシート変換のシーケンスによって HTML ページにレンダリングします。フレームワークを使用する目的は作業を簡単なものにすることなので、構成を複雑にしてこの目的を台無しにしないように、構成は最小限にしてあります。

ButterflyFactory クラスはこの構成ファイル・フォーマットを読み取って、Butterfly オブジェクトのファクトリーとして動作します (リスト 9 を参照)。


リスト 9. ButterflyFactory

class ButterflyFactory {

  private $cacheDir;
  private $chains;

  public function __construct ($configFile, $cacheDir) {
    $this->cacheDir = $cacheDir;
    $config = simplexml_load_file($configFile);
    $this->chains = $this->mapChainsByName
       (is_array($config->chain) ? $config->chain : array($config->chain));
  }

  protected function mapChainsByName ($chains) {
    $byName = array();
    foreach ($chains as $chain) {
      $name = (string) $chain->name;
      if (isset($byName[$name])) {
    throw new Exception ("Two Butterfly chains defined with the same 
name: $name");
      }
      $byName[$name] = $chain;
    }
    return $byName;
  }

  protected function getChainByName ($name) {
    if (! isset($this->chains[$name])) {
      throw new Exception ("ButterflyFactory: no chain with specified 
name: $name");
    }
    return $this->chains[$name];
  }


  protected function createCacheFactory ($cacheDir) {
    return new ButterflyCacheFactory ($cacheDir);
  }

  protected function createButterflyObject ($transformer, $xmlDoc, $cache) {
    return new Butterfly ($transformer, $xmlDoc, $cache);
  }

  public function createButterfly ($xsltFilepath, $xmlDoc, $cache) {
    return $this->createButterflyObject
      ($this->createTransformerFromFilepath ($xsltFilepath), $xmlDoc, 
$cache);
  }
 
  protected function createTransformerFromFilepath ($xsltFilepath) {
    return new ButterflyTransformer (new ButterflyXmlFile($xsltFilepath));
  }

  public function getButterfly ($chainName) {

    $chain = $this->getChainByName ($chainName);  

    $source = $this->createChainSource ($chain);

    $invalidateCache = false;
    for ($i = 0; $i < count($chain->xslt); $i++) {
      $xslt = $chain->xslt[$i];

      $cache = $this->createButterflyCache
     ($this->createCacheFilename ((string) $chain->name, $i));

      if ($invalidateCache && $cache->isPresent()) {  
    $cache->delete();
      }

      $source = $this->createButterfly ((string) $xslt['file'], $source, 
$cache);

      $invalidateCache = $invalidateCache || ! $cache->isPresent();
    }

    return $source;
  }

  protected function createChainSource ($chain) {

    if (! isset($chain->source)) {
      throw new Exception ("Butterfly chain has no source element: 
$chainName");
    }
  
    $args = is_array($chain->source->arg)
       ? $chain->source->arg
       : array($chain->source->arg);

    $argsAsStrings = array();
    foreach ($args as $arg) {
      $argsAsStrings[] = (string) $arg;
    }

    return $this->createSourceFromType ((string) $chain->source['type'],
                    $argsAsStrings);
  }

  protected function createCacheFilename ($chainName, $xsltNumber) {
    return $this->cacheDir . '/' . $chainName . '_' . $xsltNumber . 
'.cache';
  }

  protected function createSourceFromType ($type, $args) {
    return call_user_func_array (array($type, 'create'), $args);
  }

  protected function createButterflyCache ($cacheFilePath) {
    return new ButterflyCache ($cacheFilePath);
  }    
}

ButterflyFactory は、構成ファイルのパスとキャッシュ・ディレクトリー (キャッシュされたすべての XSLT 変換を保持するディレクトリー) のパスから作成されます。このファクトリー・クラスは SimpleXML モジュールを使用して XML 構成ファイルを読み取り、構文解析を行って PHP オブジェクトにします。次に連想配列を作成し、定義された各チェーンをその名前にマッッピングして検索しやすくします。

ButterflyFactory の中心的メソッドは getButterfly() です。このメソッドは定義されたチェーンの名前を引数に取り、ButterflyXmlDocument を返します。返されたこのオブジェクトが、チェーン定義の性質によって Butterfly オブジェクトとなり、変換結果を返します。getButterfly() はまず、指定された名前 (例えば、この構成例の履歴書チェーンの場合には “resume”) を基準にチェーンを検索し、ソースである XML 文書オブジェクト (ButterflyXmlFile、または他の ButterflyXmlDocument 実装のいずれか) を定義する <source> 要素がチェーンに含まれていることを確認します。この <source> 要素の type 属性が、ソース文書オブジェクトとしてインスタンス化するクラスを指定します。「resume」チェーンの場合、ソースは ButterflyXmlFile です。

getButterfly() はソース・オブジェクトを取得すると、<chain> に定義された <xslt> 要素をループして、各要素から Butterfly オブジェクトを作成します。Butterfly はそのソース・オブジェクトを引数の 1 つとして取るため、最初の Butterfly オブジェクトにはチェーンの <source> 要素から作成されたソース・オブジェクトが指定されますが、Butterfly オブジェクト自体は $source 変数に割り当られ、ループで次に作成される Butterfly のソース・オブジェクトとなります。このループ処理は、最後のオブジェクトが結果を取得するために呼び出される Butterfly として返されるまで繰り返されます。Butterfly のチェーンはこのようにして作成されるため、返された Butterfly オブジェクトを呼び出すと、そのソースとなっているオブジェクト (おそらく Butterfly) が呼び出され、そのオブジェクトがそのまたソースのオブジェクトを呼び出すといった具合になり、最終的に実際のソース・オブジェクトが呼び出された時点で、そのオブジェクトの内容が呼び出し側の Butterfly に返されます。すると、呼び出し側 Butterfly はその XSLT スタイルシートを適用して結果をそのオブジェクトを呼び出したオブジェクトに返し、結果を返されたオブジェクトも同じことを繰り返すという動作が、チェーンの先頭が変換結果を返すまで、または標準出力に変換結果を書き込むまで続きます。

また、このループは $invalidateCache フラグを最新状態に保つことから、いずれかの Butterfly のキャッシュが削除されると、チェーン内でその上位にあるすべての Butterfly オブジェクトのキャッシュも削除されます。そのため、キャッシュ・ファイルが変換チェーンの任意のステップで削除されると、すべての従属 Butterfly キャッシュ・ファイルが無効になり、キャッシュ・ファイルが再作成されることになります。




上に戻る


次のステップ

これで、XSLT スタイルシート変換機構を適切に処理するフレームワークが完成しました。このフレームワークには、XSLT チェーンの作成や、HTML ページをレンダリングする際の XSLT 変換によるパフォーマンスの影響を排除するためのキャッシュ・ファイルの使用も盛り込まれています。フレームワークを設計する上で次のステップとなるのは、より高度なキャッシュ管理インターフェースを提供すること (現時点では、該当するキャッシュ・ファイルをユーザーが削除しなければなりません)、そしてSQL クエリーの結果を取得するような他の XML ソースを提供することです。リレーショナル SQL の結果を階層型 XML 文書に変換するために OR マッピングの指定が必要になるような構成では、ButterflyXmlSqlSource などのクラス自体を軽量のフレームワークにすることも可能です。他の可能性としては、キャッシュ・ファイルに SQL データベースを使用する方法も考えられますが、パフォーマンスに関して言えば、ディスク・アクセスと fpassthru() を使用するのが最善のソリューションであることに変わりはありません。




上に戻る


まとめ

Butterfly フレームワークは、PHP 5 で XSLT を簡単に使用できるようにして、スタイルシート・チェーンとキャッシングによるパフォーマンスの向上を実現する手軽な方法です。フレームワークとしては至ってシンプルでわかりやすい Butterfly ですが、そんな単純なフレームワークが、XSLT スタイルシートを適用する仕組みを PHP コードから切り離し、開発者が作業の核心、つまり XSLT 自体に専念できるようにします。この Butterfly についてさらに詳しく調べてみてください (「参考文献」を参照)。



参考文献

学ぶために
  • World Wide Web Consortium が管理する XSLT 2.0 勧告: XML 文書を別の XML 文書に変換するための言語、XSLT 2.0 の構文およびセマンティクスの詳細を読んでください。

  • XSLT はどのような言語か」(Michael Kay 著、developerWorks、2001年2月、2005年4月更新): XSLT とはどのような言語で、何のために存在し、なぜこのように設計されたのかという疑問に対する答えを見つけてください。

  • XSLT スタイル・シートと XML ディクショナリーによる国際化対応」(Laura Menke 著、developerWorks、2001年4月): XSLT が実世界の問題にどのように役立つかについての例を取り上げています。

  • How an XSLT processor works」(Benoit Marchal 著、developerWorks、2004年3月): XSLT の背後にある理論、そして XSLT でのプログラミングを迅速化するその再帰的性質について詳しく学んでください。

  • XSLT 2.0 で複数ファイルを作る」(Jack Herrington 著、developerWorks、2005年3月): この developerWorks の記事に、xsl:result-document の実行例が記載されています。

  • XSLT Web開発者ガイド」(Khun Yee Fung 著、Addison-Wesley、2000年12月): XSLT の包括的資料およびチュートリアルです。

  • XSLT Functions: w3school.com による広範囲にわたる参考資料です。

  • PHP.NET: PHP 開発者には欠かせない情報源です。

  • PHP 5 マイグレーション・ガイド」(Jack Herrington 著、developerWorks、2006年9月): PHP V4 で開発したコードを V5 に移行する方法を学んでください。

  • Learning PHP」(Tyler Anderson、Nicholas Chase 共著、developerWorks、2005年6月): このチューリアル・シリーズで、PHP でのプログラミング方法を学んでください。

  • IBM developerWork の PHP project resources: PHP について、そしてこのプログラミング言語で実行できる操作について詳しく学んでください。

  • Recommended PHP reading list」(Daniel Krook、Carlos Hoyos 共著、developerWorks、2006年3月): IBM Web アプリケーション開発者が、プログラマーと管理者にお薦めする資料のリストです。

  • PHP コンテンツ: developerWorks の Open source ライブラリーに豊富に揃った記事、チュートリアル・デモを参照してください。

  • IBM XML 認証: XML や関連技術の IBM 認定開発者になる方法について調べてください。

  • XML Technical library: 広範な技術に関する記事とヒント、チュートリアル、標準、そして IBM レッドブックについては、developerWorks XML ゾーンを参照してください。

  • developerWorks technical events and webcasts: これらのセッションで最新情報を入手してください。

  • technology bookstore: この記事で紹介した技術やその他の技術に関する本を参照してください。

  • developerWorks podcasts: ソフトウェア開発者向けの興味深いインタービューとディスカッションを聞いてください。


製品や技術を入手するために
  • Butterfly - a lightweight XSLT framework written for PHP 5: この小さな PHP 5 フレームワークを調べてください。このフレームワークは PHP での XSLT の使用を単純化し、Web ページを開発してスタイルシート変換の結果を素早く提供します。

  • IBM 製品評価用の試用版ソフトウェア: developerWorks から直接ダウンロードできるIBM ソフトウェアの試用版を利用して皆さんの次期プロジェクトを構築してください。DB2®、Lotus®、Rational®、Tivoli®、および WebSphere® によるアプリケーション開発ツールおよびミドルウェア製品のトライアル版が揃っています。


議論するために


著者について

Photo of Jacob Miles

Jake Miles は、ビジネスを対象としたあらゆるビデオ Web ソリューションを提供する新しい会社、Twistage, Inc. で Senior Technical Liaison を務めています。さまざまな言語とソフトウェア技術に経験を持ち、10 年間、プロの開発者として働いてきた彼は、子供のころから熱心な生徒で、10 歳のときからソフトウェアをいじり回していました。またボランティアで教師も務め、誰でもわかりやすく教えられれば何事も習得できると信じています。




記事の評価


サイト改善のため、ご意見をお寄せください。こちらのフォームからお願いいたします。



 


 


不充分・不完全である大変素晴らしい
 


この記事を共有する

del.icio.us del.icio.us newsing newsing FC2ブックマーク FC2ブックマーク
Choix! Choix! ニフティクリップ ニフティクリップ Yahoo!ブックマーク Yahoo!ブックマーク
MM/memo MM/memo CZブックマーク CZブックマーク livedoorクリップ livedoorクリップ
はてなブックマーク はてなブックマーク Buzzurl(バザール) Buzzurl(バザール)




上に戻る


Adobe、Adobe ロゴ、PostScript、および PostScript ロゴは、Adobe Systems Incorporated の米国およびその他の国における登録商標または商標です。 IBM、IBM ロゴ、ibm.com、DB2、developerWorks、Lotus、Rational、Tivoli、WebSphere、および pureXML は、International Business Machines Corporation の米国およびその他の国における商標または登録商標です。 Java およびすべての Java 関連の商標およびロゴは、Sun Microsystems, Inc. の米国およびその他の国における商標です。 他の会社名、製品名およびサービス名等はそれぞれ各社の商標です。

    日本IBMについて プライバシー お問い合わせ