?? 實現(xiàn)樹型結(jié)構(gòu).txt
字號:
實現(xiàn)樹型結(jié)構(gòu)(一)
--------------------------------------------------------------------------------
【小菁】 于 00-6-9 上午 09:57:57 加貼在 Joy ASP ↑:
實現(xiàn)樹型結(jié)構(gòu)(第一部分)
作者:ACE 最后更新:06/08/2000 類別:原創(chuàng)
先看一下示例,如果你感覺尚可,就繼續(xù)閱讀本文http://www.coolbel.com/ace/articles/test/msdn.asp。
1. 簡述
對于大家來說樹型結(jié)構(gòu)是很熟悉的一種模型。它的應(yīng)用十分廣泛,比如組織結(jié)構(gòu),物料清單,資料檔案管理,資產(chǎn)管理等等都是以樹型結(jié)構(gòu)為基礎(chǔ)。在現(xiàn)實生活中,有許多事物可以抽象為樹狀結(jié)構(gòu)。這種結(jié)構(gòu)可以簡化對某些事物的理解,使概念清晰。
2. 表結(jié)構(gòu)
樹型結(jié)構(gòu)的表結(jié)構(gòu)可以很簡單也可以很復(fù)雜。根據(jù)不同的需求,表結(jié)構(gòu)不是一成不變的,讀取數(shù)據(jù)的方法也不盡相同。
我們考慮一種最簡單的情況,看下面的示例:
Sample Table
Child Node Parent Node Title article
1 0 Program 0
2 1 Visual Basic 0
3 1 Power Builder 0
4 1 C++ Builder 0
5 2 ADO Control 1
..........
更直觀的表示:
Program
|-------Visual Basic
| |------------ADO Control
|-------Power Builder
|-------C++ Builder
這種結(jié)構(gòu)十分簡單,當(dāng)修改元素間的所屬關(guān)系時,你只需要修改 Parent Node 就可以了,比如把 ADO Control 作為 Program 的子項,只要將 ADO Control 所對應(yīng)的 Parent Node 改為1。由此,不難看出這種結(jié)構(gòu)簡單,易用。
3. 用存儲過程讀取數(shù)據(jù)
如何檢索數(shù)據(jù),或許是我們最關(guān)心的。對于用戶來說,在數(shù)據(jù)的表達(dá)上要易于理解。從上面的示例中,就可以看出:直觀的表示法比顯示數(shù)據(jù)存儲結(jié)構(gòu)更易于理解。
其中的關(guān)鍵在于如何得到元素之間的層次關(guān)系,有了層次關(guān)系,就能得到類似資源管理器那樣的界面。
在這里,我們用存儲過程完成該功能。在微軟的眾多有關(guān) SQL 的文檔中,有一段 SQL 代碼非常經(jīng)典,我們本著拿來主義的思想,將它修改一下,洋為中用。
CREATE PROC sp_ListFile(@Child_node int)
As
SET NOCOUNT ON
--declare var
DECLARE @lvl smallint --層次關(guān)系
DECLARE @c_ID int
DECLARE @article bit --是否為文章的標(biāo)志
DECLARE @title varchar(150) --標(biāo)題
--create temporary table
CREATE TABLE #stack (Child_node int,Lvl smallint)
--create target table
CREATE TABLE #FileList
(lvl smallint,
Child_node_ID int,
Article bit,
Title varchar(150) )
--initial
INSERT INTO #stack VALUES(@Child_node,0)
SELECT @Lvl = 0
--main loop
WHILE @Lvl > -1
BEGIN
IF EXISTS(SELECT * FROM #stack WHERE Lvl = @Lvl)
BEGIN
SELECT @Child_node = Child_node
FROM #stack
WHERE Lvl = @Lvl
SELECT @article = article,@title = title
FROM some_table
WHERE Child_node = @Child_node
INSERT INTO #FileList
VALUES(@Lvl,@Child_node, @article,@title)
DELETE FROM #stack
WHERE Lvl = @Lvl AND Child_node = @Child_node
INSERT INTO #stack
SELECT Child_node,@Lvl + 1
FROM some_table
WHERE Parent_node = @Child_node
IF @@ROWCOUNT > 0
SELECT @Lvl = @Lvl + 1
END
ELSE
SELECT @Lvl = @Lvl - 1
END
DELETE FROM #FileList
WHERE Lvl = 0
SELECT * FROM #FileList
輸出結(jié)果:
lvl Child_node Article Title
1 1 0 Program
2 2 0 Visual Basic
3 5 1 ADO Control
2 3 0 Power Builder
2 4 0 C++ Builder
上面的存儲過程可以有很多變形,比如按時間排序,指定檢索深度等等,有的需要對數(shù)據(jù)庫作相應(yīng)調(diào)整。
4. 調(diào)用存儲過程
調(diào)用存儲過程有多種形式,我們只討論如何調(diào)用上面的存儲過程
Dim cnn
Dim rs
Dim id
Set cnn = Server.CreateObject("ADODB.Connection")
Set rs = Server.CreateObject("ADODB.RecordSet")
cnn.Open "Provider=SQLOLEDB;.......................略
rs.Open "sp_listfile " & id,cnn
由于 Coolbel 不支持存儲過程,我把結(jié)果集存為 XML 格式,以便于演示。
實現(xiàn)樹型結(jié)構(gòu)(二)
--------------------------------------------------------------------------------
【小菁】 于 00-6-9 上午 10:00:27 加貼在 Joy ASP ↑:
實現(xiàn)樹型結(jié)構(gòu)(第二部分)
作者:ACE 最后更新:06/08/2000 類別:原創(chuàng)
在上一部分,我們討論了如何讀取數(shù)據(jù),并得到了表示層次關(guān)系的結(jié)果集。在這一部分,我們來看如何用腳本語言實現(xiàn)類似 MSDN 的界面。
可以在服務(wù)器端也可以在客戶端完成這樣的功能,這就要看需要了。在服務(wù)器端完成需要占用服務(wù)器的處理時間及相關(guān)資源,在客戶端完成需要瀏覽器支持腳本語言(一般是 JavaScript),并要下載執(zhí)行腳本。
在我們的示例里采用客戶端執(zhí)行腳本的方法。
1. 將數(shù)據(jù)發(fā)送到瀏覽器
看下列代碼:
Dim GetRSString
Dim cnn
Dim rs
Dim l_ID
l_ID = "1" '表示根節(jié)點
Set cnn = Server.CreateObject("ADODB.Connection")
Set rs = Server.CreateObject("ADODB.RecordSet")
cnn.Open "Provider=SQLOLEDB;.......................略
rs.Open "sp_listfile " & l_ID,cnn
GetRSString = rs.GetString(2,,"?quot;","~~") 'adClipString
rs.Close
Set rs = Nothing
cnn.Close
Set cnn = Nothing
Response.Write "<FORM id='rs' name='rs'>" &_
"<INPUT type='hidden' id='rsCache' name='rsCache' value='" & GetRSString & "'></FORM>" &_
"<SCRIPT language=JavaScript src='Listfile.js'></SCRIPT>" &_
"<Script language=Javascript>LoadRecords(" + l_ID + ");</Script>"
在上面的代碼中,用 GetString 的方法得到了以 ?quot;和~~ 分隔的字符串,并用隱藏表單進(jìn)行存儲。 Listfile.js 里的腳本實現(xiàn)了我們想要得功能,LoadRecords 是其中的一個函數(shù)。
2. Listfile.js 中的腳本
這是全部代碼:
function ToggleDisplay(oButton, oItems)
{
if ((oItems.style.display == "") || (oItems.style.display == "none")) {
oItems.style.display = "block";
oButton.src = book_open.src;
} else {
oItems.style.display = "none";
oButton.src = book_close.src;
}
}
function LoadRecords(l_ID) {
var strRecords=document.all("rsCache").value;
var arrRecords=strRecords.split("~~");
var arrFields;
var Current_level;
var Current_ID;
var strTemp;
var strList;
var Prior_ID;
var Prior_level=-1;
var i;
var j;
Prior_ID=l_ID;
strList = "<TABLE><TR><TD height=300 valign=top class=Newscontents><!--" + l_ID + "-->";
for (i=0;i<arrRecords.length;i++)
{
arrFields=arrRecords[i].split("?quot;");
Current_level = arrFields[0];
Current_ID = arrFields[1];
if (arrFields[2] == 0)
{
strTemp = "<DIV><IMG SRC='images/plus.gif' ID='i_" + Current_ID +
"' onclick='ToggleDisplay(i_" + Current_ID + ",f_" +
Current_ID + "_d);' width=31 height=15 style='position:relative;left:" +
(Current_level*17) + ";top:3;cursor:hand;'> <A ID='f_" + Current_ID +
"' style='position:relative;left:" + (Current_level*17) +
";cursor:hand;' onclick='ToggleDisplay(i_" + Current_ID + ",f_" +
Current_ID + "_d);'>" + arrFields[3] + "</A></DIV><DIV ID='f_" +
Current_ID + "_d' style='display: none;'><!--" + Current_ID + "--></DIV>";
if (Current_level > Prior_level)
{
strTemp += "<!--LEVEL" + Current_level + "-->";
strList = strList.replace("<!--" + Prior_ID + "-->",strTemp);
}
else
{
if (Current_level == Prior_level)
{
strTemp += "<!--LEVEL" + Current_level + "-->";
strList = strList.replace("<!--LEVEL" + Current_level + "-->",strTemp );
}
else
{
for (j=parseInt(Current_level)+1;j<=Prior_level;j++)
{
strList = strList.replace("<!--LEVEL" + i + "-->","")
}
strTemp += "<!--LEVEL" + Current_level + "-->";
strList = strList.replace("<!--LEVEL" + Current_level + "-->",strTemp );
}
}
}
else
{
strTemp = "<DIV><IMG SRC='images/message.gif' width=11 height=14 style='position:relative;left:" +
(Current_level*17+20) + ";top:2;cursor:hand;'> ";
strTemp += "<A ID='f_" + Current_ID + "' HREF='page.asp?article=" + arrFields[3] +
"' TARGET=MAIN style='position:relative;left:" + (Current_level*17 +16) +
";cursor:hand;'>" + arrFields[3] + "</A></DIV><!--LEVEL" + Current_level + "-->";
if (Current_level > Prior_level)
strList = strList.replace("<!--" + Prior_ID + "-->",strTemp);
else
strList = strList.replace("<!--LEVEL" + Current_level + "-->",strTemp);
}
Prior_ID = Current_ID;
Prior_level = Current_level;
}
strList += "</TD></TR><TR><TD height=10><img style='display:none;' " +
"src='images/plus.gif' id=book_close><img style='display:none;' " +
"src='images/minus.gif' id=book_open> </TD></TR></TABLE>";
document.write(strList);
}
終于寫完了,大家自己看吧,如果你有更好的主意別望了告訴我。
http://www.coolbel.com/ace/
--------------------------------------------------------------------------------
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -