XML論壇
查看并下載本文章的源代碼(需要 MSXML 3.0 [英文])。
您知道 Microsoft Internet Explorer 5.5 具有編輯 HTML 的內置支持嗎?我一直想有一個基于 XML 的好工具來做聯機討論,和新聞組差不多,但是結構性更強,好讓我能輕松地添加新的功能。
我一直希望這類工具中能有這些功能:
輕松維護 - 能刪掉我自己張貼的內容,或者指定一些管理員,讓他們可以輕松刪掉貼子。完整地復制這些論壇的部署和管理。
用戶分級 - 可以根據有用程度對最終用戶的張貼內容進行分級。這樣,其他用戶就可以輕松地找到有價值的內容。
速度 - 相對于 Intranet 里頭腦風暴式的討論,新聞組總是太慢。我想要一個又小又輕便的解決方案,可以讓小組用來進行集體聯機討論,而且馬上就能看見彼此張貼的內容。
全面控制 UI - 這里,XSL 是顯然的解決方案。
多信息文本支持 - 純文本形式的 Web 論壇太多了。
唯一的問題是如何做好多信息文本編輯。我的朋友 Jonathan Marsh 開發了一個棒極了的原型。一旦 IE 5.5 給我解決了多信息文本編輯的問題,我就能根據朋友的原型把下面這些放在一起:

圖 1:原型 XML 討論列表
每個頂級討論線索是一個可以展開和折疊的層次結構。它使用 Cookie 來記憶您在哪里。這樣,您回到討論時,還會回到同樣的位置。
分級
您也可以看到用戶分級功能;在上面的圖里,選定的張貼內容也是最受歡迎的張貼。最多可以分 4 級。要對消息進行分級,用戶只需要在標題 RATE THIS MESSAGE 旁邊單擊鏈接,網頁會將分級信息發布到服務器,并顯示新的平均值。它還可以做很多事情。最棒的是:它非常容易使用,而且速度足夠快,這樣用戶才會真正去用。
編輯
單擊 REPLY 的時候,詳細信息框架將進入 HTML 多信息文本編輯器,如下圖所示:

