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ユーザで作業しています)
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との関係上仕方ない気もしますが、「いや出来るぜ☆」という方はぜひ御一報下さい!