目次


PHP 開発者のための XML

第 3 回 XML を読み取り、操作し、作成する高度な方法

DOM API と SimpleXML API に XSLT を追加する

Comments

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: PHP 開発者のための XML

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:PHP 開発者のための XML

このシリーズの続きに乞うご期待。

はじめに

PHP5 では、XML を扱うための機能が大幅に強化されています。DOM (Document Object Model) や SimpleXML、XSL など、新しい、そして修正されたエクステンションのおかげで、XML を扱う作業が以前ほどコード中心ではなくなりました。PHP5 では、DOM は W3C 標準に準拠しています。最も重要なこととして、この 3 つのエクステンションの間の相互運用性が大幅に高められた結果、例えばユーザビリティー向上のためにフォーマットを交換できることや W3C の XPath を使えることなどによって、全体的に新たな機能が実現されています。ここでは、入力と出力のオプションを見ていきます。そして Yahoo の Webサービスの REST プロトコル・インターフェースを使って、今やおなじみとなった DOM エクステンションと SimpleXML エクステンションの機能を、より高度な例を使って示します。そして最後に XSL エクステンションを説明して終わることにします。

このシリーズで前回までに説明した内容

このシリーズの第 1 回では、XML に関する必須事項を説明しました。そこではクイックスタート API (Application Programming Interface) に焦点を当て、単純かつ予測可能で比較的小規模な XML 文書を扱う場合に、SimpleXML が (必要な場合には DOM と組み合わせることで) 理想的な選択肢であることを説明しました。第 2 回では、PHP5 で XML を扱う際に利用可能なさまざまな構文解析 API (SimpleXML や DOM、SAX (Simple API for XML)、XMLReader など) を調べ、さまざまな規模や複雑さを持つ XML 文書に対して、どの構文解析方法が最も適切かを考えました。

PHP 5 での XML

XML (Extensible Markup Language) は、マークアップ言語であると同時にテキスト・ベースのデータ・ストレージ・フォーマットであると言われ、情報にツリー・ベースの構造を適用し、また情報をツリー・ベースの構造で記述するためのテキスト・ベースの方法でもあります。ここでは、エンタープライズの世界以外で XML が最近急速に成長している大きな要因と思われる、Web サービスの面から XML を見ることにします。

PHP5 には、XML を操作するための、まったく新規で完全に書き直されたエクステンションがあり、そのどれもが同じ libxml2 コードに基づいています。この共通ベースによってエクステンション間に相互運用性が確保され、その相互運用性によって、各エクステンションの機能が拡張されます。ツリー・ベースのパーサーとしては、SimpleXML と DOM、そして XSLT プロセッサーがあります。他の言語での経験から DOM に慣れている人は、PHP でも同様の機能をコーディングするのが以前よりも楽になるでしょう。ストリーム・ベースのパーサーとしては、SAX (Simple API for XML) と XMLReader があります。SAX の動作は PHP4 の場合と同じです。

DOM を使って XML を操作する

DOM を使って XML ファイルを操作することができます。DOM を使った方が効率的なのは、XML ファイルが比較的小さな場合のみです。この方法を使う利点は、おなじみの W3C DOM という強固な標準に基づいていること、さまざまな DOM メソッドが利用できること、柔軟なコーディングができることなどです。DOM が不利な点としては、大きな文書に対してはコーディングしにくく、パフォーマンスの問題があることです。

DOM の実際

DOM を利用することで、XML 文書を作成したり、修正したりすることができ、また同文書に対して、クエリーを実行したり、妥当性検証を行ったり、そして変換を行ったりすることができ、DOM のすべてのメソッドとプロパティーを利用することができます。DOM のレベル 2 メソッドの大部分は、さまざまなプロパティーが適切にサポートされて実装されています。DOM は非常に柔軟性が高いため、DOM で構文解析する文書はどんなに複雑でも構いません。ただし、大きな XML 文書全体を一度にメモリーにロードすると、柔軟性のコストが高くつくことを忘れないでください。

