はじめに

PHP でネスト構造の XML(SimpleXMLElement)を、再帰処理で配列(array)に変換する方法を整理した。

TL;DR

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. get_object_vars による変換
      1. 単純構造
      2. ネスト構造の変換
    2. 再帰処理で解決
      1. 懸念点
    3. json_decode, json_encode, simplexml_load_string の組み合わせで解決
  5. まとめ
  6. 参考文献

環境・条件

1
2
3
4
5
$ grep -i pretty /etc/os-release
PRETTY_NAME="Ubuntu 16.04.3 LTS"

$ php -v
PHP 7.2.22-1+ubuntu16.04.1+deb.sury.org+1 (cli) (built: Sep 2 2019 12:54:12) ( NTS )

詳細

get_object_vars による変換

単純構造

get_object_vars を使うと、XML(SimpleXMLElement) を配列に変換できる。

以下のような XML を変換してみる。

1
2
3
4
<foo>
<bar>1</bar>
<baz>hoge</baz>
</foo>

以下のように特に問題なし。

1
2
3
4
5
6
7
8
9
10
11
12
$xml_str = '<foo><bar>1</bar><baz>hoge</baz></foo>';
$xml = new SimpleXMLElement($xml_str);
// => SimpleXMLElement {
// +"bar": "1",
// +"baz": "hoge",
// }

$ary = get_object_vars($xml);
// => [
// "bar" => "1",
// "baz" => "hoge",
// ]

ネスト構造の変換

続いて下記のようなネスト構造の XML を変換してみる。

1
2
3
4
5
6
7
8
9
<foo>
<bar>1</bar>
<baz>
<hoge>
<fuga>piyo</fuga>
<cat>meow</cat>
</hoge>
</baz>
</foo>

以下の通り、1階層目までは変換できているが、2階層目以降は SimpleXMLElement のままとなっている。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$xml_str = '<foo><bar>1</bar><baz><hoge><fuga>piyo</fuga><cat>meow</cat></hoge></baz></foo>';
$xml = new SimpleXMLElement($xml_str);
// => SimpleXMLElement {
// +"bar": "1",
// +"baz": SimpleXMLElement {
// +"hoge": SimpleXMLElement {
// +"fuga": "piyo",
// +"cat": "meow",
// },
// },
// }

$ary = get_object_vars($xml);
// => [
// "bar" => "1",
// "baz" => SimpleXMLElement {
// +"hoge": SimpleXMLElement {
// +"fuga": "piyo",
// +"cat": "meow",
// },
// },
// ]

再帰処理で解決

get_object_vars のコメント を参考に作成した。

get_object_vars で変換後、各要素に対して foreach で処理。$value がオブジェクト(= XML)の場合は再帰呼び出し。

1
2
3
4
5
6
7
8
9
10
11
function xml_to_array($xml) {
$ary = [];
$_ary = is_object($xml) ? get_object_vars($xml) : $xml;
foreach ($_ary as $key => $value) {
if (is_object($value)) {
$value = xml_to_array($value);
}
$ary[$key] = $value;
}
return $ary;
}

処理結果は下記

1
2
3
4
5
6
7
8
9
10
xml_to_array($xml)
// => [
// "bar" => "1",
// "baz" => [
// "hoge" => [
// "fuga" => "piyo",
// "cat" => "meow",
// ],
// ],
// ]

懸念点

再帰呼び出ししてるので、巨大な XML とか、ネストがめちゃくちゃ深い XML とかを処理しきれるかは不明。

スタックオーバーフローとか発生するかも?

json_decode, json_encode, simplexml_load_string の組み合わせで解決

php - Recursive cast from SimpleXMLObject to Array - Stack Overflow のコメントの方法でもできる。

json_decode, json_encode, simplexml_load_string の組み合わせ。

1
2
3
4
5
6
7
8
9
10
json_decode(json_encode((array) simplexml_load_string($xml_str)), 1);
// => [
// "bar" => "1",
// "baz" => [
// "hoge" => [
// "fuga" => "piyo",
// "cat" => "meow",
// ],
// ],
// ]

まとめ

参考文献

関連記事