XML 论坛

网络整理 - 07-26
查看并下载本文章的源代码(需要 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 显示的:

?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 客户端 Js cript 代码,用于管理大纲视图的展开和折叠
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 用于管理答复的一些客户端 Js cript® 代码
Reply.xsl 客户端 XSL 转换器,用于建立答复框架的用户界面
Unload.asp ASP 脚本,从服务器下载所有共享应用程序范围内的对象
User-rating.asp ASP 脚本,用于处理每个用户的分级
View-data.asp ASP 脚本,返回内存中给定论坛的 XML
Xmlupdates.asp 共享 ASP 脚本,post.asp 用它来实现一些简单 XML 更新程序合并  


上面的 XSL 转换器是 (英文)转换器,同时使用了由 MSXML 3.0 提供的 msxsl:s cript 扩展。

设计



图 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 脚本,它将有关您消息的信息添加到共享索引,并将消息主体保存到服务器上的单独文件中。

一些技巧
从包含的源代码数目中,您可以看出这并不仅仅是一个小练习。它开始通过服务器上的 Js cript 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 日午夜之间的差(按毫秒计算)。使用 Js cript Date() 对象的 getUTC* 方法完成这一功能。在客户端,多种 XSL 转换器使用 Date 对象的 getTimezoneOffset 方法将时间调回本地时间,并使用 toLocaleString 显示为本地化字符串。这些工作由 XSL/T 转换器中的 msxsl:s cript 块完成。

多论坛支持 - 一个论坛应用程序,可用于参加同一服务器上的多个论坛。您可以使用“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 服务相同的路线,自动轮询更新以获得更多协作功能。