この記事の例では、Yahoo の検索 API と PHP5、そして REST (REpresentational State Transfer) を使って、興味深いアプリケーション環境の中で DOM を使う方法を説明します。Yahoo が REST を選んだのは、開発者の間で、REST は SOAP の利点の 80% を 20% のコストで実現すると一般的に信じられているためです。私がこのアプリケーションを PHP/XML の好例として選んだ理由は、エンタープライズの世界以外での XML の急速な成長の最も大きな要因として、Web サービスの人気があると考えられるためです。

通常、REST のリクエストを作成するためには、まずサービス・エントリー URL で始め、そしてクエリー・ストリングの形式で検索パラメーターを付加します。次に、リスト 1 で、クエリーの結果を DOM エクステンションを使って構文解析します。

リスト 1. DOM を使った場合の Yahoo Demo コードの例
<?php

//This query does a search for any Web pages relevant to "XML Query"
$query = "http://api.search.yahoo.com/WebSearchService/V1/webSearch?".
         "query=%5C%22XML%20Query%5C%22&appid=YahooDemo";

//Create the DOM Document object from the XML returned by the query
$xml = file_get_contents($query);
$dom = new DOMDocument;
$dom = DOMDocument::loadXML($xml);

function xml_to_result($dom) {

  //This function takes the XML document and maps it to a
  //PHP object so that you can manipulate it later.

  //First, retrieve the root element for the document
  $root = $dom->firstChild;

  //Next, loop through each of its attributes
  foreach($root->attributes as $attr) {
    $res[$attr->name] = $attr->value;
  }

  //Now, loop through each of the children of the root element
  //and treat each appropriately.

  //Start with the first child node.  (The counter, i, is for
  //tracking results.
  $node = $root->firstChild;
  $i = 0;

  //Now keep looping through as long as there is a node to work
  //with.  (At the bottom of the loop, the code moves to the next
  //sibling, so when it runs out of siblings, the routine stops.
  while($node) {

    //For each node, check to see whether it's a Result element or
    //one of the informational elements at the start of the document.
    switch($node->nodeName) {

      //Result elements need more analysis.
      case 'Result':
        //Add each child node of the Result to the result object,
        //again starting with the first child.
        $subnode = $node->firstChild;
        while($subnode) {

          //Some of these nodes just are just whitespace, which does
          //not have children.
          if ($subnode->hasChildNodes()){

            //If it does have children, get a NodeList of them, and
            //loop through it.
            $subnodes = $subnode->childNodes;
            foreach($subnodes as $n) {

              //Again check for children, adding them directly or
              //indirectly as appropriate.
              if($n->hasChildNodes()) {
                foreach($n->childNodes as $cn){
                   $res[$i][$subnode->nodeName][$n->nodeName]=
                                              trim($cn->nodeValue);
                }
            } else {
                $res[$i][$subnode->nodeName]=trim($n->nodeValue);
              }
            }
          }
          //Move on to the next subnode.
          $subnode = $subnode->nextSibling;
        }
        $i++;
        break;
      //Other elements are just added to the result object.
      default:
        $res[$node->nodeName] = trim($node->nodeValue);
        break;
    }

    //Move on to the next Result of informational element
    $node = $node->nextSibling;
  }
  return $res;
}

//First, convert the XML to a DOM object you can manipulate.
$res = xml_to_result($dom);

//Use one of those "informational" elements to display the total
//number of results for the query.
echo "<p>The query returns ".$res["totalResultsAvailable"].
            " total results  The first 10 are as follows:</p>";

//Now loop through each of the actual results.
for($i=0; $i<$res['totalResultsReturned']; $i++) {

    echo "<a href='".$res[$i]['ClickUrl']."'><b>".
                            $res[$i]['Title']."</b></a>:  ";
    echo $res[$i]['Summary'];

    echo "<br /><br />";
}

?>

SimpleXML を使って XML を操作する

XML 文書があまり複雑ではなく、あまり深くなく、複合コンテンツを持たない場合には、SimpleXML エクステンションはXML 文書の操作には最適なツールです。SimpleXML は (その名前のとおり) DOM よりもコーディングが容易です。また、既知の文書構造を扱う場合には、DOM よりもはるかに直感的です。DOM と SimpleXML の柔軟性が大幅に向上しているので、libXML2 アーキテクチャーによって、DOM から SimpleXML に、あるいはその逆にフォーマットを自在に交換してインポートを行うことができます。

