php数组的无序列表怎么取值,在父子窗体中无序列表php打印层次数据?

从后端到前端都可以.

您可以从php脚本中调用一个非递归存储过程(sproc),该过程为您生成消息层次结构.这种方法的优点是您只需要从php到数据库进行一次SINGLE调用,而如果使用内联SQL,则将进行尽可能多的调用(最少).另一个优点是,由于它是一种非递归的程序,因此性能极好,并且还可以使您的php代码保持整洁.最后,为了记录起见,我要说的是,调用存储过程比任何其他方法都更加安全和高效,因为您只需要授予对应用程序用户的执行权限,并且存储过程到数据库的往返行程比任何其他方法都要少其他方法,包括参数化查询,该查询至少需要2个调用才能进行单个查询(一种用于在db中设置查询模板,另一种用于填充参数)

因此,这就是从MySQL命令行调用存储过程的方式.

call message_hier(1);

这是它创建的结果集.

msg_id emp_msg parent_msg_id parent_msg depth

====== ======= ============= ========== =====

1 msg 1 NULL NULL 0

2 msg 1-1 1 msg 1 1

3 msg 1-2 1 msg 1 1

4 msg 1-2-1 3 msg 1-2 2

5 msg 1-2-2 3 msg 1-2 2

6 msg 1-2-2-1 5 msg 1-2-2 3

7 msg 1-2-2-1-1 6 msg 1-2-2-1 4

8 msg 1-2-2-1-2 6 msg 1-2-2-1 4

好的,现在我们可以通过简单地用我们需要的任何起始节点调用sproc来获取全部或部分消息树的能力,但是我们将如何处理结果集?

在这个示例中,我已经决定要使用它生成一个XML DOM,然后要做的就是对XML进行转换(XSLT),然后我们将创建一个嵌套的消息网页.

PHP脚本

php脚本非常简单,它仅连接到数据库,调用sproc并循环结果集以构建XML DOM.记住,我们只调用一次数据库.

// i am using the resultset to build an XML DOM but you can do whatever you like with it !

header("Content-type: text/xml");

$conn = new mysqli("localhost", "foo_dbo", "pass", "foo_db", 3306);

// one non-recursive db call to get the message tree !

$result = $conn->query(sprintf("call message_hier(%d)", 1));

$xml = new DomDocument;

$xpath = new DOMXpath($xml);

$msgs = $xml->createElement("messages");

$xml->appendChild($msgs);

// loop and build the DOM

while($row = $result->fetch_assoc()){

$msg = $xml->createElement("message");

foreach($row as $col => $val) $msg->setAttribute($col, $val);

if(is_null($row["parent_msg_id"])){

$msgs->appendChild($msg);

}

else{

$qry = sprintf("//*[@msg_id = '%d']", $row["parent_msg_id"]);

$parent = $xpath->query($qry)->item(0);

if(!is_null($parent)) $parent->appendChild($msg);

}

}

$result->close();

$conn->close();

echo $xml->saveXML();

?>

XML输出

这是php脚本生成的XML.如果将此XML保存在文件中并在浏览器中打开,则可以展开和折叠级别.

现在,如果愿意,您可以放弃构建XML DOM并使用XSL呈现网页,或者可能只是循环结果集并直接呈现消息.我只是选择了这种方法,以使我的示例尽可能全面而有用.

MySQL脚本

这是一个完整的脚本,包括表,存储过程和测试数据.

drop table if exists messages;

create table messages

(

msg_id smallint unsigned not null auto_increment primary key,

msg varchar(255) not null,

parent_msg_id smallint unsigned null,

key (parent_msg_id)

)

engine = innodb;

insert into messages (msg, parent_msg_id) values

('msg 1',null),

('msg 1-1',1),

('msg 1-2',1),

('msg 1-2-1',3),

('msg 1-2-2',3),

('msg 1-2-2-1',5),

('msg 1-2-2-1-1',6),

('msg 1-2-2-1-2',6);

drop procedure if exists message_hier;

delimiter #

create procedure message_hier

(

in p_msg_id smallint unsigned

)

begin

declare v_done tinyint unsigned default(0);

declare v_dpth smallint unsigned default(0);

create temporary table hier(

parent_msg_id smallint unsigned,

msg_id smallint unsigned,

depth smallint unsigned

)engine = memory;

insert into hier select parent_msg_id, msg_id, v_dpth from messages where msg_id = p_msg_id;

/* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */

create temporary table tmp engine=memory select * from hier;

while not v_done do

if exists( select 1 from messages e inner join hier on e.parent_msg_id = hier.msg_id and hier.depth = v_dpth) then

insert into hier select e.parent_msg_id, e.msg_id, v_dpth + 1

from messages e inner join tmp on e.parent_msg_id = tmp.msg_id and tmp.depth = v_dpth;

set v_dpth = v_dpth + 1;

truncate table tmp;

insert into tmp select * from hier where depth = v_dpth;

else

set v_done = 1;

end if;

end while;

select

m.msg_id,

m.msg as emp_msg,

p.msg_id as parent_msg_id,

p.msg as parent_msg,

hier.depth

from

hier

inner join messages m on hier.msg_id = m.msg_id

left outer join messages p on hier.parent_msg_id = p.msg_id;

drop temporary table if exists hier;

drop temporary table if exists tmp;

end #

delimiter ;

-- call this sproc from your php

call message_hier(1);

可以在以下位置找到此答案的完整资源:http://pastie.org/1336407.正如您已经注意到的那样,我已经省略了XSLT,但是您可能不会采用XML路由,并且如果这样做,Web上会有很多示例.

希望对您有所帮助:)

编辑:

添加了更多数据,因此您拥有多个根消息(msg_ids 1,9,14).

truncate table messages;

insert into messages (msg, parent_msg_id) values

('msg 1',null), -- msg_id = 1

('msg 1-1',1),

('msg 1-2',1),

('msg 1-2-1',3),

('msg 1-2-2',3),

('msg 1-2-2-1',5),

('msg 1-2-2-1-1',6),

('msg 1-2-2-1-2',6),

('msg 2',null), -- msg_id = 9

('msg 2-1',9),

('msg 2-2',9),

('msg 2-3',9),

('msg 2-3-1',12),

('msg 3',null); -- msg_id = 14

现在,如果您只想获取特定于根节点的消息(起始消息),则可以调用原始存储过程,并传递所需根的起始msg_id.使用上面的新数据将是msg_ids 1,9,14.

call message_hier(1); -- returns all messages belonging to msg_id = 1

call message_hier(9); -- returns all messages belonging to msg_id = 9

call message_hier(14); -- returns all messages belonging to msg_id = 14

您可以传递任何您喜欢的msg_id,因此,如果我想要味精1-2-2-1以下的所有消息,则可以传递msg_id = 6:

call message_hier(6); -- returns all messages belonging to msg_id = 6

但是,如果您想要所有根的所有消息,则可以按如下方式调用我创建的这个新存储过程:

call message_hier_all(); -- returns all messages for all roots.

这样做的主要问题是,随着您的消息表的增长,它将返回大量数据,这就是为什么我专注于仅针对给定根节点或启动msg_id提取消息的更特定的sproc的原因.

我不会发布新的sproc代码,因为它与原始代码几乎相同,但是您可以在这里找到所有的修订:http://pastie.org/1339618

您需要进行的最后更改是在php脚本中,该脚本现在将按如下所示调用新的sproc:

//$result = $conn->query(sprintf("call message_hier(%d)", 1)); // recommended call

$result = $conn->query("call message_hier_all()"); // new sproc call

希望这可以帮助 :)

call message_hier_all();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值