PHPでXMLの名前空間つきタグを読み込む色々
この記事は賞味期限切れです。(更新から1年が経過しています)
PHPのSimpleXMLでRSSを読み込もうと思ったら、名前空間つきのタグが読み込めなかったので、色々な方法を試してみた備忘録。
実験の対象として、はてなブックマークのホットエントリのRSSを使ってみます。
$url = "http://b.hatena.ne.jp/hotentry.rss";
$str = file_get_contents( $url );
SimpleXMLを使う方法
普通にSimpleXMLで読み込むと、
$simplexml = simplexml_load_string( $str );
var_dump( $simplexml );
SimpleXMLで名前空間つきタグを扱うには、childrenメソッドを使います。例えば、
$simplexml->item[$i]->children("hatena", true)->bookmarkcount;
ループでitem要素全てまとめて処理してみます。 それぞれのitem要素にhatena->bookmarkcountが追加されます。
$simplexml = simplexml_load_string( $str );
$i = count( $simplexml->item );
while( $i-- ){
$simplexml->item[$i]->hatena->bookmarkcount = $simplexml->item[$i]->children("hatena", true)->bookmarkcount;
}
var_dump( $simplexml );
DOMDocumentクラスを使う
DOM文書を読み込むためのDOMDocumentクラスを使ってみます。 JavaScriptでも使うような、getElementsByTagNameなんていうお馴染みのメソッドを使って文書構造を掘っていきます。
$dom = DOMDocument::loadXML( $str );
foreach( $dom->getElementsByTagName("item") as $item ){
foreach( $item->childeNodes as $node ){
if( $node->nodeType === 1 ){
echo "{$node->nodeName} : {$node->nodeValue}";
}
}
}
nodeTypeには、ノードの種類が整数で渡されています。上で言う「1」はエレメントノードですね。 勿論、プレフィックスつきのタグも問題なく読み込めます。
出力時に楽なように、エントリーをまとめて一つの配列に突っ込んでみます。
$dom = DOMDocument::loadXML( $str );
$entries = array();
foreach( $dom->getElementsByTagName( "item" ) as $item ){
$entry = array();
foreach( $item->childNodes as $node ){
if( $node->nodeType !== 1 ) continue;
if( $item->getElementsByTagName( $node->nodeName )->length > 1 ){
if( !isset( $entry[ $node->nodeName ] ) ){
$entry[ $node->nodeName ] = array();
}
array_push( $entry[ $node->nodeName ], $node->nodeValue );
} else {
$entry[ $node->nodeName ] = $node->nodeValue;
}
}
array_push( $entries, $entry );
}
var_dump( $entries );
複数あるタグは配列で対応。書いてみたものの…DOMDocumentのまま使った方が使いやすい気もしたり。
むしろこういう使い方するならSimpleXML使った方がよいですね。
XMLReaderクラスを使う
SimpleXMLやDOMDocumentが、XMLの情報をドッカンと丸ごとメモリに置いておくのに大して、
XMLReaderはfopenのようにポインタの位置だけを保持しておく為、メモリに優しく高速。らしい。
ですが、ポインタの位置だけだと正直使い辛いのも事実。
$xml = XMLReader::load( $url, null, LIBXML_NOBLANKS );
while( $xml->read() ){
echo "{$xml->nodeType} : {$xml->name} = {$xml->value} @ {$xml->depth} <br />";
}
$xml->read()でノードを一つずつ読み進んでいく感じ。
多階層なXMLを読んでいくのは骨が折れそう。
これは重た~いXMLを読まなきゃいけない時用の代物ですね。
まとめ
名前に違わず相当楽ですね、SimpleXML。
名前空間つきのタグも処理したい場合等は、DOMDocumentの方がシンプルに処理出来そう。
XMLReaderはパフォーマンスを意識したい場合に。
上手に使い分けたいですね!
- 2010/12/18
- マニュアルのリンクを修正
コメント