SimpleXML の実際

SimpleXML で操作される文書は、簡単に素早くコーディングすることができます。下記のコードは、クエリーの結果を SimpleXML エクステンションを使って構文解析します。ご想像のとおり、下記の SimpleXML コード (リスト 2) は、上記のリスト 1 で示した DOM コードの例よりもコンパクトです。

リスト 2. Yahoo の SimpleXML の例
<?php

//This query does a search for any Web pages relevant to "XML Query"
$query = "http://api.search.yahoo.com/WebSearchService/V1/webSearch?".
         "query=%5C%22XML%20Query%5C%22&appid=YahooDemo";

$xml = simplexml_load_file($query);

// Load up the root element attributes
foreach($xml->attributes() as $name=>$attr) {
   $res[$name]=$attr;
}

//Use one of those "informational" elements to display the total
//number of results for the query.
echo "<p>The query returns ".$res["totalResultsAvailable"].
            " total results  The first 10 are as follows:</p>";

//Unlike with DOM, where we loaded the entire document into the
//result object, with SimpleXML, we get back an object in the
//first place, so we can just use the number of results returned
//to loop through the Result members.

for($i=0; $i<$res['totalResultsReturned']; $i++) {

    //The object represents each piece of data as a member variable
    //rather than an array element, so the syntax is a little bit
    //different from the DOM version.

    $thisResult = $xml->Result[$i];

    echo "<a href='".$thisResult->ClickUrl."'><b>".
                       $thisResult->Title."</b></a>:  ";
    echo $thisResult->Summary;

    echo "<br /><br />";
}

?>

リスト 3 は、リスト 2 の SimpleXML の例にキャッシュ・レイヤーを追加しています。このキャッシュは、どのようなクエリーの結果も 2 時間にわたってキャッシュします。

リスト 3. キャッシュ・レイヤーを持つ、Yahoo の SimpleXML の例
<?php

//This query does a search for any Web pages relevant to "XML Query"
$query = "http://api.search.yahoo.com/WebSearchService/V1/webSearch?".
         "query=%5C%22XML%20Query%5C%22&appid=YahooDemo";

//The cached material should only last for 2 hours, so you need the
//current time.
$currentTime = microtime(true);

//This is where I put my tempfile; you can store yours in a more
//convenient location.
$cache = 'c:\temp\yws_'.md5($query);

//First check for an existing version of the time, and then check
//to see whether or not it's expired.
if(file_exists($cache) &&
          filemtime($cache) > (time()-7200)) {

   //If there's a valid cache file, load its data.
   $data = file_get_contents($cache);
} else {

   //If there's no valid cache file, grab a live version of the
   //data and save it to a temporary file.  Once the file is complete,
   //copy it to a permanent file.  (This prevents concurrency issues.)
   $data = file_get_contents($query);
   $tempName = tempnam('c:\temp','YWS');
   file_put_contents($tempName, $data);
   rename($tempName, $cache);
}

//Wherever the data came from, load it into a SimpleXML object.
$xml = simplexml_load_string($data);

//From here, the rest of the file is the same.

// Load up the root element attributes
foreach($xml->attributes() as $name=>$attr) {
   $res[$name]=$attr;
}

...

XSL を使って XML を操作する

XSL (EXtensible Stylesheet Language) は、XML 文書を操作する作業のために作成された、機能的な XML 言語です。XSL を使うと、CSS がルールを実装して動作する方法と同様に、スタイルシート定義に基づいて、ある XML 文書を、再定義された XML 文書や XHTML 文書、HTML 文書、あるいはテキスト文書に変換することができます。PHP5 での W3C 標準の実装では、DOM と XPath との間に相互運用性があります。XSLT (EXtensible Stylesheet Language Transformations) は libxml2 をベースとする XML エクステンションであり、XSLT のスタイルシートは XML 文書です。XSLT は、XML ソース・ツリーを XML 結果ツリーあるいは XML 型の結果ツリーに変換します。こうした変換によって、スタイルシートの中で指定された一連のルールが XML データに適用されます。XSLT は出力ファイルに対して、要素あるいは属性を追加、あるいは削除します。これを利用すれば、要素をソートあるいは再配置することができ、またどの要素を隠し、どの要素を表示するかを決定することができます。さまざまなスタイルシートを用意することによって、さまざまなメディアに XML を適切に表示することができます (例えば画面表示か印刷表示かなど)。XSLT は、XPath を使ってオリジナルの XML 文書の中をナビゲートします。XSLT の変換モデルに通常含まれるものとしては、ソース XML ファイル、1 つ以上の処理テンプレートを含む XSLT ファイル、XSLT プロセッサーがあります。XSLT 文書は、DOM を使ってロードする必要があります。PHP5 は libxslt プロセッサーのみをサポートしています。

