Pear XML_Serializerで多重階層のXMLを生成する

XML_Serializerは配列からXMLを生成できる便利なライブラリです。
以下のような、「1つの階層に同じタグが並列に並ぶもの」が複数の階層に現れる場合の生成法がわからなかったので、メモしておきます。

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <drink id="1">
        <name>コーラ</name>
        <item>ダイエットコーラ</item>
        <item>バニラコーク</item>
    </drink>
    <drink id="2">
        <name>ペプシ</name>
        <item>ペプシ バオバブ</item>
        <item>ペプシ しそ</item>
    </drink>
</data>

この場合、「data」の子ノードに「drink」が並列に複数並び、「drink」の子ノードに「item」が複数並んでいます。

結論から言えば、オプションの「defaultTagName」指定がポイントでした。

検証環境は以下の通りです。
OS:Ubuntu10.10
PHP:5.3.3

では始めます。(以下、rootユーザで作業しています)

1.Pearのインストール

apt-get install php-pear

2.XML_Serializerのインストール

sudo pear install --alldeps xml_serializer-beta

3.確認

pear list で確認します

INSTALLED PACKAGES, CHANNEL PEAR.PHP.NET:
=========================================
PACKAGE          VERSION STATE
Archive_Tar      1.3.7   stable
Console_Getopt   1.2.3   stable
PEAR             1.9.1   stable
Structures_Graph 1.0.3   stable
XML_Parser       1.3.4   stable
XML_Serializer   0.20.2  beta
XML_Util         1.2.1   stable
4.ソース準備
<?php
require_once("XML/Serializer.php");

// 出力したい内容
$data = array( 0 => array('_attributes' => array('id'=> '1'),
                          'name' => 'コーラ',
                          0 => 'ダイエットコーラ',
                          1 => 'バニラコーク'
                          ),
               1 => array('_attributes' => array('id'=> '2'),
                          'name' => 'ペプシ',
                          0 => 'ペプシ バオバブ',
                          1 => 'ペプシ しそ'
                         )
               );

// XML生成時のオプション
 $options = array(
      "indent"          => "\t",
      "linebreak"       => "\n",
      "typeHints"       => false,
      "addDecl"         => true,
      "encoding"        => "UTF-8",
      "rootName"        => "data",
      "rootAttributes"  => array(),
      "defaultTagName"  => array('data'=> 'drink',
                                 'drink' => 'item'
                                 ),
      "attributesArray" => "_attributes"
      );

$serializer = new XML_Serializer($options);
$serializer->serialize($data);
$result = $serializer->getSerializedData();

header("Content-Type: text/xml; charset=utf-8");
echo $result; 
5.ブラウザから確認

ちゃんと出力されました。

ポイントは$optionの

"defaultTagName"  => array('data'=> 'drink',
                                'drink' => 'item'
                           ),

という部分です。
まず、rootNameに「data」を指定しているため、
出力したい内容の$data全体がdataタグで囲まれる形になります。
そして、defaultTagNameで「'data'=>'drink'」と指定することで、
$dataの1次元目(= dataタグの子ノード)のキーが数字だと自動的に
drinkタグで囲まれます。
itemタグも同様のロジックで囲まれますね。


余談ですが・・・
XML_Serializerを使っていて、
「drinkやitemの階層で、drink/itemと違うタグを複数並列に配置したい場合はどうすればよいか?」
というのが気になっています。

例えば、

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <drink id="1">
        <name>コーラ</name>
        <name>cola</name>
        <item>ダイエットコーラ</item>
        <item>バニラコーク</item>
    </drink>
    <drink id="2">
        <name>ペプシ</name>
        <name>pepsi</name>
        <item>ペプシ バオバブ</item>
        <item>ペプシ しそ</item>
    </drink>
</data>

のようにnameタグを複数出力したい場合はどうすればよいのでしょうか?
(この例はあまりよくないので、"english_name"タグとかに変えたくなりますがそこはスルーします!)

defaultTagNameで'drink' => 'item'と置いてしまったら、

array('_attributes' => array('id'=> '1'),
	                      'name' => 'コーラ',
                              'name' => 'cola',
	                       0 => 'ダイエットコーラ',
	                       1 => 'バニラコーク'
	                     ),

と書いたとしてもname要素がcolaに上書きされるだけです。。

上のXMLをテキストファイルに保存してブラウザに読み込ませるとちゃんと表示されることから
XML構造として誤りではないようですし、何とかできたらいいですね。
恐らくPHPとの関係上仕方ない気もしますが、「いや出来るぜ☆」という方はぜひ御一報下さい!