@blog.justoneplanet.info

日々勉強

PHP SimpleXML

以下のXMLを使用してサンプルコードを解説する。

<?xml version="1.0"?>
<library>
    <book isbn="0111222333">
        <title>She sells seashells</title>
        <author>Emily</author>
        <publisher>store</publisher>
    </book>
    <book isbn="0123456789">
        <title>Eight apes ate eight apples</title>
        <author>John</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="9876543210">
        <title>Strike</title>
        <author>Mike</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="1234567890">
        <title>Shine</title>
        <author>Jack</author>
        <publisher>store</publisher>
    </book>
</library>

■XMLドキュメントのパース

  • 対応しているXMLのバージョンは1.0(1.1は非対応)
  • パースに失敗すると警告を発する
  • ドキュメントをパースするときは、SimpleXMLElementオブジェクトを生成する必要がある
<?php
$xml = simplexml_load_file('doc/library.xml');
?>

上述のコードは以下のコードと同じ働きをする。

<?php
$doc = file_get_contents('doc/library.xml');
$xml = simplexml_load_string($doc);
?>

オブジェクト指向型のアプローチ

以下のようにSimpleXMLElementクラスを使って、アブじぇ句と指向型のアプローチを取ることもできる。

<?php
$xml = new SimpleXMLElement('doc/library.xml', null, true);
?>

上述のコードは以下のコードと同じ働きをする。

<?php
$doc = file_get_contents('doc/library.xml');
$xml = new SimpleXMLElement($doc);
?>

個人的にはオブジェクト指向型のアプローチの方がコードがスッキリして好きだ。

SimpleXMLElement(string $dat[, int $options[, bool $flag_uri[, string $namespace[, bool $is_prefix]]]])
$dat
XML文字列。URLで指定する場合は、第三引数を「true」にしなければならない
$options
libxmlに渡すパラメータ。用途にもよるが、「null」を渡して使用することが多い
$flag_uri
第一引数がURLの場合は、「true」をセットしなくてはならない

■要素と属性へのアクセス

各要素にアクセスするには「->」を使用し、属性にアクセスするためには配列リテラルを使用する。

<?php
$xml = new SimpleXMLElement('doc/library.xml', null, true);
foreach($xml->book as $book){
    print($book['isbn'] . PHP_EOL);
    print($book->title . PHP_EOL);
    print($book->author . PHP_EOL);
    print($book->publisher . PHP_EOL);
}
/*
0111222333
She sells seashells
Emily
store
-----
0123456789
Eight apes ate eight apples
John
shop
-----
9876543210
Strike
Mike
shop
-----
1234567890
Shine
Jack
store
-----
*/
?>

但し、上述のコードには「子要素や属性の名前を知っていなければならない」という欠点がある。従って、以下のコードのように、要素名や属性名を取得するメソッドを使う方が良い。

<?php
$xml = new SimpleXMLElement('doc/library.xml', null, true);
foreach($xml->children() as $child){
    print($child->getName() . PHP_EOL);
    foreach($child->attributes() as $attr){
        print("\t" . $attr->getName() . ': ' . $attr . PHP_EOL);
    }
    foreach($child->children() as $sub){
        print("\t" . $sub->getName() . ': ' . $sub . PHP_EOL);
    }
    print('-----' . PHP_EOL);
}
/*
book
isbn: 0111222333
title: She sells seashells
author: Emily
publisher: store
-----
book
isbn: 0123456789
title: Eight apes ate eight apples
author: John
publisher: shop
-----
book
isbn: 9876543210
title: Strike
author: Mike
publisher: shop
-----
book
isbn: 1234567890
title: Shine
author: Jack
publisher: store
-----
*/
?>

但し、上述のコードでは深さが特定の場合しか探索できない。深さが不定の場合は、再帰関数やRecursiveIteratorIteratorクラスなどを使用する。

一度値を配列に格納する方法

すぐに出力する場合は上述の方法で問題はないが、配列に要素の文字列を格納する場合はSimpleXMLElementオブジェクトから文字列に変換する。