XSL の実際

XSL の興味深いアプリケーションとして、データベースから選択されたばかりの任意のデータを含むXML ファイルを、即時処理で作成します。この方法を使うと、データベースに対してクエリーを実行した結果の XML ファイルで PHP スクリプトが構成され、そして XSL 変換を使って実際の HTML 文書を生成する、完全な Web アプリケーションを作成することができます。

この方法ではプレゼンテーション・レイヤーがビジネス・レイヤーと完全に分離されるため、それぞれのレイヤーを、他方とは独立に維持管理することができます。

リスト 4 は、XML 入力ファイルと XSL スタイルシート、XSLT プロセッサー、そして考えられるいくつかの出力の間の関係を示しています。

リスト 4. XML 変換
<?php

// Create new XSLTProcessor
$xslt = new XSLTProcessor();

//Both the source document and the stylesheet must be
//DOMDocuments, but the result can be a DOMDocument,
//a file, or even a String.

// Load the XSLT stylesheet
$xsl = new DOMDocument();
$xsl->load('recipe.xsl');

// Load the stylesheet into the processor
$xslt->importStylesheet($xsl);

// Load XML input file
$xml = new DOMDocument();
$xml->load('recipe.xml');

//Now choose an output method and transform to it:

// Transform to a string
$results = $xslt->transformToXML($xml);
echo "String version:";
echo htmlentities($results);

// Transform to DOM object
$results = $xslt->transformToDoc($xml);
echo "The root of the DOM Document is ";
echo $results->documentElement->nodeName;

// Transform to a file
$results = $xslt->transformToURI($xml, 'results.txt');

?>

まとめ

このシリーズの最初の方では、Document Object Model と SimpleXML を使った構文解析を、単純な場合と複雑な場合の両方に関して調べました。また第 2 回では、XMLReader の使い方も調べました。XMLReader を使うことで、これまで SAX を使って行っていた作業を、より高速に容易に行うことができます。

そして今回の記事では、REST ベースの Web サービスなどのリモート・ファイルにアクセスする方法について、また XSLT を使って XML データをストリングや DOM 文書オブジェクト、ファイルなどに容易に出力する方法について説明しました。


ダウンロード可能なリソース


