PHP/SimpleXMLElement

Last-modified: 2011-09-13 (火) 01:20:18

Windows版PHP 5.2による調査。

SimpleXMLElementオブジェクトが表す情報は以下の4パターンがある。どの情報を表しているかによって、SimpleXMLElementのメソッドの動作、関数適用時の結果が異なる。

  • 要素
  • 要素セット (要素の集合)
    厳密には以下2つのケースがある
    • ->foo によって取得した要素セット
    • ->children()によって取得した要素セット
  • 属性
  • 属性セット (属性の集合)

名前空間を使わないXMLの場合

要素関連の操作

演算対象
要素要素セット要素セットが空の場合
$xml->getName()要素名※2長さ0の文字列
(string)$xmlコンテントのテキスト ※12※2長さ0の文字列
count($xml)子要素数要素数0
empty($xml)コンテントも子要素も無ければtrue要素数0でtruetrue
$xml[index]※3index番目の要素 ※4NULL
$xml['name']属性nameの属性 ※5※11(->nameの場合は※2, ->children()の場合はNULL)NULL
$xml->name子要素のうち要素名がnameのものからなる要素セット ※6※11(->nameの場合は※2, ->children()の場合は、この要素セットに含まれる要素のうち名前がnameの要素のセット(->nameで得られたのと同じ挙動をする))NULL
foreach ※1$keyは子要素名,$valueは子要素 ※7$keyは要素名, $valueはその要素 ※7繰り返しなし
$xml->children()子要素の要素セット ※8※2※10
$xml->attributes()属性セット※9※2※10
※1
foreach($xml as $key => $value) {...}
※2
$xml[0]に演算を適用したのと同じ結果が得られる
※3
index=0で$xml自身と同じ内容が得られる。また、index>0でPHPのWarning発生。有効な用途はない。
※4
indexは >=0。indexが要素数以上の場合はNULLが得られる。
※5
名前がnameの属性が存在しない場合はNULLが得られる。
※6
名前がnameの子要素が存在しない場合は空の要素セットが得られる。
※7
同じ名前の要素が複数ある場合でも、すべての要素が得られる。(繰り返し中で同じ$keyが何回か出現する)
※8
子要素が無ければ空の要素セットが得られる。
※9
属性が無ければ空の属性セットが得られる。
※10
SimpleXMLElementが得られるが、そのSimpleXMLElementにcount, empty などを実行しようとするとPHPのWarningが発生するため、実質的に利用できない。
※11
->nameで得られた要素セットと、->children()で得られた要素セットとでそれぞれ異なる動作をする。
※12
子要素とそのコンテントを除去して、残った文字列を連携したもの。改行や行頭空白も含まれる。

また、いずれの場合も、

 (boolean)$xml  === !empty($xml)

属性関連の操作

演算対象
属性属性セット属性セットが空の場合
$xml->getName()属性名※2長さ0の文字列
(string)$xml属性の値※2長さ0の文字列
count($xml)0属性数0
empty($xml)false(値が空でもfalse)属性数0でtruetrue
$xml[index]※3index番目の属性 ※4NULL
$xml['name']NULL$xml->nameと同じ。NULL
$xml->name空の要素セット?この属性セットに含まれる属性のうち名前がnameの属性(セットではない)NULL
foreach ※1繰り返しなし$keyは属性名, $valueはその属性繰り返しなし
$xml->children()空の要素セット?NULLNULL
$xml->attributes()空の属性セットNULLNULL
※1
foreach($xml as $key => $value) {...}
※2
$xml[0]に演算を適用したのと同じ結果が得られる
※3
index=0で$xml自身と同じ内容が得られる。また、index>0でPHPのWarning発生。有効な用途はない。
※4
indexは >=0。indexが属性数以上の場合はNULLが得られる。

また、いずれの場合も、

 (boolean)$xml  === !empty($xml)

留意点

  • 「無い」ことを表すのに、NULLが返る場合と、空のセットが返る場合がある。
  • 要素に対するempty($xml)は、要素のコンテント/子要素が無ければtrueとなるのに対し、属性のempty($xml)は属性の値が空でもtrueにはならない。
  • 要素、属性については、count($xml)==0 ⇔ empty($xml)==true の関係が成り立たない。
  • attributes(), children()で得られたセットについては、$xml->name はそのセットのフィルタ(サブセットの切り出し)として機能する。一方、要素の->name で得られたセットについては、$xml->name は $xml[0]->name の省略形として機能する。
  • あるSimpleXMLElementが、要素、要素セット、属性、属性セットのどれなのかを区別する確実な方法がない。

名前空間を使うXMLの場合

要素関連の操作

$xmlは要素であり、children('名前空間')を経由して取得された要素とする。

$xml = $root->children('http://example.com/foo')->name[0];

childrenを経由していない要素だと挙動が異なるらしい。要確認。例えば、以下の$xmlを$rootに置き換えると挙動が異なる。

$xml->children()prefixが付いていない子要素を集めたセットが返る。※1
$xml->children('')
$xml->children(NULL)
$xml->children('ns')子要素のうち、指定された名前空間に属する子要素を集めたセットが返る。※2
$xml->name子要素のうち、$xmlと同じ名前空間に属する子要素を集めたセットが返る。※2
count($xml)子要素のうち、$xmlと同じ名前空間に属する子要素の数。※2
empty($xml)count($xml)==0ならtrue ※3
foreach子要素のうち、$xmlと同じ名前空間に属する子要素について繰り返す。※2
※1
prefixがなければ、名前空間の有無を問わず、名前空間が親($xml)と同じか否かを問わず、取得できる。このため、名前空間利用時にはこのメソッドは実質的に利用できない。例:<foo xmlns="x"><aaa/><bbb xmlns="y"/><cc:ccc xmlns:cc="x"/><dd:ddd xmlns:dd="y"/></foo> で$xmlがfooのとき、取得されるのはaaa, bbbである。
※2
純粋に名前空間で判断され、prefixを使っているかどうかを問わない。
※3
コンテントテキストの有無はemptyの結果に影響しない。この点で、名前空間を使わない場合と動作が異なる。

名前空間なしに属する要素を明示的に指定して取得することはできない。(例: <foo xmlns="x"><bar xmlns=""/><baz xmlns="z"/></foo> において 名前空間なしに属する要素だけを(barだけ)を取り出す方法がない)

countでは、子要素の有無を判定できない。自分と異なる名前空間の要素があってもcountには反映されないため。

属性関連の操作

未調査

メモ

名前空間を区別せず全子要素数を取得するには、getNamespacesで名前空間を列挙し、それぞれにchildrenを実行して子要素数をカウントし、合計すればよい、かもしれない。

メモ 安全に使うには

  • $xml[0]で要素も要素セットも要素になる。
  • 要素セットはプログラム内で流通させない。要素セットを取得したら即[]を適用して要素にする。
操作名前空間なし名前空間あり
子要素をとる
属性を取る
...