dポイントプレゼントキャンペーン実施中!

はじめて投稿させていただきます。
DBに登録されているツリーテーブルを配列に取り込み、
xmlのツリーにしてファイルに保存したいと考えております。
DBのデータは以下のようになっております。
idcidattname
0-1Da
10Fb
20Fc
中略
33-1Dd
3433De
3534Ff
3634Fg
中略
262-1Dh
263262Di
264263Fj

id:インデックス
cid:子番号(idに同じ番号を持つものを親とする)(-1は最上階層の親)
att:DはディレクトリFは末端
name:表示する名前
これを展開しながらxmlタグを挿入していきたいのですが
nameを出力するタイミングでタグを挿入しようとすると末端のものしか
開始・終了タグで挟むことができません。
入れ子になっている場合の親の終了タグは全ての子供が終わった後に、階層の深さの数だけを最後に足してやりたいのです。
不規則な配列なのでforeachでするくらいしかわからず、
やってみたのですがatt=="D"なら再帰処理で繰り返し、
Dでなくなったら末端を書くくらいの事しかできず、
終了タグをどういった処理で入れたらよいかわかりません。

800文字制限に引っかかってしまい実際の配列の形はのせれませんでした。。
分割投稿も禁止のようで。。
各要素を持つ末端配列はわかりやすいように、仮に一つであっても次元を一つ下げて0番目の配列に格納しております。
もしかしたら配列への格納方法もよくないのかもしれません。。

・後々扱いやすいような配列への格納の仕方
・配列を展開しながらのタグの挿入方法
をどなたか良い案がありましたら宜しくお願い致します。

A 回答 (4件)

面白そうなので、プログラムを書いてしまいました^^。



DBからデータを読みながら処理するのではなく、DBからのデータを一旦$dbdataに入れて処理をする前提のプログラムです(DBからSELECTする部分は省略してます)。DBのデータが、きれいな順番で並んでいないことがあるならば、そうしないとうまく処理できないと思います。

内部的にはDOMでデータを扱ってます。
>・後々扱いやすいような配列への格納の仕方
配列よりもクラスのオブジェクトにするのが一番扱いやすいと思います。クラスを自作しても良いのですが、色々と機能を追加していくとDOMに近づいていくように思います。なので、DOMを使っています。

それから、ディレクトリ階層を下に辿っていく処理は再帰を利用しています。

<?php
$dbdata
 = array(
   array('id'=>'0','cid'=>'-1','attr'=>'D','name'=>'a'),
   array('id'=>'1','cid'=>'0','attr'=>'F','name'=>'b'),
   array('id'=>'2','cid'=>'0','attr'=>'F','name'=>'c'),
   array('id'=>'33','cid'=>'-1','attr'=>'D','name'=>'d'),
   array('id'=>'34','cid'=>'33','attr'=>'D','name'=>'e'),
   array('id'=>'35','cid'=>'34','attr'=>'F','name'=>'f'),
   array('id'=>'36','cid'=>'34','attr'=>'F','name'=>'g'),
   array('id'=>'262','cid'=>'-1','attr'=>'D','name'=>'h'),
   array('id'=>'263','cid'=>'262','attr'=>'D','name'=>'i'),
   array('id'=>'264','cid'=>'263','attr'=>'F','name'=>'j'),
  );

// 扱いづらいので、以下のようなハッシュ形式データにする。
// array('0' => array('cid'=>'-1','attr'=>'D','name'=>'a'),
//   '1' => array('cid'=>'0','attr'=>'F','name'=>'b'),
$hash = array();
foreach ($dbdata as $arr) {
 $id = $arr['id'];
 unset($arr['id']);
 $hash[$id] = $arr;
}

// DOMDocument作成
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->formatOutput = true;

// hoge呼び出し
$hoge = new hoge($doc, $hash);
$doc->appendChild($hoge->exec());
echo $doc->saveXML();

class hoge {
 var $doc;
 var $hash;

 function hoge($doc, $hash) {
  $this->doc = $doc;
  $this->hash = $hash;
 }

 function exec($id = '-1') {
  // 初回呼び出し
  if ($id == '-1') {
   // root要素作成
   $retnode = $this->doc->createElement('root');
  }
  // 初回以外
  else {
   // attr (D or F)
   $attr = $this->hash[$id]['attr'];
   // name
   $name = $this->hash[$id]['name'];

   // D or Fという要素作成
   $retnode = $this->doc->createElement($attr);
   // id属性設定
   $retnode->setAttribute('id', $id);
   // name属性設定
   $retnode->setAttribute('name', $name);
  }

  // 初回 or attr == D の場合(子供がいる)
  if ($id == '-1' || $attr == 'D') {
   foreach ($this->hash as $k => $v) {
    // 子要素か?
    if ($v['cid'] == $id) {
     // 再帰呼び出しして、$retnodeの子要素にする
     $retnode->appendChild($this->exec($k));
    }
   }
  }
  return $retnode;
 }
}
?>

インデントは全角スペースを使っているので、半角スペースに置き換えてください。

なお、数日間出掛けてしまうので、追加のご質問頂いても返答できないかもしれません。申し訳ありません。

もし何かの役に立てば幸いです。

この回答への補足

