レベル: 初級 Cliff Morgan (cliffmorgan@webproducer.us), Writer, Freelance
2007年 2月 27日 3 回シリーズの第 1 回の今回は、PHP5 の XML 実装を紹介します。そして、まだ PHP で XML を使うことに慣れていない人達のために、PHP 環境の DOM と SimpleXML を使って、短くて簡単な XML ファイルを読み取り、構文解析し、操作し、そして作成する方法について説明します。
はじめに
今日のアプリケーション開発環境では、XML の重要性を無視することはできません。この入門ガイドでは、まだ PHP で XML を扱ったことがない人、あるいはまだ PHP5 に移行していない人のために、XML に関して PHP5 に追加された新機能の利用方法を紹介します。この記事を読むことによって、PHP5 では XML の処理がいかに容易であるかを理解できるはずです。今回は 3 回シリーズの第 1 回として、クイック・スタート API に焦点を当て、開発者が単純かつ予測可能で比較的小規模な XML 文書を扱う場合に、SimpleXML が (必要な場合には DOM と組み合わせることで) いかに理想的な選択肢であるかを説明します。このような文書こそ、まさに、送信フォームのコンテンツを含む Ajax アプリケーションや、weather.com などの Web サービス API (application programming interface) のレスポンスを含む Ajax アプリケーションなどが渡す種類の文書なのです。
XML の基本
なぜ XML が PHP 開発者にとって重要かを理解するために、また単純な XML 文書を理解し、作成できるようになるために、少し XML の背景を説明した方がよいでしょう。
XML について
XML (Extensible Markup Language) は、説明する人によって、マークアップ言語であるとも、テキスト・ベースのデータ・ストレージ・フォーマットであるとも言われます。XML は SGML (Standard Generalized Markup Language) のサブセットであり、情報にツリー構造を適用し、また情報をツリー構造で記述するためのテキスト・ベースの手段でもあります。XML をベースにしている言語やフォーマットには、RSS (Really Simple Syndication) や Mozilla の XUL (XML User Interface Language)、Macromedia の MXML (Maximum eXperience Markup Language), Microsoft のXAML (eXtensible Application Markup Language)、そしてオープンソースの Java 用 XML UI マークアップ言語である XAMJ (Xml Application Markup language for Java) などがあります。さまざまな種類の XML があることからもわかるように、XML は非常に重要であり、誰もが XML の流れに乗ろうとしています。
XML を作成する
XML の基本データ単位は要素です。要素は、<book> などの開始タグと、</book> などの終了タグで区切られます。開始タグがあるならば、必ず終了タグもなければなりません。各開始タグに対して終了タグを含めるのを忘れると、その XML 文書は整形式ではなくなり、パーサーはその文書を適切に構文解析することができません。タグには通常、その要素の中に含まれる内容のタイプを反映した名前が付けられます。例えば book という名前の要素であれば、本の標題 (例えば Great American Novel など) を含むと考えられます (リスト 1)。タグとタグの間の内容は、空白を含めて、文字データと呼ばれます。
リスト 1. XML 文書の例
<books>
<book>
<title>Great American Novel</title>
<characters>
<character>
<name>Cliff</name>
<desc>really great guy</desc>
</character>
<character>
<name>Lovely Woman</name>
<desc>matchless beauty</desc>
</character>
<character>
<name>Loyal Dog</name>
<desc>sleepy</desc>
</character>
</characters>
<plot>
Cliff meets Lovely Woman. Loyal Dog sleeps, but wakes up to bark
at mailman.
</plot>
<success type="bestseller">4</success>
<success type="bookclubs">9</success>
</book>
</books>
|
XML の要素名と属性名を構成する文字としては、大文字のアルファベット A から Z、小文字のアルファベット a から z、数字の 0 から 9、ある特別な英語ではない文字、3 種類の句読記号、ハイフン、アンダーバー、そしてピリオドがあります。他の句読記号を名前に使うことはできません。
XML では大文字小文字を区別します。この例では、<Book> と <book> は2 つの別々の要素を表し、どちらも要素名として有効です。2 つの異なる要素を <Book> と <book> を使って記述することは、書き間違える可能性が高いことから、あまり適切ではありません。
XML 文書には、それぞれルート要素がただ 1 つだけ含まれています。ルート要素は、XML 文書の中で親を持たない唯一の要素です。上記の例では、ルート要素は <books> です。たいていの XML 文書には、親要素と子要素が含まれています。<books> 要素は、<book> という子を 1 つ持っています。<book> 要素は、<title> と <characters>、<plot>、<success> という 4 つの子を持っています。<characters> 要素は 3 つの子要素を持ち、それぞれが <character> 要素です。各 <character> 要素は、<name> と <desc> という 2 つの子要素を持っています。
要素のネストが親子関係を作るのに加え、XML 要素は属性を持つこともできます。属性は名前と値の対であり、要素の開始タグに付加されます。名前と値は等号 = によって分離され、値は単一引用符あるいは二重引用符で囲まれます。上記のリスト 1 では、<success> 要素は “bestseller” と “bookclubs” という 2 つの属性を持っています。XML 開発者の間では、属性の使い方に関してこれとは異なる考え方もあります。ある属性に含まれる情報の大部分は子要素の中に含めることもできるのです。しかし一部の開発者は、属性情報はメタデータ、つまりデータに関する情報のはずであり、データそのものではないと主張します。データそのものであれば、要素の中に含める必要があります。属性を使用するかどうかの選択は、実際にはデータの性質と、そのデータがどのように XML から抽出されるかに依存します。
XML の強み
XML が良質である点の 1 つは、比較的単純であることです。XML は基本的なテキスト・エディターやワード・プロセッサーを使って作成でき、特別なツールやソフトウェアを必要としません。XML の基本的な構文はネストした要素で構成され、一部の要素は属性と内容を持っています。要素は通常、開始タグと終了タグという 2 つのタグで構成され、それぞれのタグは開始の <tag > と終了の < /tag > のように大括弧で囲まれます。XML は大文字小文字を区別し、空白を無視しません。XML は多くの人におなじみの HTML と非常に似ていますが、HTML とは異なり、タグには最も適切にデータを表す名前を付けることができます。それ以外に XML の利点としては、自己記述型で人間にも機械にも読み取れるフォーマットであること、Unicode をサポートしているため人間の言葉に関する部分の国際化が可能なこと、構文や構文解析に対する要求が厳しいことなどがあげられます。残念ながら、PHP5 では UTF-8 は問題を起こしがちです。この欠点が、PHP6 を開発する推進力の 1 つとなっています。
XML の弱み
XML は大量のテキストを含んで冗長であり、その結果として保存するための容量も大きく、そして膨大な帯域幅を消費します。人間も XML を読めるはずですが、7 百万ものノードを持つ XML ファイルを人間が読めるとは思えません。最も基本的なパーサー機能は、あまり広範なデータ型をサポートしていません。そのため XML によく含まれている不規則なデータや例外的なデータは、構文解析が困難となる主な原因となっています。
整形式の XML
XML の構文規則のすべてに従っている場合、その XML 文書は整形式です。ある文書が整形式ではない場合、その文書は技術的な意味では XML ではありません。<br> のような HTML タグは XML では受け入れられません。整形式の XML であるためには、タグを <br /> のように書く必要があります。XML が整形式ではないと、パーサーはその XML を適切に構文解析することができません。さらに、XML 文書はルート要素をただ 1 つだけ含む必要があります。1 つのルート要素は、終わりのないファイル・キャビネットのようなものと考えられます。ファイル・キャビネットは 1 つですが、そのファイル・キャビネットの中に入れるもの、そして入れる量に関して、ほとんど制限がありません。つまり無限の引き出しやフォルダーがあり、そこにいくらでも情報を詰め込めるのです。
PHP の基本
この記事の読者の大部分は既に PHP を扱っていると思いますが、PHP が発展してきた歴史については知らないかもしれません。
PHP について
PHP (Hypertext Preprocessor) は、クロスプラットフォームのスクリプト言語として、動的な Web ページやサーバー・サイド・アプリケーション・ソフトウェアを作成するために使われています。PHP は PHP/FI (Personal Home Page/Form Interpreter) として始まり、Suraski と Gutmans の手によって新たな命を吹き込まれ、この 2 人が 1998 年の 6 月に PHP3 として最初のリリースを行いました。彼らの会社、Zend Technologies は、現在も PHP の開発を管理しています。
PHP5 は2004 年の 7 月にリリースされ、Zend Engine II によって強化されており、次のような多くの新機能を含んでいます。
- オブジェクト指向プログラミングを新たにサポート
- MySQL サポートの改善
- XML サポートの改善 (皆さんはこれに関心があるはずです)
PHP5 と XML
PHP は初期のバージョンから XML をサポートしてきましたが、PHP5 の導入によって、そのサポートが指数関数的に改善されています。PHP4 での XML サポートは少し限定的でした (例えば、デフォルトで有効なパーサーは SAX ベースのみであることや、PHP4 の DOM が W3C 標準を実装していないなど)。そのため PHP XML の開発者達は、いわゆる PHP5 として作り直し、一般的に使われる標準に準拠するようにしたのです。
PHP5 で XML に関して新しくなった点
PHP5 には、完全に作成し直された新規のエクステンションが含まれています (例えば SAX パーサーや DOM、SimpleXML、XMLReader、XMLWriter、そして XSLT プロセッサーなど)。こうしたエクステンションは、今やすべて libxml2 をベースにしています。
PHP5 は、PHP4 よりも改善された SAX サポートの他、W3C に従う DOM と SimpleXML エクステンションをサポートしています。SAX も DOM も SimpleXML も、すべてデフォルトで有効です。他の言語での経験から DOM に慣れている人は、PHP でも同様の機能をコーディングするのが以前よりも楽になるでしょう。
PHP5 で XML を読み取り、操作し、作成する
SimpleXML は、(必要な場合は DOM と組み合わせることで)、単純で予測可能な、そして比較的小規模な XML 文書扱う開発者が PHP5 で XML を読み、操作し、書く上で、理想的な選択肢です。
最適なクイック・スタート API
PHP5 で利用できる多くの API の中で、DOM と SimpleXML は最も馴染みがあるものです。DOM は最もコーディングしやすく、また SimpleXML は、ここで説明するような大部分の一般的な状況において、最も機能豊富です。
DOM エクステンション
DOM (Document Object Model) は、HTML 文書や XML 文書を表現するための W3C 標準のオブジェクト・セットであり、そうしたオブジェクトの組み合わせに関する標準モデルであり、そしてそれらを利用し、操作するための標準インターフェースです。多くのベンダーが、ベンダー独自のデータ構造や API へのインターフェースとして DOM をサポートしています。そうしたことから DOM モデルに慣れた開発者が多く、DOM モデルは信頼されています。メモリー上での DOM の構造は元々の XML 文書と似ているため、DOM は理解しやすく、また容易に使いこなすことができます。DOM はアプリケーションに情報を渡すために、XML ファイルの要素ツリーをそのまま複製したオブジェクト・ツリーを作成します (各 XML 要素がツリーのノードです)。DOM はツリー・ベースのパーサーです。DOM は文書全体のツリーを作成するため、大量のメモリーと CPU 時間を使用します。従って、パフォーマンスの問題から、大きな文書を DOM で構文解析するのは非現実的です。この記事の中での DOM エクステンションの主な使用法は、ストリングあるいは XML ファイルとして使用するために、SimpleXML フォーマットをインポートして DOM フォーマットの XML を出力する、あるいはその逆の使い方です。
SimpleXML
SimpleXML エクステンションは、XML 文書を構文解析するために最適なツールです。SimpleXML エクステンションは、PHP5 を必要としており、また XML ファイルの作成と、組み込み XPath のサポートを行うために、DOM との相互運用ができるようになっています。SimpleXML は、複雑でなく、レコード形式のようなデータ (例えば同じアプリケーション内部の別の部分から文書あるいはストリングとして渡される XML など) に最適です。その XML 文書があまり複雑ではなく、あまり深くなく、複合コンテンツを含まなければ、SimpleXML は (その名前どおり) DOM よりもコーディングが容易です。また、既知の文書構造を扱う場合には、DOM よりも高い信頼性を持っています。
クイック・スタートの例
ここからは、小規模の典型的な XML ファイルに対して、DOM と SimpleXML を使ったクイック・スタートの例をあげます。
DOM の実際
ここで使われる DOM は、皆さんがブラウザーの中で使用し、JavaScript で操作する W3C の DOM 仕様です。その DOM と同じメソッドを持っているため、おなじみのコーディング手法を使うことができます。リスト 2 は、DOM を使って XML ストリングと XML 文書を作成する方法を説明しています (見やすいように整形してあります)。
リスト 2. DOM を使う
<?php
//Creates XML string and XML document using the DOM
$dom = new DomDocument('1.0');
//add root - <books>
$books = $dom->appendChild($dom->createElement('books'));
//add <book> element to <books>
$book = $books->appendChild($dom->createElement('book'));
//add <title> element to <book>
$title = $book->appendChild($dom->createElement('title'));
//add <title> text node element to <title>
$title->appendChild(
$dom->createTextNode('Great American Novel'));
//generate xml
$dom->formatOutput = true; // set the formatOutput attribute of
// domDocument to true
// save XML as string or file
$test1 = $dom->saveXML(); // put string in test1
$dom->save('test1.xml'); // save as file
?>
|
これによって、リスト 3 の出力ファイルが作成されます。
リスト 3. 出力ファイル
<?xml version="1.0"?>
<books>
<book>
<title>Great American Novel</title>
</book>
</books>
|
リスト 4 は SimpleXMLElement オブジェクトを DOMElement オブジェクトにインポートしており、DOM と SimpleXML の相互運用性を説明しています。
リスト 4. 相互運用性その 1 -- DOM が SimpleXML をインポートする
<?php
$sxe = simplexml_load_string('<books><book><title>'.
'Great American Novel</title></book></books>');
if ($sxe === false) {
echo 'Error while parsing the document';
exit;
}
$dom_sxe = dom_import_simplexml($sxe);
if (!$dom_sxe) {
echo 'Error while converting XML';
exit;
}
$dom = new DOMDocument('1.0');
$dom_sxe = $dom->importNode($dom_sxe, true);
$dom_sxe = $dom->appendChild($dom_sxe);
echo $dom->save('test2.xml');
?>
|
リスト 5 の関数は、DOM 文書のあるノードを取得して SimpleXML のノードに変えます。そうすると、この新しいオブジェクトをネイティブの SimpleXML 要素として使うことができます。もしエラーが起きると、FALSE を返します。
リスト 5. 相互運用性その 2 -- SimpleXML がDOM をインポートする
<?php
$dom = new domDocument;
$dom->loadXML('<books><book><title>Great American
Novel</title></book></books>');
if (!$dom) {
echo 'Error while parsing the document';
exit;
}
$s = simplexml_import_dom($dom);
echo $s->book[0]->title; // Great American Novel
?>
|
SimpleXML の実際
SimpleXML エクステンションは、XML 文書を構文解析するための最適ツールです。SimpleXML エクステンションは、XML ファイルの作成と、組み込み XPath のサポートを行うために、DOM との相互運用ができるようになっています。SimpleXML は (その名前どおり) DOM よりもコーディングが簡単です。
まだ PHP に慣れていない人のために、リスト 6 はテスト用の XML ファイルを、見やすいようにインクルードとしてフォーマットしています。
リスト 6. example.php という PHP のインクルードとして (下記のコード・サンプルの中に) フォーマットされたテスト用の XML ファイル
<?php
$xmlstr = <<<XML
<books>
<book>
<title>Great American Novel</title>
<characters>
<character>
<name>Cliff</name>
<desc>really great guy</desc>
</character>
<character>
<name>Lovely Woman</name>
<desc>matchless beauty</desc>
</character>
<character>
<name>Loyal Dog</name>
<desc>sleepy</desc>
</character>
</characters>
<plot>
Cliff meets Lovely Woman. Loyal Dog sleeps, but wakes up to bark
at mailman.
</plot>
<success type="bestseller">4</success>
<success type="bookclubs">9</success>
</book>
</books>
XML;
?>
|
Ajax アプリケーションでは、XML 文書から郵便番号を抽出してデータベースに照会したいことがあるかもしれません。りスト 7 は、上記のサンプル XML インクルードから直接 <plot> を抽出します。
リスト 7. ノードを抽出する -とても簡単です
<?php
include 'example.php';
$xml = new SimpleXMLElement($xmlstr);
echo $xml->book[0]->plot; // "Cliff meets Lovely Woman. ..."
?>
|
また、複数行にまたがる住所を抽出したいかもしれません。ある要素の複数インスタンスが 1 つの親要素の子として存在する場合には、通常の繰り返し方法を適用します。リスト 8 はこの機能を示しています。
リスト 8. ある要素の複数インスタンスを抽出する
<?php
include 'example.php';
$xml = new SimpleXMLElement($xmlstr);
/* For each <book> node, echo a separate <plot>. */
foreach ($xml->book as $book) {
echo $book->plot, '<br />';
}
?>
|
SimpleXML は、要素の名前と値を読むことに加えて、要素の属性にもアクセスすることができます。リスト 9 では、配列の要素にアクセスするのとまったく同じように、要素の属性にアクセスします。
リスト 9. SimpleXML が要素の属性にアクセスする
<?php
//Input XML file repeated for your convenience
$xmlstr = <<<XML
<?xml version='1.0' standalone='yes'?>
<books>
<book>
<title>Great American Novel</title>
<characters>
<character>
<name>Cliff</name>
<desc>really great guy</desc>
</character>
<character>
<name>Lovely Woman</name>
<desc>matchless beauty</desc>
</character>
<character>
<name>Loyal Dog</name>
<desc>sleepy</desc>
</character>
</characters>
<plot>
Cliff meets Lovely Woman. Loyal Dog sleeps, but wakes up to bark
at mailman.
</plot>
<success type="bestseller">4</success>
<success type="bookclubs">9</success>
</book>
</books>
XML;
?>
<?php
include 'example.php';
$xml = new SimpleXMLElement($xmlstr);
/* Access the <success> nodes of the first book.
* Output the success indications, too. */
foreach ($xml->book[0]->success as $success) {
switch((string) $success['type']) {
// Get attributes as element indices
case 'bestseller':
echo $success, ' months on bestseller list';
break;
case 'bookclubs':
echo $success, ' bookclub listings';
break;
}
}
?>
|
要素または属性を、ストリングと比較したり、あるいはストリングを要求する関数に渡したりするためには、その要素または属性を (string) を使ってストリングにキャストする必要があります。そうしないと、PHP はデフォルトで、その要素をオブジェクトとして扱います (リスト 10)。
リスト 10. ストリングと呼ぶか、あるいは失うか
<?php
include 'example.php';
$xml = new SimpleXMLElement($xmlstr);
if ((string) $xml->book->title == 'Great American Novel') {
print 'My favorite book.';
}
htmlentities((string) $xml->book->title);
?>
|
SimpleXML でのデータは、定数である必要はありません。リスト 11 は、下記の新しい XML 文書を出力します。この文書はオリジナルとほとんど同じですが、新しい XML は Cliff を Big Cliff に変更します。
リスト 11. SimpleXML を使ってテキスト・ノードを変更する
<?php
$xmlstr = <<<XML
<?xml version='1.0' standalone='yes'?>
<books>
<book>
<title>Great American Novel</title>
<characters>
<character>
<name>Cliff</name>
<desc>really great guy</desc>
</character>
<character>
<name>Lovely Woman</name>
<desc>matchless beauty</desc>
</character>
<character>
<name>Loyal Dog</name>
<desc>sleepy</desc>
</character>
</characters>
<plot>
Cliff meets Lovely Woman. Loyal Dog sleeps, but wakes up to bark
at mailman.
</plot>
<success type="bestseller">4</success>
<success type="bookclubs">9</success>
</book>
</books>
XML;
?>
<?php
include 'example.php';
$xml = new SimpleXMLElement($xmlstr);
$xml->book[0]->characters->character[0]->name = 'Big Cliff';
echo $xml->asXML();
?>
|
SimpleXML は PHP 5.1.3 以降、子と属性を容易に追加できるようになっています。リスト 12 は、オリジナルの文書に基づく、新しい登場人物と記述子を持つ XML 文書を出力します。
リスト 12. SimpleXML を使って子とテキスト・ノードを追加する
<?php
$xmlstr = <<<XML
<?xml version='1.0' standalone='yes'?>
<books>
<book>
<title>Great American Novel</title>
<characters>
<character>
<name>Cliff</name>
<desc>really great guy</desc>
</character>
<character>
<name>Lovely Woman</name>
<desc>matchless beauty</desc>
</character>
<character>
<name>Loyal Dog</name>
<desc>sleepy</desc>
</character>
<character>
<name>Yellow Cat</name>
<desc>aloof</desc>
</character>
</characters>
<plot>
Cliff meets Lovely Woman. Loyal Dog sleeps, but wakes up to bark
at mailman.
</plot>
<success type="bestseller">4</success>
<success type="bookclubs">9</success>
</book>
</books>
XML;
?>
<?php
include 'example.php';
$xml = new SimpleXMLElement($xmlstr);
$character = $xml->book[0]->characters->addChild('character');
$character->addChild('name', 'Yellow Cat');
$character->addChild('desc', 'aloof');
$success = $xml->book[0]->addChild('success', '2');
$success->addAttribute('type', 'reprints');
echo $xml->asXML();
?>
|
まとめ
3 回シリーズ第 1 回の今回は、クイック・スタート API に焦点を当て、単純かつ予測可能で比較的小規模な XML 文書を扱う開発者にとって、SimpleXML が (必要な場合には DOM と組み合わせることで) いかに理想的な選択肢であるかを説明しました。PHP5 によって、開発者が PHP を使って XML を処理できる内容が大幅に向上しました。第 2 回は、高度な XML 構文解析方法に焦点を当てる予定です。
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | |  | Cliff Morgan is an independent consultant who designs and implements Web applications and Web sites. |
記事の評価
|