PHP で XML を読み書きするためのテクニックは数多くあります。この記事では、XML を読み取るための 3 つの方法 (DOM ライブラリの使用、SAX パーサーの使用、および正規表現の使用) を説明します。 DOM および PHP テキスト テンプレートを使用した XML の作成についても説明します。
PHP で Extensible Markup Language (XML) を読み書きするのは、少し怖いように思えるかもしれません。実際、XML とそれに関連するすべてのテクノロジは恐ろしいものですが、PHP での XML の読み取りと書き込みは、必ずしも恐ろしい作業である必要はありません。まず、XML とは何なのか、XML を使って何ができるのかについて少し学ぶ必要があります。次に、PHP で XML を読み書きする方法を学ぶ必要があります。これを行う方法はたくさんあります。
この記事では、XML について簡単に説明した後、PHP を使用して XML を読み書きする方法について説明します。
XML とは何ですか?
XML はデータ保存形式です。どのようなデータが保存されるかは定義されず、データの形式も定義されません。 XML は単にタグとそのタグの属性を定義するだけです。整形式の XML マークアップは次のようになります。
<名前>ジャック・ヘリントン</名前>
この <name> タグには、「Jack Herrington」というテキストが含まれています。
テキストを含まない XML マークアップは次のようになります。
<パワーアップ/>
XML で何かを記述する方法は複数あります。たとえば、このタグは前のタグと同じ出力を形成します。
<パワーアップ></パワーアップ>
XML タグに属性を追加することもできます。たとえば、この <name> タグには最初と最後の属性が含まれています。
<name first="ジャック" last="ヘリントン" />
特殊文字も XML でエンコードできます。たとえば、& 記号は次のようにエンコードできます。
&
タグと属性を含む XML ファイルは、例のようにフォーマットされていれば整形式です。これは、タグが対称的であり、文字が正しくエンコードされていることを意味します。リスト 1 は、整形式の XML の例です。
リスト 1. XML 書籍リストの例
<書籍>
<本>
<著者>ジャック・ヘリントン</著者>
<title>PHP ハック</title>
<出版社>オライリー</出版社>
</本>
<本>
<著者>ジャック・ヘリントン</著者>
<title>ポッドキャスティングのハック</title>
<出版社>オライリー</出版社>
</本>
</本>
|
リスト 1 の XML には書籍のリストが含まれています。親の <books> タグには一連の <book> タグが含まれており、各タグには <author>、<title>、および <publisher> タグが含まれています。
XML ドキュメントは、そのマークアップ構造とコンテンツが外部スキーマ ファイルによって検証される場合、正しいものとなります。スキーマ ファイルはさまざまな形式で指定できます。この記事で必要なのは、整形式の XML だけです。
XML は Hypertext Markup Language (HTML) によく似ていると思われる方、その通りです。 XML と HTML は両方ともマークアップベースの言語であり、多くの類似点があります。ただし、XML ドキュメントは整形式の HTML である可能性がありますが、すべての HTML ドキュメントが整形式の XML であるわけではないことを指摘することが重要です。改行タグ (br) は、XML と HTML の違いを示す良い例です。この改行タグは整形式の HTML ですが、整形式の XML ではありません。
<p>これは段落です<br>
改行あり</p>
この改行タグは、整形式の XML および HTML です。
<p>これは段落です<br />
改行あり</p>
HTML を整形式 XML として記述したい場合は、W3C 委員会の Extensible Hypertext Markup Language (XHTML) 標準に従ってください ( 「参考文献」を参照)。最新のブラウザはすべて XHTML をレンダリングできます。さらに、XML ツールを使用すると、XHTML を読み取ってドキュメント内のデータを検索できます。これは、HTML を解析するよりもはるかに簡単です。
DOMライブラリを使用してXMLを読み取る
整形式の XML ファイルを読み取る最も簡単な方法は、一部の PHP インストールにコンパイルされたドキュメント オブジェクト モデル (DOM) ライブラリを使用することです。 DOM ライブラリは、XML ドキュメント全体をメモリに読み取り、それをノード ツリーとして表します (図 1 を参照)。
図 1. 書籍 XML の XML DOM ツリー
ツリーの最上位にある Books ノードには 2 つの book 子タグがあります。各書籍には、著者、出版社、タイトルなどの複数のノードがあります。 author、publisher、title ノードにはそれぞれ、テキストを含むテキスト子ノードがあります。
書籍 XML ファイルを読み取り、DOM を使用してコンテンツを表示するコードをリスト 2 に示します。
リスト 2. DOM を使用した書籍 XML の読み取り
<?php
$doc = 新しい DOMDocument();
$doc->load( 'books.xml' );
$books = $doc->getElementsByTagName( "book" );
foreach( $books として $book )
{
$authors = $book->getElementsByTagName( "著者" );
$author = $authors->item(0)->nodeValue;
$publishers = $book->getElementsByTagName( "publisher" );
$publisher = $publishers->item(0)->nodeValue;
$titles = $book->getElementsByTagName( "title" );
$title = $titles->item(0)->nodeValue;
echo "$title - $author - $publishern";
}
?>
|
スクリプトはまず新しい DOMdocument オブジェクトを作成し、load メソッドを使用して書籍 XML をこのオブジェクトにロードします。その後、スクリプトは getElementsByName メソッドを使用して、指定された名前の下にあるすべての要素のリストを取得します。
book ノードのループで、スクリプトは getElementsByName メソッドを使用して、著者、発行者、およびタイトル タグのノード値を取得します。 nodeValue はノード内のテキストです。次に、スクリプトはこれらの値を表示します。
次のようにコマンドラインで PHP スクリプトを実行できます。
%phpe1.php
PHP ハック - ジャック・ヘリントン - オライリー
ポッドキャスティングのハック - ジャック・ヘリントン - オライリー
%
ご覧のとおり、各ブックブロックは 1 行を出力します。これは良いスタートです。しかし、XML DOM ライブラリにアクセスできない場合はどうすればよいでしょうか?
SAX パーサーを使用して XML を読み取る
XML を読み取るもう 1 つの方法は、XML Simple API (SAX) パーサーを使用することです。 PHP のほとんどのインストールには SAX パーサーが含まれています。 SAX パーサーはコールバック モデルで実行されます。タグがオープンまたはクローズされるたび、またはパーサーがテキストを参照するたびに、ノードまたはテキストに関する情報を使用してユーザー定義関数がコールバックされます。
SAX パーサーの利点は、本当に軽量であることです。パーサーはコンテンツをメモリ内に長期間保持しないため、非常に大きなファイルにも使用できます。欠点は、SAX パーサー コールバックの作成が非常に面倒なことです。リスト 3 は、SAX を使用して書籍 XML ファイルを読み取り、内容を表示するコードを示しています。
リスト 3. SAX パーサーを使用した書籍 XML の読み取り
<?php
$g_books = 配列();
$g_elem = null;
function startElement( $parser, $name, $attrs )
{
グローバル $g_books、$g_elem;
if ( $name == 'BOOK' ) $g_books []= array();
$g_elem = $name;
}
関数 endElement( $parser, $name )
{
グローバル $g_elem;
$g_elem = null;
}
関数 textData( $parser, $text )
{
グローバル $g_books、$g_elem;
if ( $g_elem == '作者' ||
$g_elem == 'パブリッシャー' ||
$g_elem == 'タイトル' )
{
$g_books[ count( $g_books ) - 1 ][ $g_elem ] = $text;
}
}
$parser = xml_parser_create();
xml_set_element_handler( $parser, "startElement", "endElement" );
xml_set_character_data_handler( $parser, "textData" );
$f = fopen( 'books.xml', 'r' );
while( $data = fread( $f, 4096 ) )
{
xml_parse( $parser, $data );
}
xml_parser_free( $parser );
foreach( $g_books として $book )
{
echo $book['TITLE']." - ".$book['AUTHOR']." - ";
echo $book['PUBLISHER']."n";
}
?>
|
スクリプトは最初に、メモリ内のすべての書籍と書籍情報を保持する g_books 配列を設定します。また、 g_elem 変数は、スクリプトが現在処理しているタグの名前を保持します。次に、スクリプトはコールバック関数を定義します。この例では、コールバック関数は startElement、endElement、および textData です。マークを開くときと閉じるときは、それぞれ startElement 関数と endElement 関数を呼び出します。 TextData は、開始タグと終了タグの間のテキストで呼び出されます。
この例では、startElement タグは book 配列内の新しい要素を開始する book タグを検索します。次に、textData 関数は現在の要素を調べて、それが発行者、タイトル、または著者タグであるかどうかを確認します。そうである場合、関数は現在のテキストを現在のブックに挿入します。
解析を続行できるようにするために、スクリプトは xml_parser_create 関数を使用してパーサーを作成します。次に、コールバック ハンドルを設定します。その後、スクリプトはファイルを読み取り、ファイルのチャンクをパーサーに送信します。ファイルが読み取られた後、xml_parser_free 関数によってパーサーが削除されます。スクリプトの最後では、g_books 配列の内容が出力されます。
ご覧のとおり、これは DOM に同じ機能を記述するよりもはるかに困難です。 DOM ライブラリも SAX ライブラリも存在しない場合はどうなるでしょうか?代替手段はありますか?
正規表現を使用して XML を解析する
この方法について言及するだけで一部のエンジニアから批判されると思いますが、正規表現を使用して XML を解析することは可能です。リスト 4 は、 preg_ 関数を使用してブック ファイルを読み取る例を示しています。
リスト 4. 正規表現を使用した XML の読み取り
<?php
$xml = "";
$f = fopen( 'books.xml', 'r' );
while( $data = fread( $f, 4096 ) ) { $xml .= $data;
fclose( $f );
preg_match_all( "/<本>(.*?)</本>/s",
$xml、$bookblocks );
foreach( $bookblocks[1] as $block )
{
preg_match_all( "/<著者>(.*?)</著者>/",
$block、$author );
preg_match_all( "/<タイトル>(.*?)</タイトル>/",
$block、$title );
preg_match_all( "/<パブリッシャー>(.*?)</パブリッシャー>/",
$block、$publisher );
echo( $title[1][0]." - ".$author[1][0]." - ".
$publisher[1][0]."n" );
}
?>
|
このコードがいかに短いかに注目してください。最初に、ファイルを大きな文字列に読み取ります。次に、正規表現関数を使用して、書籍の各項目を読み取ります。最後に、foreach ループを使用して各書籍ブロックをループし、著者、タイトル、発行者を抽出します。
では、どこに欠陥があるのでしょうか?正規表現コードを使用して XML を読み取る場合の問題は、XML が整形式であるかどうかを最初にチェックしないことです。これは、XML を読み取る前に XML が整形式かどうかを知る方法がないことを意味します。また、一部の整形式 XML は正規表現と一致しない可能性があるため、後で変更する必要があります。
XML を読み取るために正規表現を使用することはお勧めしませんが、正規表現関数は常に使用できるため、互換性を保つためにはこれが最善の方法である場合があります。 XML の形式や構造を制御できないため、正規表現を使用してユーザーから XML を直接読み取らないでください。ユーザーから XML を読み取るには、常に DOM ライブラリまたは SAX パーサーを使用する必要があります。 DOM を使用した XML の記述
XML の読み取りは方程式の一部にすぎません。 XMLはどのように書くのでしょうか? XML を記述する最良の方法は、DOM を使用することです。リスト 5 は、DOM が書籍 XML ファイルを構築する方法を示しています。
リスト 5. DOM を使用したブック XML の作成
<?php
$books = 配列();
$books [] = 配列(
'タイトル' => 'PHP ハック',
'著者' => 'ジャック・ヘリントン',
「出版社」 => 「オライリー」
);
$books [] = 配列(
'タイトル' => 'ポッドキャスティングハック',
'著者' => 'ジャック・ヘリントン',
「出版社」 => 「オライリー」
);
$doc = 新しい DOMDocument();
$doc->formatOutput = true;
$r = $doc->createElement( "books" );
$doc->appendChild( $r );
foreach( $books として $book )
{
$b = $doc->createElement( "book" );
$author = $doc->createElement( "著者" );
$author->appendChild(
$doc->createTextNode( $book['author'] )
);
$b->appendChild( $author );
$title = $doc->createElement( "タイトル" );
$title->appendChild(
$doc->createTextNode( $book['title'] )
);
$b->appendChild( $title );
$publisher = $doc->createElement( "publisher" );
$publisher->appendChild(
$doc->createTextNode( $book['publisher'] )
);
$b->appendChild( $publisher );
$r->appendChild( $b );
}
echo $doc->saveXML();
?>
|
スクリプトの先頭で、books 配列にいくつかのサンプル ブックが読み込まれます。このデータはユーザーまたはデータベースから取得できます。
サンプル ブックがロードされた後、スクリプトは新しい DOMDocument を作成し、それにルート ブック ノードを追加します。次に、スクリプトは各本の著者、タイトル、発行者のノードを作成し、各ノードにテキスト ノードを追加します。各ブック ノードの最後のステップは、ブック ノードをルート ノードのブックに再追加することです。
スクリプトの最後で、saveXML メソッドを使用して XML をコンソールに出力します。 (save メソッドを使用して XML ファイルを作成することもできます。) スクリプトの出力をリスト 6 に示します。
リスト 6. DOM ビルド スクリプトの出力
%phpe4.php
<?xmlバージョン="1.0"?>
<書籍>
<本>
<著者>ジャック・ヘリントン</著者>
<title>PHP ハック</title>
<出版社>オライリー</出版社>
</本>
<本>
<著者>ジャック・ヘリントン</著者>
<title>ポッドキャスティングのハック</title>
<出版社>オライリー</出版社>
</本>
</本>
%
|
DOM を使用する本当の価値は、DOM によって作成される XML が常に整形式であることです。しかし、DOM を使用して XML を作成できない場合はどうすればよいでしょうか?
PHPでXMLを書く
DOM が使用できない場合は、PHP のテキスト テンプレートを使用して XML を作成できます。リスト 7 は、PHP が書籍 XML ファイルを構築する方法を示しています。
リスト 7. PHP でのブック XML の作成
<?php
$books = 配列();
$books [] = 配列(
'タイトル' => 'PHP ハック',
'著者' => 'ジャック・ヘリントン',
「出版社」 => 「オライリー」
);
$books [] = 配列(
'タイトル' => 'ポッドキャスティングハック',
'著者' => 'ジャック・ヘリントン',
「出版社」 => 「オライリー」
);
?>
<書籍>
<?php
foreach( $books として $book )
{
?>
<本>
<タイトル><?php echo( $book['タイトル'] );
<著者><?php echo( $book['著者'] ) ?>
</著者>
<出版社><?php echo( $book['publisher'] );>
</出版社>
</本>
<?php
}
?>
</本>
|
スクリプトの上部は DOM スクリプトに似ています。スクリプトの最後では、books タグを開き、各書籍を反復処理して、book タグとすべての内部タイトル、著者、発行者のタグを作成します。
このアプローチの問題は、エンティティのエンコードです。エンティティが正しくエンコードされていることを確認するには、リスト 8 に示すように、各項目に対して htmlentities 関数を呼び出す必要があります。
リスト 8. htmlentities 関数を使用したエンティティのエンコード
<書籍>
<?php
foreach( $books として $book )
{
$title = htmlentities( $book['title'], ENT_QUOTES );
$author = htmlentities( $book['author'], ENT_QUOTES );
$publisher = htmlentities( $book['publisher'], ENT_QUOTES );
?>
<本>
<タイトル><?php echo( $title );
<著者><?php echo( $author ) ?> </著者>
<パブリッシャー><?php echo( $publisher ) ?>
</出版社>
</本>
<?php
}
?>
</本>
|
基本的な PHP で XML を書くのが面倒になるのはここです。完璧な XML を作成したと思っていても、データを使用しようとするとすぐに、一部の要素が正しくエンコードされていないことがわかります。
結論
XML の周りには常に多くの誇張と混乱があります。ただし、特に PHP のような優れた言語では、それは思っているほど難しくありません。 XML を正しく理解して実装すると、多くの強力なツールを自由に使用できるようになります。 XPath と XSLT は、研究する価値のある 2 つのツールです。