[PHP] xmlを配列にする。
篠原 隆司
アフィリエイト広告を利用しています
このページの内容が役に立ったら X (旧twitter) でフォローして頂けると励みになります
挨拶や報告は無しで大丈夫です
PHPでXML形式のテキストデータを連想配列にする関数を作りました。
PHPでXMLを配列にするものは既に存在します。
PHPで、XML形式のテキストデータを、連想配列にするというと、似たようなものとしてこういうのがありますね。
- PEARのXML_Unserializer
- xml2array
はい。そういうわけで、実は既にあるんです。
既にあるのに、同じようなものを作る。
こういう行為を「車輪の再発明」なんて言ったりします。
PHPでXMLを配列にするものは既に存在するけど・・・
とはいえ、今回作ったのには、やはり理由がありまして、
その、
なんていうか、メンドクサイじゃないですか?
↑ であげた既存のものを使っていらっしゃるかたはいるでしょうか?
ご存知のない方は、Googleで軽く調べて頂ければと思うのですが、なんだかややこしくないですか?
XMLを連想配列にしたいだけなのに。
で、PHPでXMLを配列にする関数を作りました
これが、今回作った関数になります。
/*
* 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;
}
これだけです。
その代わりと言ってはなんですが、なんでもかんでも対応しているわけではありません。
[CDATA] など、凝ったものは省いております。
それと、simpel_xmlを扱いますので、PHP5以上の対応となります。
PHPでXMLを配列にするxml2array()で対応していること
まず、XMLのツリー形式そのままで、多階層な連想配列にします。
値(value)と属性値(attribute)を取り込みます。
PHPでXMLを配列にするxml2array()の使い方例
サンプルとして実際のコードを書いてみます。
// 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);
ここまでで、$xmlは、$retArray として連想配列になっています。
試しに出力してみましょう。
// 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) : いわてけん
print_rで、配列の中を覗いてみます。
// 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
)
)
)
)
)
)
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に対応することにします。
$xml = preg_replace('/<([/]?)[A-Za-z0-9]+:([A-Za-z0-9]+)( xmlns:[^>]+)?>/', '<12>', $xml);
$sxml = simplexml_load_string($xml);
このように、simplexml_load する前に、preg_replace で、名前空間の指定を取り外します。
※ 名前空間まで厳密にチェックする必要があるかどうかは、案件ごとに異なると思います。
ご使用の際は、案件の仕様を満たすかどうか、ご自身の判断でお使いください。