$data = new SimpleXMLElement($url, null, true);
if($data->getName() === 'rss'){//rss
    foreach($data->channel->item as $i){
        $rv[] = array(
            'title' => ((string)$i->title),
            'link'  => ((string)$i->link)
        );
    }
}
elseif($data->getName() === 'feed'){//atom
    foreach($data->entry as $item){
        $rv[] = array(
            'title' => ((string)$item->title),
            'link'  => ((string)$item->link['href'])
        );
    }
}
各メソッドについて
SimpleXMLElement::children()
指定したノードの子ノードを見つける
SimpleXMLElement::attributes()
属性名をキーとして、指定したノードの属性値の配列を返す
SimpleXMLElement::getName()
要素名、属性名を返す

■XPathクエリ

XPathを使用して特定の要素を抜き出したりするには、以下のように「SimpleXMLElement::xpath」を用いる。

<?php
$xml = new SimpleXMLElement('doc/library.xml', null, true);
$elm = $xml->xpath('/library/book/title');
foreach($eml as $title){
    print($title . PHP_EOL);
}
/*
She sells seashells
Eight apes ate eight apples
Strike
Shine
*/
/*
array(4) {
  [0]=>
  object(SimpleXMLElement)#2 (1) {
    [0]=>
    string(19) "She sells seashells"
  }
  [1]=>
  object(SimpleXMLElement)#3 (1) {
    [0]=>
    string(27) "Eight apes ate eight apples"
  }
  [2]=>
  object(SimpleXMLElement)#4 (1) {
    [0]=>
    string(6) "Strike"
  }
  [3]=>
  object(SimpleXMLElement)#5 (1) {
    [0]=>
    string(5) "Shine"
  }
}
*/
?>
<?php
$xml = new SimpleXMLElement('doc/library.xml', null, true);
$elm = $xml->book[0]->xpath('title');
foreach($elm as $title){
    print($title . PHP_EOL);
}
//She sells seashells
?>

SimpleXMLElement::xpathメソッドのについて

xpathクエリを実行し、結果をSimpleXMLElementオブジェクトとして返す。

■SimpleXMLによるXMLドキュメントの操作

以下のように、PHP5.1.3以降ではSimpleXMLで要素の追加が行えるようになった。

<?php
$xml = new SimpleXMLElement('doc/library.xml', null, true);

$book = $xml->addChild('book');
$book->addAttribute('isbn', '0812550706');
$book->addChild('title', 'She sells seashells');
$book->addChild('author', 'John');
$book->addChild('publisher', 'amazon');

header('Content-type: text/xml');
print($xml->asXML());
/*
<?xml version="1.0" encoding="utf-8"?>
<library>
    <book isbn="0111222333">
        <title>She sells seashells</title>
        <author>Emily</author>
        <publisher>store</publisher>
    </book>
    <book isbn="0123456789">

        <title>Eight apes ate eight apples</title>
        <author>John</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="9876543210">
        <title>Strike</title>
        <author>Mike</author>

        <publisher>shop</publisher>
    </book>
    <book isbn="1234567890">
        <title>Shine</title>
        <author>Jack</author>
        <publisher>store</publisher>
    </book>

<book isbn="0812550706"><title>She sells seashells</title><author>John</author><publisher>amazon</publisher></book></library>
*/
?>

asXMLメソッドはXML文字列を返す。また、引数にファイルパスを指定した場合は、XMLドキュメントとして保存される。但し、既にファイルが存在している場合は、警告なしにファイルが上書きされるので注意が必要である。

要素の削除

SimpleXMLは要素や属性の追加についてのメソッドを持っているが、削除についてのメソッドは存在しない。削除する場合は以下のようにする。

<?php
$xml = new SimpleXMLElement('doc/library.xml', null, true);
$xml->book[0] = null;
/*
<?xml version="1.0" encoding="utf-8"?>
<library>
    <book isbn="0111222333"></book>
    <book isbn="0123456789">
        <title>Eight apes ate eight apples</title>
        <author>John</author>
        <publisher>shop</publisher>
    </book>

    <book isbn="9876543210">
        <title>Strike</title>
        <author>Mike</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="1234567890">
        <title>Shine</title>

        <author>Jack</author>
        <publisher>store</publisher>
    </book>
</library>
*/
?>

