LoginSignup
13
10

More than 5 years have passed since last update.

[PHP] XML⇒JSON変換(名前空間、属性、CDATAも考慮)

Last updated at Posted at 2015-12-01

ネット検索でよく見かける方法では、XMLタグ名にコロン(名前空間)や属性が含まれる場合には、JSON化した時に抜け落ちます。(ただし、PHPのバージョンにかなり依存するようです)

例)以下をJSON化すると「コロンを含んだ名前空間タグ」「属性名="属性値"」「CDATA」がごっそり消えてしまいます…

xml
<root>
    <test1:abc>値1</test1:abc>
    <test2 属性名="属性値">値2</test2>
    <test3><![CDATA[値3]]></test3>
</root>
json
{
    "test2": "値2",
    "test3": {},
}

なお、環境は PHP5.4 です。 (JSON_XXX定数を使わなければPHP5.3でも動作可)

churippu_s.png サンプルコード

以下、急場しのぎ的な部分もありますが、『XML⇒JSON変換』関数を自作してみました。

php
// XML(RSSなど)を取得
$strXml = file_get_contents("http://xxx.com/rss");
// XML⇒JSONに変換
$strJson = xml_to_json($strXml);
// 出力
echo $strJson;

//**********************************
// XML ⇒ JSONに変換する関数
//**********************************
function xml_to_json($xml)
{
    // コロンをアンダーバーに(名前空間対策)
    $xml = preg_replace("/<([^>]+?):([^>]+?)>/", "<$1_$2>", $xml);
    // プロトコルのは元に戻す
    $xml = preg_replace("/_\/\//", "://", $xml);
    // XML文字列をオブジェクトに変換(CDATAも対象とする)
    $objXml = simplexml_load_string($xml, NULL, LIBXML_NOCDATA);
    // 属性を展開する
    xml_expand_attributes($objXml);
    // JSON形式の文字列に変換
    $json = json_encode($objXml, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
    // "\/" ⇒ "/" に置換
    return preg_replace('/\\\\\//', '/', $json);
}

//**********************************
// XMLタグの属性を展開する関数
//**********************************
function xml_expand_attributes($node)
{
    if($node->count() > 0) {
        foreach($node->children() as $child)
        {
            foreach($child->attributes() as $key => $val) {
                $node->addChild($child->getName()."@".$key, $val);
            }
            xml_expand_attributes($child); // 再帰呼出
        }
    }
}

※ソース内の json_encode() 関数の第2引数にある JSON_XXX の定数は、PHP5.4.0以降でしか使えませんのでご注意下さい

上記を実行すると、たとえばこういうXMLが、

xml
<root>
    <test1:abc>値1</test1:abc>
    <test2 属性名="属性値">値2</test2>
    <test3><![CDATA[値3]]></test3>
</root>

こういうJSONに変換されます。

json
{
    "test1_abc": "値1",
    "test2": "値2",
    "test3": "値3",
    "test2@属性名": "属性値"
}

churippu_s.png 解説

  • 名前空間については、コロンをアンダーバーに置換することで対応
  • 属性については、親要素の子要素となる形で外出しすることで対応
  • CDATAについては、simplexml_load_string()関数の第3引数にLIBXML_NOCDATAを指定すればOK

一応、ソースデモはこちら

(・o・ゞ いじょー。

churippu_s.png 参考URL

13
10
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
10