PHPでXMLをnamespaceを利用したxpathでnode取得

PHPxmlを読み込んでxpathでnodeを取得して見たいと思います。
今回はyahooの形態素解析apiから取得したxmlを題材にしてみます。

XMLオブジェクトの操作

順を追ってxmlを操作してみます。
ちなみにyahooの形態素解析前回のcurlを利用して取得できます。

$data = array(  
        'appid' => self::APP_ID,  
        'results' => 'ma',  
        'sentence' => trim($name)  
    );  
  
$response = $this->getGetRequestResponse($data);  

いろいろと端折っていますが、とりあえずこれでxmlの文字列が取得できます。

SimpleXMLObjectの生成

先ほど取得した、xml文字列からPHPにあるSimpleXMLObjectを生成してみます。

$xml = simplexml_load_string($xmlString);  

これは文字列を引数にxmlのオブジェクトを生成しているわけですね。
これでオブジェクトができました。

namespaceを設定する

yahooのapiを利用して取得したxmlにはnamespaceが設定されていますので、そのままxpathを解析させてもちゃんとデータが取得できません。
そのため、ここで設定してみます。

$xml->registerXPathNamespace('y', 'urn:yahoo:jp:jlp');  

第一引数は、そのnamespaceに対するエイリアスみたいなものでしょうか。この名前を利用してxpathを実行します。
第二引数では、xml内で宣言されている名前の付いていないxmlnsを指定しています。
これでnamespaceを利用しつつちゃんとxpathでデータが取得できるようになります。

C#であればnamespaceなどを全部無視してxpathを実行したりできるのですがphpにもあるのでしょうか?

xpathの実行

ではxpathを指定しつつ、取得したデータを利用してみます。

$words = $xml->xpath('//y:ResultSet/y:ma_result/y:word_list/y:word');  
$data = array();  
  
foreach($words as $word){  
    array_push($data, (string)$word->surface, (string)$word->reading);  
}  
return $data;  

xpathを実行する際に、先ほど設定したnamespaceを指定しつつ実行します。
そしてここでは複数取得されてくるためforeachで回して、中身を配列に突っ込んでいます。

$word->surfaceなどのままでと、以下のようなものも文字列ではなくSimpleXMLObjectで取れてくるため、stringでキャストする事でnode内の文字として取得しています。

<word>  
  <surface>佐藤</surface>  
  <reading>さとう</reading>  
</word>  

これでCURLXMLのパースができるようになったのでapiを利用するのに必要な情報は概ね揃いましたね。