名前空間やCDATAの読み込み
PHPでRSS取得するのに、単純にsimplexml_load_file()を利用して取得しようと思った時に、名前空間(「:」コロンで区切られた要素)やCDATAの値が取得できないのでメモ。 CDATAに関して言えば、取得自体はできているけど、パッと見取れていないように見えるのでちょっと工夫が必要。
WordPressの基本的なfeed(RSS2.0)を読み込む例(記事部分抜粋)
<item> <title>記事タイトル</title> <link>http://xxx.jp/?p=xxx</link> <pubDate>Tue, 18 Feb 2014 01:00:43 +0000</pubDate> <dc:creator>記事を書いた人</dc:creator> <category><![CDATA[ 未登録 ]]></category> </item>
このファイルを読み込んでみます。
simplexml_load_file()で取得してみる
$rss_url = "http://xxx.jp/?feed=rss2"; $rss_data = simplexml_load_file( $rss_url ); $rss_array = array(); $i = 0; foreach ( $rss_data->channel->item as $item ) { $rss_array[$i]['title'] = $item->title; $rss_array[$i]['link'] = $item->link; $rss_array[$i]['pubData'] = $item->pubData; $rss_array[$i]['dc'] = $item->dc:creator; // 取得できない $rss_array[$i]['category'] = $item->category; // 取得できない $i++; }
これだけだと、dc:creatorとcategoryが取得できません。
CDATAの取得を考える
CDATAの取得方法を考えてみました。
CDATA取得方法その1:simplexml_load_file()のパラメータを設定する
simplexml_load_file()でLIBXML_NOCDATAを第3引数に渡すことで取得できます。
$rss_url = "http://xxx.jp/?feed=rss2"; $rss_data = simplexml_load_file( $rss_url, 'SimpleXMLElement', LIBXML_NOCDATA ); $rss_array = array(); $i = 0; foreach ( $rss_data->channel->item as $item ) { $rss_array[$i]['title'] = $item->title; $rss_array[$i]['link'] = $item->link; $rss_array[$i]['pubData'] = $item->pubData; $rss_array[$i]['dc'] = $item->dc:creator; // 取得できない $rss_array[$i]['category'] = $item->category; // 取得できた! $i++; }
libxmlはPHPのXML操作ライブラリで、その中の定義済み定数にLIBXML_NOCDATAの説明があります。他の定数も存在するので、XMLの操作をする上で一度は見ておいたほうが良いかと。
CDATA取得方法その2:CDATA要素を(string)でキャストする
CDATA要素に対して文字列として扱うように、(string)でキャストすると取得できます。
$rss_url = "http://xxx.jp/?feed=rss2"; $rss_data = simplexml_load_file( $rss_url ); $rss_array = array(); $i = 0; foreach ( $rss_data->channel->item as $item ) { $rss_array[$i]['title'] = $item->title; $rss_array[$i]['link'] = $item->link; $rss_array[$i]['pubData'] = $item->pubData; $rss_array[$i]['dc'] = $item->dc:creator; // 取得できない $rss_array[$i]['category'] = (string)$item->category; // 取得できた! $i++; }
CDATA要素の数が沢山あると大変なので、「その1」のやり方がスマートのように思えます。
名前空間要素の取得を考える
次に名前空間要素の取得方法を考えてみました。
名前空間要素の取得方法その1:children()メソッドで名前空間名を指定
「:」コロンつなぎの要素、名前空間情報は、children()メソッドで指定すると取得できます。(PHPのマニュアル:SimpleXMLElement::childrenを参照)
$rss_url = "http://xxx.jp/?feed=rss2"; $rss_data = simplexml_load_file( $rss_url, 'SimpleXMLElement', LIBXML_NOCDATA ); $rss_array = array(); $i = 0; foreach ( $rss_data->channel->item as $item ) { $rss_array[$i]['title'] = $item->title; $rss_array[$i]['link'] = $item->link; $rss_array[$i]['pubData'] = $item->pubData; $rss_array[$i]['dc'] = $item->children('dc',true)->creator; // 取得できた! $rss_array[$i]['category'] = $item->category; // 取得できた! $i++; }
名前空間要素の取得方法その2:記事の要素をまるごと配列に保存
これが一番やりたかった事。RSSの要素をWordPress側でカスタマイズする必要があったので、CDATAも名前空間の要素もどういうのが来るか不明なので、まるごと配列にえいやー!と保存したい。 とりあえず、何も考えずにまるごと保存してみました。
$rss_url = "http://xxx.jp/?feed=rss2"; $rss_data = simplexml_load_file( $rss_url, 'SimpleXMLElement', LIBXML_NOCDATA ); $rss_array = array(); foreach ( $xmldata->channel->item as $item ) { $rss_array[] = $item; }
CDATAはLIBXML_NOCDATA指定により取得できました。けど、名前空間が……となったので、一度RSS情報を文字列として取得して、名前空間要素を文字列変換しパースするという方法で解決しました。
$rss_url = "http://xxx.jp/?feed=rss2"; $rss_data = file_get_contents( $rss_url ); $rss_data = preg_replace( "/<([^>]+?):(.+?)>/", "<$1_$2>", $rss_data ); $rss_data = preg_replace( "/_\/\//", "://", $rss_data ); $rss_data = simplexml_load_string( $rss_data, 'SimpleXMLElement', LIBXML_NOCDATA ); $rss_array = array(); foreach ( $rss_data->channel->item as $item ) { $rss_array[] = $item; }
\(^o^)/取得できた!!
- file_get_contents()でRSS情報を取得する
- preg_replace()で「:」(コロン)を「_」(アンダーバー)に変換
- preg_replace()でプロトコルは元に戻す
- simplexml_load_string()で文字列XML情報をパースする
注意点
以下の2点に注意すること。
- simplexml_load_file関数はphp.iniの設定でallow_url_fopenをOnにしていないと使えない。
- Offの場合は、curl_get_contents()でRSS情報を取得してから、simplexml_load_string()でパースし直す。