書き込みをするスペースがここくらいしかなかないようなのでここで報告させていただきます。
結論から先に言いますと希望する挙動を得ることができました。
ありがとうございましたm(_ _)m
PHPマニュアルページのDOMの部分とにらめっこしながらfdsjaklfjas様が書いてくださったソースを実データに合わせた形に変更し、DBからデータを取得してスクリプトを走らせたところ日本語がやはり化けましたので、取得しながらエンコードをかけたらうまくいきました。
$doc = new DOMDocument('1.0', 'UTF-8');
この段階で
$doc = new DOMDocument('1.0', 'Shift-JIS');
とすることは出来ないのですね^^;
あと今回は
<entity id="1" pic="hoge.jpg" t_name="item_0001" url="contents" image="images/dir.gif" imageopen="images/diropne.gif" name="商品1"/>
のようにid等必要なものを全てentity要素の属性として1つのタグの中に書く事をfdsjaklfjas様のソースから教えていただいたのですが、
上記タグを例えば
<entity id="1">
 <pic>hoge.jpg</pic>
 <t_name>item_0001</t_name>
 <url>contents</url>
 <image>images/dir.gif</image>
 <imageopen>images/diropne.gif</imageopen>
 <name>商品1</name>
</entity>
のようにentity配下のpic、t_name要素というような形を生成することは可能なのでしょうか?
createElementで作成してappendChildで追加するとどうしても
<pic>は<pic />というタグ1つで終了する形になってしまいまして。。
勉強の為、もし宜しければ今回作成していただいたプログラムを題材にそういったことが出来るのなら教えてくださいm(_ _)m

補足日時:2007/01/09 10:36
    • good
    • 0
この回答へのお礼

具体的にプログラムを作っていただきありがとうございます!
私の方も休み明けにならないとソースを触れないので
休み明けになりましたら早速試してみます!
もし実際に組んでみて質問したいことがでてきたら数日後なら
大丈夫でしょうか^^;
その時はまた宜しくお願い致します。

お礼日時:2007/01/07 02:06

>のようにentity配下のpic、t_name要素というような形を生成することは可能なのでしょうか?



$e1 = $doc->createElement('entity');
$e2 = $doc->createElement('pic', 'hoge.jpg');
$e3 = $doc->createElement('t_name', 'item_0001');
$e1->appendChild($e2);
$e1->appendChild($e3);

でどうでしょうか。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
待っている間に考えていました。

 <?xml version="1.0" encoding="utf-8" ?>
 - <entity>
  - <aaa>
   - <bbb>
     <pic>hoge.jpg</pic>
     <t_name>item_0001</t_name>
    </bbb>
   </aaa>
  </entity>
上のような形ってどうやるんだろうって思っていたのですが
<?php
$doc = new DOMDocument('1.0', 'utf-8');
$e1 = $doc->createElement('entity');
$e2 = $doc->createElement('aaa');
$e3 = $doc->createElement('bbb');
$e4 = $doc->createElement('pic', 'hoge.jpg');
$e5 = $doc->createElement('t_name', 'item_0001');
$e3->appendChild($e4);
$e3->appendChild($e5);
$e2->appendChild($e3);
$e1->appendChild($e2);
$doc->appendChild($e1);
echo $doc->saveXML();
?>
のように深い階層から順番にappendChildを記述していけば良いのですね^^
DOMDocumentというのは今回初めて使ってみたのですがすごく勉強になりました。
どうもありがとうございました m(_ _)m

お礼日時:2007/01/10 15:35

多分、DOMを使った方がいいかもしれない。

。。
自分も勉強中だからまだよくわからないけど新規に作るなら

$doc=new DOMDocument('1.0','UTF-8');
$doc->appendChild($doc->createElement('root'));

でもこれver5じゃないと使えないみたい。

この回答への補足

アドバイスありがとうございます
>でもこれver5じゃないと使えないみたい。
ver5とはPHP5ということでしょうか?
もしそうでしたらこちらの環境はPHP5です。
ですが、DOMDocumentというのを使用すればまっさらな状態から
不規則階層のxmlツリーを作成できるのでしょうか?

現実問題として不規則階層を持つツリーデータをDBから取り出して
xmlツリーを作成すること自体は可能なのでしょうかね・・・汗
階層数があらかじめ決まっていれば何とかなりそうな予感はするのですが。。。

引き続き、良い方法がありましたらどなたかご教授お願い致しますm(__)m

補足日時:2007/01/07 00:51
    • good
    • 0
この回答へのお礼

DOMDocumentを使用して
fdsjaklfjas様のソースをこちらの環境に合わせながら
なんとか希望通りのものを作成することができました。
DOMDocumentってすごいですね^^;
ありがとうございました。

お礼日時:2007/01/09 10:35

単純ループじゃなく再帰呼出(リカーシブコール)系で組み直すとか


それだと効率悪いか・・・もう少し考えないとだめかな・・・

この回答への補足

以下のような再帰処理で配列を作ってみたのですが
この配列でその後の処理がいけるのかいけないのか・・・。
自分の力ではここからxmlツリーを作成することが出来ませんでした。。

function GetTree($val)
{
$sql = "select * from tree_tbl where cid = ".$val." order by id";
if(!($result = mysql_query($sql)))
{
return;
}
$leaves = "";
while($row = mysql_fetch_assoc($result))
{
$leaf = "";
$leaf[0] = $row;
//子がある場合
if($row["att"]=="D"){
$leaf[1] = GetTree($row["id"]);
}
$leaves[] = $leaf;
}
return $leaves;
}
$tree = GetTree(-1);
print_r($tree);

補足日時:2007/01/06 03:40
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!