以下の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を指定すると、子ノードで使用している名前空間も返す。
ピンバック: ぱふぅ家のホームページ
トラックバックして頂きありがとうございます!
いろいろな情報が掲載されていて面白そうですね!
SimpleXML を勉強中の方からSimpleXMLにおける要素の削除方法について
ご指摘があり修正しております。
ご親切にありがとうございます!!!
unsetを使用するんですね!!
ありがとうございました!!!
今後ともよろしくお願い申し上げます!