圖 2:多信息文本編輯器接口
實際上,IE 5.5 的內置編輯器還有很多這里沒有提到的功能。使用工具欄、彈出式菜單和您擁有的其他控件,您可以隨心所欲地創建內容更加豐富的用戶界面。其實,這段代碼是從另一篇 MSDN 文章上獲得的:定位和編輯(英文)。
開始
和所有基于 XML 的 Web 服務一樣,首先要為包含消息線索索引的論壇設計一個簡單的架構。在這里,我決定使用傳統的文檔類型定義 (DTD):
《!ELEMENT discussion (title, threads*)》
《!ELEMENT title (#PCDATA)》
《!ELEMENT threads (message*)》
〈!ELEMENT message (subject, body, author, posted, rating, replies)〉
〈!ELEMENT replies (message*)〉
《!ATTLIST message id CDATA #REQUIRED〉
〈!ELEMENT subject (#PCDATA)》
〈!ELEMENT body EMPTY》
〈!ATTLIST body src CDATA #REQUIRED〉
〈!ELEMENT subject (#PCDATA)〉
〈!ELEMENT author EMPTY〉
〈!ATTLIST author name CDATA #IMPLIED email CDATA #IMPLIED〉
〈!ELEMENT rating EMPTY〉
〈!ATTLIST rating users CDATA #IMPLIED average CDATA #IMPLIED〉
這段代碼會捕獲線索化討論的層次結構,在這個結構中,消息包含了答復,答復又包含了更多的消息,等等。每個張貼內容的主體都存儲在獨立的 XHTML 文件中,而 元素的 src 屬性確定了文件的位置。
這個索引存儲在論壇目錄里名為 index.xml 的文件中。您將此目錄作為一個稱作 root 的 URL 參數提供給 discuss.asp 網頁。例如,上面的網頁是使用以下的 URL 顯示的:
http://localhost/xdiscuss/discuss.asp?root=userdata
這樣,同一個論壇 Web 應用程序可以用來維護站點上任意數量的獨立論壇。例如,我有一個論壇討論這個應用程序本身(就是上面那個),另一個則用來討論我正在開發的產品的新功能。
管理
在服務器的論壇目錄中,還有一個名為 admin.xml 的文件,其中包含了允許刪除張貼內容的用戶名稱和電子郵件別名:
〈admin〉
〈user〉
〈name〉clovett〈/name〉
〈permission〉all〈/permission〉
〈/user〉
〈user〉
〈name〉jmarsh〈/name〉
〈permission〉all〈/permission〉
〈/user〉
〈/admin〉
現在,唯一的一個權限是“All”。很顯然,可以用很多方法來擴展這個列表。如果能用一個用戶界面來維護這個管理消息,那也是個好辦法。
源代碼
您下載源代碼時,將看到以下文件:
文件名 說明
Common.asp 用于管理共享資源的一些通用 ASP 函數
Cookies.js 標準客戶端 Cookie 管理代碼
Defaults.xsl 顯示 XML 的缺省樣式表(僅用于調試)
Delete.asp ASP 腳本,先檢查管理員權限,然后刪除消息
Detail.css 用于消息詳細資料框架的層疊樣式表
Detail.xsl 用于建立詳細信息框架 UI 的 XSL 轉換器
Discuss.asp 應用程序的主要入口點;取得一個稱作“Root”的 URL 參數,指向位于同一服務器的論壇目錄
Discuss.css 共享 CSS,用于控制論壇的總體外觀和風格
Error.xsl 用于格式化錯誤信息的小樣式表
Expand.js 客戶端 JScript 代碼,用于管理大綱視圖的展開和折疊
Global.asa 管理存儲在 ASP 應用程序范圍內的共享對象
Left.html 左框架,目前僅包含調試鏈接
Message.asp 用于生成選定消息的詳細信息視圖
Outline.asp ASP 腳本,用于生成大綱視圖
Outline.css CSS,用于控制大綱視圖的外觀
Post.asp ASP 腳本,用于管理新消息的張貼
Relevance-filter.xsl XSL 轉換器,用于過濾論壇索引,僅返回按某種方式分級的消息
Reply.asp ASP 腳本,建立選定消息的答復用戶界面
Reply.js 用于管理答復的一些客戶端 Jscript® 代碼
Reply.xsl 客戶端 XSL 轉換器,用于建立答復框架的用戶界面
Unload.asp ASP 腳本,從服務器下載所有共享應用程序范圍內的對象
User-rating.asp ASP 腳本,用于處理每個用戶的分級
View-data.asp ASP 腳本,返回內存中給定論壇的 XML
Xmlupdates.asp 共享 ASP 腳本,post.asp 用它來實現一些簡單 XML 更新程序合并
上面的 XSL 轉換器是 http://www.w3.org/1999/XSL/Transform(英文)轉換器,同時使用了由 MSXML 3.0 提供的 msxsl:script 擴展。
設計

圖 3:總體消息流
上圖說明了本應用程序的總體消息流:index.xml 文件高速緩存在 ASP 應用程序范圍中,以獲得更好的性能,該文件還會不時保存到磁盤中,以免丟失所作的更改。這些由共享 ASP 腳本 common.asp 以及 global.asa 和 unload.asp 共同管理。
頂級大綱框架由 outline.asp 生成。outline.asp 運行一個服務器端 XSL 轉換器以過濾出用戶想看的消息(基于分級進行)。然后,它將篩選后的索引內容發送至客戶端,內容中附加的 outline.xsl 轉換器將執行客戶端 XSL 轉換,以生成 DHTML 用戶界面。
當您從大綱中選擇消息時,底部的詳細消息框架將顯示 message.asp 的運行結果。message.asp 從指定的論壇中找到指定消息并返回消息的詳細信息,同時通過附加的 detail.xsl 轉換器建立詳細信息 DHTML 用戶接口。
在詳細信息視圖中,您可以刪除調用 delete.asp 的消息,并檢查您是否具有管理員權限,或者答復這個消息。Reply.asp 建立模板消息,并使用 reply.xsl 轉換器來顯示多信息文本編輯器。從編輯器視圖上,您可以將答復張貼到 post.asp 腳本,它將有關您消息的信息添加到共享索引,并將消息主體保存到服務器上的單獨文件中。
一些技巧
從包含的源代碼數目中,您可以看出這并不僅僅是一個小練習。它開始通過服務器上的 JScript ASP 代碼、十分復雜的 XML 轉換器和技巧性的 DHTML 客戶端 UI 代碼來拓寬維護能力方面的限制。其中技巧性最強的一些是:
縮進 - 使用稱作 padding-left 的 CSS 樣式生成大綱視圖的縮進。根據 〈message〉 元素的嵌套深度計算該樣式的值。此計算在 outline.xsl 轉換器中執行,使用以下 XPath 表達式:
padding-left:〈xsl:value-of select="count(ancestor::message)"/〉em;
本地時間 - 服務器在 post.asp 中生成消息的時間戳記,并將其保存為通用協調時間,通用協調時間是指定日期與 1970 年 1 月 1 日午夜之間的差(按毫秒計算)。使用 JScript Date() 對象的 getUTC* 方法完成這一功能。在客戶端,多種 XSL 轉換器使用 Date 對象的 getTimezoneOffset 方法將時間調回本地時間,并使用 toLocaleString 顯示為本地化字符串。這些工作由 XSL/T 轉換器中的 msxsl:script 塊完成。
多論壇支持 - 一個論壇應用程序,可用于參加同一服務器上的多個論壇。您可以使用“Root”URL 參數選擇論壇,每個論壇的 index.xml 文件被高速緩存在應用程序范圍中。為了管理所有論壇,使用了另一個動態生成的、自由線索的 XML 文檔對象來維護所有載入論壇的主控列表。這樣,當在 global.asa 中引發 Application_OnEnd 事件時,commmon.asp 中的 Unload() 方法可以找到所有載入的論壇,并將其全部卸載。
展開/折疊 - 大綱視圖實際上是一個只有一行的表。要實現層次結構的展開/折疊,HTML 中需要包含足夠的信息,以便 DHTML 腳本代碼指出各行之間的父子層次結構。它的實現方式是:通過 outline.xsl 轉換器,在每個 〈TR〉 元素上生成 id、thread、parent 和 depth expando 屬性。這些值按 XPath 父子關系來生成,非常巧妙。在 expand.js 中將使用這一 HTML 信息實現展開/折疊功能。當前的展開狀態也被維護并保存在 Cookie 中,以便您回來時它還能保持原來的展開狀態。通過維護當前展開消息的消息 ID 列表可以實現這一功能。
下一步是什么?
這時,要添加下面的新功能將會相當容易:
采用新的 .NET Framework(英文)和高度類型化語言(例如 C#),上述程序的性能和可維護性都將獲得大幅度提高。
賦予管理員重新組織張貼內容的能力(甚至可能使用 DHTML 拖放功能),這有助于將新聞組的隨意閑聊轉化為有價值而又便于瀏覽的知識庫。
創建更多的復雜用戶權限,允許用戶刪除自己張貼的內容。也許可以通過 NT 身份驗證來驗證用戶的身份。
輕松配置不同的數據視圖。現在我們具有過濾的大綱視圖和消息詳細信息視圖,但是其他類型的過濾和排序也很有趣,例如,摘要視圖可以顯示整個線索中的所有張貼內容。
能夠選擇字體、顏色、字號,等等。這將很容易掛鉤。
通過更多的復雜選項增強用戶分級功能和保護用戶不要重復分級同一個張貼內容。
按照與我以前寫的 ListEditor:有用的 XML Web 服務相同的路線,自動輪詢更新以獲得更多協作功能。
您知道 Microsoft Internet Explorer 5.5 具有編輯 HTML 的內置支持嗎?我一直想有一個基于 XML 的好工具來做聯機討論,和新聞組差不多,但是結構性更強,好讓我能輕松地添加新的功能。
我一直希望這類工具中能有這些功能:
輕松維護 - 能刪掉我自己張貼的內容,或者指定一些管理員,讓他們可以輕松刪掉貼子。完整地復制這些論壇的部署和管理。
用戶分級 - 可以根據有用程度對最終用戶的張貼內容進行分級。這樣,其他用戶就可以輕松地找到有價值的內容。
速度 - 相對于 Intranet 里頭腦風暴式的討論,新聞組總是太慢。我想要一個又小又輕便的解決方案,可以讓小組用來進行集體聯機討論,而且馬上就能看見彼此張貼的內容。
全面控制 UI - 這里,XSL 是顯然的解決方案。
多信息文本支持 - 純文本形式的 Web 論壇太多了。
唯一的問題是如何做好多信息文本編輯。我的朋友 Jonathan Marsh 開發了一個棒極了的原型。一旦 IE 5.5 給我解決了多信息文本編輯的問題,我就能根據朋友的原型把下面這些放在一起:

圖 1:原型 XML 討論列表
每個頂級討論線索是一個可以展開和折疊的層次結構。它使用 Cookie 來記憶您在哪里。這樣,您回到討論時,還會回到同樣的位置。
分級
您也可以看到用戶分級功能;在上面的圖里,選定的張貼內容也是最受歡迎的張貼。最多可以分 4 級。要對消息進行分級,用戶只需要在標題 RATE THIS MESSAGE 旁邊單擊鏈接,網頁會將分級信息發布到服務器,并顯示新的平均值。它還可以做很多事情。最棒的是:它非常容易使用,而且速度足夠快,這樣用戶才會真正去用。
編輯
單擊 REPLY 的時候,詳細信息框架將進入 HTML 多信息文本編輯器,如下圖所示:

圖 2:多信息文本編輯器接口
實際上,IE 5.5 的內置編輯器還有很多這里沒有提到的功能。使用工具欄、彈出式菜單和您擁有的其他控件,您可以隨心所欲地創建內容更加豐富的用戶界面。其實,這段代碼是從另一篇 MSDN 文章上獲得的:定位和編輯(英文)。
開始
和所有基于 XML 的 Web 服務一樣,首先要為包含消息線索索引的論壇設計一個簡單的架構。在這里,我決定使用傳統的文檔類型定義 (DTD):
《!ELEMENT discussion (title, threads*)》
《!ELEMENT title (#PCDATA)》
《!ELEMENT threads (message*)》
〈!ELEMENT message (subject, body, author, posted, rating, replies)〉
〈!ELEMENT replies (message*)〉
《!ATTLIST message id CDATA #REQUIRED〉
〈!ELEMENT subject (#PCDATA)》
〈!ELEMENT body EMPTY》
〈!ATTLIST body src CDATA #REQUIRED〉
〈!ELEMENT subject (#PCDATA)〉
〈!ELEMENT author EMPTY〉
〈!ATTLIST author name CDATA #IMPLIED email CDATA #IMPLIED〉
〈!ELEMENT rating EMPTY〉
〈!ATTLIST rating users CDATA #IMPLIED average CDATA #IMPLIED〉
這段代碼會捕獲線索化討論的層次結構,在這個結構中,消息包含了答復,答復又包含了更多的消息,等等。每個張貼內容的主體都存儲在獨立的 XHTML 文件中,而 元素的 src 屬性確定了文件的位置。
這個索引存儲在論壇目錄里名為 index.xml 的文件中。您將此目錄作為一個稱作 root 的 URL 參數提供給 discuss.asp 網頁。例如,上面的網頁是使用以下的 URL 顯示的:
http://localhost/xdiscuss/discuss.asp?root=userdata
這樣,同一個論壇 Web 應用程序可以用來維護站點上任意數量的獨立論壇。例如,我有一個論壇討論這個應用程序本身(就是上面那個),另一個則用來討論我正在開發的產品的新功能。
管理
在服務器的論壇目錄中,還有一個名為 admin.xml 的文件,其中包含了允許刪除張貼內容的用戶名稱和電子郵件別名:
〈admin〉
〈user〉
〈name〉clovett〈/name〉
〈permission〉all〈/permission〉
〈/user〉
〈user〉
〈name〉jmarsh〈/name〉
〈permission〉all〈/permission〉
〈/user〉
〈/admin〉
現在,唯一的一個權限是“All”。很顯然,可以用很多方法來擴展這個列表。如果能用一個用戶界面來維護這個管理消息,那也是個好辦法。
源代碼
您下載源代碼時,將看到以下文件:
文件名 說明
Common.asp 用于管理共享資源的一些通用 ASP 函數
Cookies.js 標準客戶端 Cookie 管理代碼
Defaults.xsl 顯示 XML 的缺省樣式表(僅用于調試)
Delete.asp ASP 腳本,先檢查管理員權限,然后刪除消息
Detail.css 用于消息詳細資料框架的層疊樣式表
Detail.xsl 用于建立詳細信息框架 UI 的 XSL 轉換器
Discuss.asp 應用程序的主要入口點;取得一個稱作“Root”的 URL 參數,指向位于同一服務器的論壇目錄
Discuss.css 共享 CSS,用于控制論壇的總體外觀和風格
Error.xsl 用于格式化錯誤信息的小樣式表
Expand.js 客戶端 JScript 代碼,用于管理大綱視圖的展開和折疊
Global.asa 管理存儲在 ASP 應用程序范圍內的共享對象
Left.html 左框架,目前僅包含調試鏈接
Message.asp 用于生成選定消息的詳細信息視圖
Outline.asp ASP 腳本,用于生成大綱視圖
Outline.css CSS,用于控制大綱視圖的外觀
Post.asp ASP 腳本,用于管理新消息的張貼
Relevance-filter.xsl XSL 轉換器,用于過濾論壇索引,僅返回按某種方式分級的消息
Reply.asp ASP 腳本,建立選定消息的答復用戶界面
Reply.js 用于管理答復的一些客戶端 Jscript® 代碼
Reply.xsl 客戶端 XSL 轉換器,用于建立答復框架的用戶界面
Unload.asp ASP 腳本,從服務器下載所有共享應用程序范圍內的對象
User-rating.asp ASP 腳本,用于處理每個用戶的分級
View-data.asp ASP 腳本,返回內存中給定論壇的 XML
Xmlupdates.asp 共享 ASP 腳本,post.asp 用它來實現一些簡單 XML 更新程序合并
上面的 XSL 轉換器是 http://www.w3.org/1999/XSL/Transform(英文)轉換器,同時使用了由 MSXML 3.0 提供的 msxsl:script 擴展。
設計

圖 3:總體消息流
上圖說明了本應用程序的總體消息流:index.xml 文件高速緩存在 ASP 應用程序范圍中,以獲得更好的性能,該文件還會不時保存到磁盤中,以免丟失所作的更改。這些由共享 ASP 腳本 common.asp 以及 global.asa 和 unload.asp 共同管理。
頂級大綱框架由 outline.asp 生成。outline.asp 運行一個服務器端 XSL 轉換器以過濾出用戶想看的消息(基于分級進行)。然后,它將篩選后的索引內容發送至客戶端,內容中附加的 outline.xsl 轉換器將執行客戶端 XSL 轉換,以生成 DHTML 用戶界面。
當您從大綱中選擇消息時,底部的詳細消息框架將顯示 message.asp 的運行結果。message.asp 從指定的論壇中找到指定消息并返回消息的詳細信息,同時通過附加的 detail.xsl 轉換器建立詳細信息 DHTML 用戶接口。
在詳細信息視圖中,您可以刪除調用 delete.asp 的消息,并檢查您是否具有管理員權限,或者答復這個消息。Reply.asp 建立模板消息,并使用 reply.xsl 轉換器來顯示多信息文本編輯器。從編輯器視圖上,您可以將答復張貼到 post.asp 腳本,它將有關您消息的信息添加到共享索引,并將消息主體保存到服務器上的單獨文件中。
一些技巧
從包含的源代碼數目中,您可以看出這并不僅僅是一個小練習。它開始通過服務器上的 JScript ASP 代碼、十分復雜的 XML 轉換器和技巧性的 DHTML 客戶端 UI 代碼來拓寬維護能力方面的限制。其中技巧性最強的一些是:
縮進 - 使用稱作 padding-left 的 CSS 樣式生成大綱視圖的縮進。根據 〈message〉 元素的嵌套深度計算該樣式的值。此計算在 outline.xsl 轉換器中執行,使用以下 XPath 表達式:
padding-left:〈xsl:value-of select="count(ancestor::message)"/〉em;
本地時間 - 服務器在 post.asp 中生成消息的時間戳記,并將其保存為通用協調時間,通用協調時間是指定日期與 1970 年 1 月 1 日午夜之間的差(按毫秒計算)。使用 JScript Date() 對象的 getUTC* 方法完成這一功能。在客戶端,多種 XSL 轉換器使用 Date 對象的 getTimezoneOffset 方法將時間調回本地時間,并使用 toLocaleString 顯示為本地化字符串。這些工作由 XSL/T 轉換器中的 msxsl:script 塊完成。
多論壇支持 - 一個論壇應用程序,可用于參加同一服務器上的多個論壇。您可以使用“Root”URL 參數選擇論壇,每個論壇的 index.xml 文件被高速緩存在應用程序范圍中。為了管理所有論壇,使用了另一個動態生成的、自由線索的 XML 文檔對象來維護所有載入論壇的主控列表。這樣,當在 global.asa 中引發 Application_OnEnd 事件時,commmon.asp 中的 Unload() 方法可以找到所有載入的論壇,并將其全部卸載。
展開/折疊 - 大綱視圖實際上是一個只有一行的表。要實現層次結構的展開/折疊,HTML 中需要包含足夠的信息,以便 DHTML 腳本代碼指出各行之間的父子層次結構。它的實現方式是:通過 outline.xsl 轉換器,在每個 〈TR〉 元素上生成 id、thread、parent 和 depth expando 屬性。這些值按 XPath 父子關系來生成,非常巧妙。在 expand.js 中將使用這一 HTML 信息實現展開/折疊功能。當前的展開狀態也被維護并保存在 Cookie 中,以便您回來時它還能保持原來的展開狀態。通過維護當前展開消息的消息 ID 列表可以實現這一功能。
下一步是什么?
這時,要添加下面的新功能將會相當容易:
采用新的 .NET Framework(英文)和高度類型化語言(例如 C#),上述程序的性能和可維護性都將獲得大幅度提高。
賦予管理員重新組織張貼內容的能力(甚至可能使用 DHTML 拖放功能),這有助于將新聞組的隨意閑聊轉化為有價值而又便于瀏覽的知識庫。
創建更多的復雜用戶權限,允許用戶刪除自己張貼的內容。也許可以通過 NT 身份驗證來驗證用戶的身份。
輕松配置不同的數據視圖。現在我們具有過濾的大綱視圖和消息詳細信息視圖,但是其他類型的過濾和排序也很有趣,例如,摘要視圖可以顯示整個線索中的所有張貼內容。
能夠選擇字體、顏色、字號,等等。這將很容易掛鉤。
通過更多的復雜選項增強用戶分級功能和保護用戶不要重復分級同一個張貼內容。
按照與我以前寫的 ListEditor:有用的 XML Web 服務相同的路線,自動輪詢更新以獲得更多協作功能。