但し、この方法は要素内を空にするだけであり、book要素の属性も属性値を空にすることしかできない。もしも、完全に削除したい場合は、DOMへエクスポートする必要がある。以下のようにする。

<?php
$xml = new SimpleXMLElement('doc/library.xml', null, true);
unset($xml->book[0]);
/*
<?xml version="1.0" encoding="utf-8"?>
<library>
    
    <book isbn="0123456789">
        <title>Eight apes ate eight apples</title>
        <author>John</author>
        <publisher>shop</publisher>
    </book>

    <book isbn="9876543210">

        <title>Strike</title>
        <author>Mike</author>
        <publisher>shop</publisher>
    </book>
    <book isbn="1234567890">
        <title>Shine</title>

        <author>Jack</author>
        <publisher>store</publisher>
    </book>
</library>
*/
?>
各メソッドについて
SimpleXMLElement::addChild
要素を追加する。戻り値はSimpleXMLElementオブジェクトであり、これに対して操作することでルートのXMLを操作することもできる
SimpleXMLElement::addAttribute
属性を追加する

■名前空間

<?xml version="1.0"?>
<library xmlns="http://sample.org/library" xmlns:meta="http://sample.org/book-meta" xmlns:pub="http://sample.org/publisher" xmlns:sample="http://sample.org/sample">
    <book meta:isbn="0345342968">
        <title>Fahrenheit 451</title>
        <author>Ray Bradbury</author>
        <pub:publisher>Del Rey</pub:publisher>
    </book>
</library>
<?php
$xml = new SimpleXMLElement('test.xml', null, true);
$ns = $xml->getDocNamespaces();
foreach($ns as $key => $value){
	print("{$key}: {$value}\n");
}
/*
: http://sample.org/library
meta: http://sample.org/book-meta
pub: http://sample.org/publisher
sample: http://sample.org/sample
*/
?>

<?php
$xml = new SimpleXMLElement('test.xml', null, true);
$ns = $xml->getNamespaces(true);
foreach($ns as $key => $value){
	print("{$key}: {$value}\n");
}
/*
: http://sample.org/library
meta: http://sample.org/book-meta
pub: http://sample.org/publisher
*/
?>

以下のように、引数にfalseを指定するとカレントノードの名前空間を返す。名前空間が指定されていない場合は、空の配列となる。

<?php
$xml = new SimpleXMLElement('test.xml', null, true);
$ns = $xml->getNamespaces(false);
foreach($ns as $key => $value){
	print("{$key}: {$value}\n");
}
/*
: http://sample.org/library
*/
?>

各メソッドについて

SimpleXMLElement::getDocNamespaces
ドキュメントで宣言されている名前空間を返す。引数にはbool値が入り(デフォルトはfalse)trueを指定すると、子ノードで宣言されている名前空間も返す。
SimpleXMLElement::getNamespaces
ドキュメントで使用している名前空間を返す。引数にはbool値が入り(デフォルトはfalse)trueを指定すると、子ノードで使用している名前空間も返す。

3 Comments»

PHPで駅の近くの珈琲店を探す

PHPで駅データ.jpを利用し、駅の近くの珈琲店を探す。DOM XML(PHP4)、SimpleXML(PHP5)、PHP XML Library(Keith Devens.com)によるプログラムを示す。

トラックバックして頂きありがとうございます!
いろいろな情報が掲載されていて面白そうですね!

SimpleXML を勉強中の方からSimpleXMLにおける要素の削除方法について
ご指摘があり修正しております。
ご親切にありがとうございます!!!
unsetを使用するんですね!!

ありがとうございました!!!
今後ともよろしくお願い申し上げます!

RSS feed for comments on this post.TrackBack URL

Leave a comment