XML ファイルを変数に取り込む - PHP5 プログラミング

PROGRAM


XML ファイルを変数に取り込む

php で XML を使用する方法としては、DOM で XML を操作する で記したような DOM を使う方法もありますけれど、ここではもっと単純に操作することができる SimpleXML を使う方法について見て行きたいと思います。

XML データの取り込み

PHP5 では XML ファイルを読み込んで、変数に格納する関数が用意されています。

$xml = simplexml_load_file($file);

このようにすることで、$file で指定した XML ファイルを読み込んで、その内容を構造を維持した形で $xml 変数に格納することができます。

このとき、simplexml_load_file で読んだテキストが文字化けする でも書きましたけど、読み込む XML ファイルには冒頭の <?xml> タグの "encode" 属性で、適切な文字コードが指定さていないと文字化けするのに注意します。

 

または、次のようにすれば、ファイルではなく文字列として XML データを用意して、それを構造を持ったオブジェクトとして利用することも可能です。

$xml = simplexml_load_string($string);

このようにして読み込まれた XML データは、テキストデータから "SimpleXMLElement" というオブジェクト形式に変換されます。

取り込んだ XML データを使用する

XML から取り込んだ "SimpleXMLElement" オブジェクトは、XML の階層に合わせて、各要素が "SimpleXMLElement" オブジェクトの形で格納されています。

 

最初のオブジェクトはルート要素が持つ内容を "SimpleXMLElement" 型で保持しています。

この "SimpleXMLElement" 型は、保持している値や子要素を連想配列のような形で取得できるようになっています。キーは要素名、値はその中に記載されているデータです。

 

ルート要素の子要素やテキストを取得する

SimpleXMLElement 型が持つデータは、テキストでも子要素でも SimpleXMLElement 型で格納されています。

ルート要素が持っている子要素については、次のようにして順次取得することが可能です。

foreach ($xmlObject->children() as $name => $value)

{

 

}

このようにすることで、$xmlObject 変数に格納されていた "SimpleXMLElement" 型が持つ、要素と値の対を、順に取得して処理することができます。

このとき、上記の例では要素名は $name に、値は $value に格納されます。値は、テキストであっても子要素であっても SimpleXMLElement 型になります。

 

子要素を名前を指定して取得する

要素がもつの子要素を、要素名を指定してピンポイントにアクセスしたい場合は次のようにします。

$children = $xmlObject->{'要素名'};

これで、$xmlObject が持つ子要素 <要素名> の値または子要素を $children に取得することができました。

 

このとき、取得されるデータ型は SimpleXMLElement 型で、同一階層に同じ要素名が複数存在する場合があります。

そのため、例えば目的の要素名を持つタグが 1 つだけの場合で、それを取得したい場合には、次のように最初(0 番目)の要素を取得するようにします。

$child = $xmlObject->{'要素名'}->{0};

また、複数取得できた要素を順次処理したい場合には、次のようにします。

foreach ($xmlObject->{'要素名'} as $value)

{

 

}

ここでは、要素名を指定して子要素を取得しているので、取得される要素は必ず指定した要素名になります。

そのため、ここでは "as" の後を "$name => $value" ではなく "$value" として、値だけを取得して順次処理するような感じにしてみています。

 

また、たとえば "<空間名:要素名>" といったような、名前空間を持つ要素を取得したい場合には、要素名を指定するところの前に children メソッドを挟むことで取得できます。

$children = $xmlObject->children('空間名', true)->{'要素名'};

children メソッドの 2 番目の引数は、1 番目の引数をどのように扱うかを指定しています。

これが true の場合には "プレフィックス文字列" として扱い、false の場合は "名前空間 URL" として扱われます。

 

要素が持つテキストの値を取得する

要素が持つ値がテキストでも、要素には SimpleXMLElement 型として値が格納されています。

要素がテキスト値を持っていると判っている場合は、その要素を string 型にキャストしてあげることで、簡単に値を取得することが可能です。

$value = (string)$xmlObject;

