[PHP] xmlを配列にする。

PHPで、XML形式のテキストデータを、連想配列にする関数を作りました。

PHPでXMLを配列にするものは既に存在します。

PHPで、XML形式のテキストデータを、連想配列にするというと、似たようなものとしてこういうのがありますね。

はい。そういうわけで、実は既にあるんです。
既にあるのに、同じようなものを作る。
こういう行為を「車輪の再発明」なんて言ったりします。

PHPでXMLを配列にするものは既に存在するけど・・・

とはいえ、今回作ったのには、やはり理由がありまして、
その、
なんていうか、メンドクサイじゃないですか?

↑ であげた既存のものを使っていらっしゃるかたはいるでしょうか?
ご存知のない方は、Googleで軽く調べて頂ければと思うのですが、なんだかややこしくないですか?

XMLを連想配列にしたいだけなのに。

で、PHPでXMLを配列にする関数を作りました

これが、今回作った関数になります。

[code language=”php”] /*
* simplexml形式を連想配列にする。
* $sxml = simplexml_load_string($xml);
* $retArray = xml2array($sxml);
*/
function xml2array(&$sxml, $isRoot = true){
if ($isRoot)
return array($sxml->getName() => array(xml2array($sxml, false)));
$r = array();
foreach($sxml->children() as $cld){
$a = &$r[(string)$cld->getName()];
$a = &$a[count($a)];
if (count($cld->children()) == 0)
$a[‘_value’] = (string)$cld;
else
$a = xml2array($cld, false);
foreach($cld->attributes() as $at)
$a[‘_attr’][(string)$at->getName()] = (string)$at;
}
return $r;
}
[/code]

これだけです。
16行足らずですが、これだけです。

その代わりと言ってはなんですが、なんでもかんでも対応しているわけではありません。
[CDATA] など、凝ったものは省いております。
それと、simpel_xmlを扱いますので、PHP5以上の対応となります。

PHPでXMLを配列にするxml2array()で対応していること

まず、XMLのツリー形式そのままで、多階層な連想配列にします。
値(value)と属性値(attribute)を取り込みます。

PHPでXMLを配列にするxml2array()の使い方例

サンプルとして実際のコードを書いてみます。

[code language=”php”] // XMLを用意します。
// ファイルから読みこんでもOKです。
$xml =<<<EOT
<?xml version="1.0" encoding="utf-8" ?>
<area>
<pref code="0001">
<name no="1">北海道</name>
<kana>ほっかいどう</kana>
</pref>
<pref code="0002">
<name no="2">青森県</name>
<kana>あおもりけん</kana>
</pref>
<pref code="0003">
<name no="3">岩手県</name>
<kana>いわてけん</kana>
</pref>
</area>
EOT;

// simplexml として、読みこみます。
$sxml = simplexml_load_string($xml);

// xml2array に渡します。
$retArray = xml2array($sxml);
[/code]

ここまでで、$xmlは、$retArray として連想配列になっています。

試しに出力してみましょう。

[code language=”php”] // for文で、取り出してみます。
foreach($retArray[‘area’] as $area){
foreach($area[‘pref’] as $pref){
$name = $pref[‘name’][0];
$kana = $pref[‘kana’][0];
echo $pref[‘_attr’][‘code’];
echo ‘ : ‘ . $name[‘_value’];
echo ‘(‘ . $name[‘_attr’][‘no’] . ‘)’;
echo ‘ : ‘ . $kana[‘_value’];
echo ‘<br />’;
}
}

↓下記のように出力されます。

0001 : 北海道(1) : ほっかいどう
0002 : 青森県(2) : あおもりけん
0003 : 岩手県(3) : いわてけん
[/code]

print_rで、配列の中を覗いてみます。

[code language=”php”] // print_r で、配列の中を出力します。
echo ‘<pre>’;
print_r($retArray);
echo ‘</pre>’;

↓ 下記が出力されます。

Array
(
[area] => Array
(
[0] => Array
(
[pref] => Array
(
[0] => Array
(
[name] => Array
(
[0] => Array
(
[_value] => 北海道
[_attr] => Array
(
[no] => 1
)
)
)
[kana] => Array
(
[0] => Array
(
[_value] => ほっかいどう
)
)
[_attr] => Array
(
[code] => 0001
)
)
[1] => Array
(
[name] => Array
(
[0] => Array
(
[_value] => 青森県
[_attr] => Array
(
[no] => 2
)
)
)
[kana] => Array
(
[0] => Array
(
[_value] => あおもりけん
)
)
[_attr] => Array
(
[code] => 0002
)
)
[2] => Array
(
[name] => Array
(
[0] => Array
(
[_value] => 岩手県
[_attr] => Array
(
[no] => 3
)
)
)
[kana] => Array
(
[0] => Array
(
[_value] => いわてけん
)
)
[_attr] => Array
(
[code] => 0003
)
)
)
)
)
)
[/code]

PHPでXMLを配列にするポイント

print_rの結果をご覧頂いたように、XMLのツリー構造を保ったまま連想配列にしています。
ここでいくつかポイントを書いておきます。

ノードの扱いについて

ノードは、自身の直下に、配列を作ります。
ノードでは、 pref[0], pref[1], ppref[2] と3つ作られています。
pref[0]が、XMLで最初に現れるに対応します。
pref[1]は2番目に、pref[2]は3番目のに対応・・・と続きます。

末端ノードのとき

ノードが末端ノードの時は、その値を[‘_value’] に、値がセットされます。
※ _value とアンダーバーから始まることに注意してください。

属性の参照

属性値(Attribute) は、 [‘_attr’] にセットされます。
[‘_attr’] の中の、添え字は、XMLで使われている属性名となります。
※ _attr とアンダーバーから始まることに注意してください。

XMLに名前空間が使われていたら・・・

simple_xmlで、名前空間を扱おうとすると少々面倒な記述になります。
具体的には、 $simple_xml->children(‘名前空間のURI’); といった感じで、単純にchildrenだけでは取れません。
ちなみに、XMLで定義されている名前空間は、$simple_xml->getDocNamespaces(true); これで取ることができます。

ただ・・・、実際の場面において、名前空間まで意識することはあまり無いかと思います。
少なくとも、私が扱うなかでは、名前空間まで厳密にチェックして値を取得する、ほどのことは必要とすることがまずありません。

そこで、元のXMLから、名前空間の指定を単純に取り外すことで、名前空間付きのXMLに対応することにします。

[code language=”php”] $xml = preg_replace(‘/<([/]?)[A-Za-z0-9]+:([A-Za-z0-9]+)( xmlns:[^>]+)?>/’, ‘<12>’, $xml);
$sxml = simplexml_load_string($xml);
[/code]

このように、simplexml_load する前に、preg_replace で、名前空間の指定を取り外します。

※ 名前空間まで厳密にチェックする必要があるかどうかは、案件ごとに異なると思います。
ご使用の際は、案件の仕様を満たすかどうか、ご自身の判断でお使いください。

広告