関連トピック

  • この 3 回シリーズの第 1 回、「PHP 開発者のための XML、第 1 回: PHP での XML を 15 分で学ぶ」(Cliff Morgan 著、developerWorks、2007年2月) を読んで PHP5 での XML 実装を知り、PHP 環境での XML の処理がいかに容易かを学んでください。
  • このシリーズの第 2 回、「PHP 開発者のための XML、第 2 回: 高度な XML 構文解析方法」(Cliff Morgan 著、developerWorks、2007年3月) では、PHP5 でのさまざまな XML 構文解析方法を説明しています。アプリケーションにとって最適な構文解析方法を学んでください。
  • ヒント: 効率的な伝送のために XML ファイルを圧縮する」(Uche Ogbuji 著、developerWorks、2004年4月) を読み、Web サービスでの送信用に、圧縮を使って XML を準備する方法を学んでください。
  • Tip: Use Language specific tools for XML processing」(Uche Ogbuji 著、developerWorks、2004年1月) を読み、XML を構文解析する際に SAX や DOM に代わるこの記事に記載されている方法を試してください。
  • 2 回シリーズの記事、「Developing PHP the AJAX way, Part 1: Getting started」(Sean Kelly 著、developerWorks、2006年5月) と「Ajaxを利用してPHPを開発する、第2回: 「戻る」「進む」「更新」」(Mike Brittain 著、developerWorks、2006年6月) では、オンラインの Web アプリケーションとして、単純な写真のアルバムを PHP と Sajax (Simple Ajax Toolkit) のみを使って作成しています。
  • 2 回シリーズの記事、「XML 転送のパフォーマンスを改善する 第 1 回」と「XML 転送のパフォーマンスを改善する 第 2 回」(Dennis Sosnoski 著、developerWorks、2004年6月) は、XML を非テキスト型で表現する方法に関する問題を解説し、その目的のために現在開発中の手法について調べています。
  • Intuition and Binary XML」(Leigh Dodds 著、XML.com、2001年4月) では、XML をバイナリー・エンコードするという代替方法について議論しています。
  • このオンライン・プレゼンテーション「Workshop: XML in PHP5」を見てください。
  • XSLTはどのような言語か」(Michael Kay 著、developerWorks、2005年4月) を読み、この言語の由来や、XSLT が得意なこと、なぜ XSLT を使うべきなのかといった面から XSLT を学んでください。
  • ヒント記事、「Tip: Implement XMLReader: An interface for XML converters」(Benoit Marchal 著、developerWorks、2003年11月) を読んで XML パイプライン用の API を探ってください。
  • Reading and writing the XML DOM in PHP」(Jack Herrington 著、developerWorks、2005年12月) では、XML を読むための方法として、DOM ライブラリー、SAX パーサー、正規表現という 3 つを解説しています。またこの記事では、DOM と PHP テキスト・テンプレートを使って XML を書く方法も学ぶことができます。
  • PHP での SimpleXML 処理」(Elliotte Rusty Harold 著、developerWorks、2006年10月) を読んで SimpleXML エクステンションを試し、そして PHP ページで XML をクエリーし、検索し、変更し、再公開できるようにしてください。
  • PHP V5 マイグレーション・ガイド」(Jack Herrington 著、developerWorks、2006年9月) を読み、PHP V4 で開発されたコードを V5 に移行してください。コードの保守容易性と安定性が大幅に向上します。
  • SimpleXML に関する 3 回シリーズの記事の第 1 回、「Introducing Simple XML in PHP5」(Alejandro Gervasio 著、Dev Shed、2006年6月) を読み、主に単純な XML ファイルの構文解析を目的とするライブラリー、PHP5 の simplexml エクステンションの基本を学び、作業に役立ててください。
  • PHP Cookbook, Second Edition』(Adam Trachtenberg と David Sklar の共著、O'Reilly Media 刊、2006年8月) を読み、任意の Web ブラウザーで動作する動的な Web アプリケーションの作成方法を学んでください。
  • O'Reilly の XML サイト、XML.com は XML の世界を包括的に網羅しています。
  • W3C の XML サイトで XML 仕様の原典を読んでください。
  • PHP 開発のホーム・サイトを訪れ、特に Web 開発に適した、そして広く使われている、この汎用スクリプト言語について学んでください。
  • PHP 開発者コミュニティーのニュース源、Planet PHP を訪れてください。
  • XML および関連技術において IBM 認証開発者になる方法については、IBM XML certification を参照してください。
  • developerWorks の XML ゾーンは、XML の技術ライブラリーとして、広範な話題を網羅した技術記事やヒント、チュートリアル、技術標準、IBM レッドブックなどを用意しています。
  • PEAR: PHP Extension and Application Repository を訪れ、再利用可能な PHP コンポーネントのためのフレームワークであり、配布システムでもある PEAR に関する情報を入手してください。
  • PEAR の兄弟サイト、PECL: PHP Extension Community Library は PHP エクステンションのリポジトリーです。
  • Libxml2 で Gnome の XML C パーサーとツールキットを入手してください。
  • 皆さんの次期開発プロジェクトを IBM trial software を使って構築してください。developerWorks から直接ダウンロードすることができます。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Open source
ArticleID=249941
ArticleTitle=PHP 開発者のための XML: 第 3 回 XML を読み取り、操作し、作成する高度な方法
publish-date=03132007