ただしこのとき、要素が空のテキストを持つ場合でも、子要素を持つ場合でも、どちらとも空文字列が取得されるようでした。

また、SimpleXMLElement 型の値を is_string 関数で判定しても、文字列かどうかを知ることができないため、要素が持つ内容がテキストか子要素かを知るのは簡単には行かない感じです。

 

その辺りを踏まえると、取得できた値が子要素かテキストかを知りたい場合は、次のように判定すると良さそうな感じでした。

if ($value->count() == 0 && (string)$value != '')

{

}

テキスト要素の場合は子要素の数が 0 になるので、まずはそれで判断します。

その上で今回は、値を string 型に変換したときに、それが空文字列ではないかどうかをチェックしています。空文字列でないかのチェックは状況によっては必要ないかもしれません。

 

要素が存在するかを調べる

存在しない要素名や要素番号を指定した場合、SimpleXMLElement は NULL を返します。

そのため、次のような感じにすることで、要素が存在しているかどうかを確認することが可能です。

if (!is_null($xmlObject->{'要素名'}))

{

}

このようにすることで、変数 $xmlObject が <要素名> という要素を持っているかを調べることができます。

 

要素の名前を取得する

ルート要素の名前や、取得した子要素の名前を調べたい場合には、SimpleXMLElement の getName メソッドを使用します。

$name = $xmlObject->getName();

このようにすることで、変数 $name へ $xmlObject に格納された要素の名前が string 型で取得できました。

 

要素が持つ子要素の数を取得する

要素が持つ子要素の数を取得するには、次のようにします。

$elementCount = $xmlObject->count();

このとき、要素がテキストの値を持っていても、子要素がない場合には 0 が取得できるようでした。

 

要素の属性を取得する

要素が持っている属性は attributes メソッドを使用します。

$attributes = $xmlObject->attributes();

これで $xmlObject が保持している属性の一覧を取得できました。

 

取得された属性の一覧は、子要素の時と同じ SimpleXMLElement 型で取得できるので、同様にして次のように、各属性の値を順次取得して処理することが可能です。

foreach ($xmlObject->attributes() as $name => $value)

{

 

}

これで、その要素が持つ属性の、属性名 $name と属性値 $value の対を順次取得して行けます。

順次ではなく、任意の属性を取得したい場合には、次のようにします。

$attribute = (string)$xmlObject->attributes()->{'属性名'};

これで、$xmlObject 要素が持つ属性 '属性名' の値を取得することができました。

上の例では string 型にキャストして取り出していますが、これは、値が SimpleXMLElement 型で格納されているためです。属性の値を取得したら、それを文字列として使用することが多い気がして、ここではキャストする形にしています。

キャストしなければ、属性の値も SimpleXMLElement 型で取得されるため、getName() メソッドを使用して、その属性名を取得したりすることができます。

 

取り込んだ XML データを編集する

SimpleXMLElement には、要素や属性を追加するメソッドが用意されています。

 

たとえば、変数 $xmlObject に格納した SimpleXMLElement データに属性を追加するには、次のようにします。

$xmlObject->addAttribute('属性名', '値');

 

同様にして、次のように子要素を追加することも可能です。

$xmlObject->addChild('要素名', 'テキスト値');

これで、二つ目の引数に指定したテキストの値を持つ要素を、$xmlObject の子要素として追加することができました。

このとき、二つ目の引数を省略すると、空の要素が追加されます。

 

このようにして修正を加えた SimpleXMLElement は、簡単に XML テキストに変換することができます。

そのためには、変換したい SimpleXMLElement のところで、次のように asXML メソッドを呼び出します。

$xml = $xmlObject->asXML();

これで $xml 変数に、SimpleXMLElement 型の $xmlObject が保持している値が、XML テキストに展開されて、文字列型のデータとして取得できました。

引数としてファイル名を指定すると、取得した XML テキストをそのファイルに書き出すことができます。

なお、この asXML というメソッドは、ファイルへの出力時でも、文字列への出力時でも、失敗した場合には FALSE を返します。


[ もどる ]