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

developerWorks Japan  >  XML | Open source  >

PHP 開発者のための XML: 第 3 回 XML を読み取り、操作し、作成する高度な方法

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

developerWorks
ページオプション

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

原文はこちら

原文はこちら


レベル: 中級

Cliff Morgan (cliffmorgan@webproducer.us), Writer, Freelance

2007年 3月 13日

3 回シリーズの最終回である今回は、PHP5 で XML を読み取り、操作し、作成するための、その他の方法について解説します。ここでは、今やおなじみとなった API である DOM と SimpleXML について、より高度な環境での使い方に焦点を当て、またこの 3 回シリーズでは初めて、XSL エクステンションについても説明します。

はじめに

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 文書オブジェクト、ファイルなどに容易に出力する方法について説明しました。



参考文献



著者について

Cliff Morgan は独立コンサルタントとして Web アプリケーションや Web サイトの設計や実装を行っています。




記事の評価


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



はいいいえわからない
 


 


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


この記事を共有する

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




上に戻る


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