Mach3.laBlog

PHPでXMLの名前空間つきタグを読み込む色々

この記事は賞味期限切れです。(更新から1年が経過しています)

PHPのSimpleXMLでRSSを読み込もうと思ったら、名前空間つきのタグが読み込めなかったので、色々な方法を試してみた備忘録。

PHPでXMLの名前空間つきタグを読み込む色々

実験の対象として、はてなブックマークのホットエントリの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」はエレメントノードですね。 勿論、プレフィックスつきのタグも問題なく読み込めます。

cf) PHP: 定義済み定数 – Manual

出力時に楽なように、エントリーをまとめて一つの配列に突っ込んでみます。

$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
マニュアルのリンクを修正

コメント

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*

ITキヲスク | 2010年12/12~12/18の週間ブックマークd41d8cd98f00b204e9800998ecf8427e