站内搜索: 请输入搜索关键词

当前页面: 开发资料首页J2EE 专题将 TOC 从 XML 带到 DHTML

将 TOC 从 XML 带到 DHTML

摘要:
对 Web 开发人员而言,通过使用带有“有意义的”标记数据元素的 XML,可实现使信息更有携带性与弹性。由于在 Internet Explorer 5 中增强的 XSL 支持,使得在浏览器中显示 XML 数据更加容易。

我们在 Web Workshop 中使用 XML 存储 TOC 信息已经有一段时间了,通过 XSL 样式表可以将该信息转换为 HTML。样式表还“写下”链接到一个 CSS 和 JScript 文件,因此我们一次就可将 XML 转换到 DHTML。通过修改单一的 XSL 样式表,XML 存储的数据即可轻松改变所有 TOC 的输出格式。

让我们来依次看一下这四种文件 — XML、XSL、JScript 及 CSS。

在 XML 存储 TOC
对于本示例,我们已经创建了一个与 web 开发有关的文章或“主题”的列表。每个 TOPIC 元素都有一个说明性的 TITLE 和 URL。主题按 TOPICS 元素内的 TYPE 进行分组。注意第三个 TOPICS 元素自身包含 TOPICS 元素。webdev.xml 文件顶端的<?xml:stylesheet type="text/xsl" href="list.xsl"?>处理指令会告诉 Internet Explorer 5 当该 XML 文件直接在浏览器中打开时,按照此样式表实施 XML。(我们将在栏目尾端讨论如何在服务器上以 ASP 实现此项操作。)

以下是 XML 数据:

列表 1:webdev.xml
<?xml version="1.0"?>
<?xml:stylesheet type="text/xsl" href="list.xsl"?>





Objects
/workshop/author/dhtml/reference/objects.asp


Properties
/workshop/author/dhtml/reference/properties.asp


Methods
/workshop/author/dhtml/reference/methods.asp


Events
/workshop/author/dhtml/reference/events.asp


Collections
/workshop/author/dhtml/reference/collections.asp





Attributes
/workshop/author/css/reference/attributes.asp


Length units
/workshop/author/css/reference/lengthunits.asp


Color table
/workshop/author/dhtml/reference/colors/colors.asp







Developer's guide
/xml/XMLGuide/default.asp


Objects
/xml/reference/scriptref/XMLDOM_Objects.asp





Developer's guide
/xml/XSLGuide/default.asp


Elements
/xml/reference/xsl/XSLElements.asp


Methods
/xml/reference/xsl/xslmethods.asp


Pattern syntax
/xml/reference/xsl/XSLPatternSyntax.asp







使用一个 XSL 样式表将 XML 转换为 HTML
虽然我们可以在代码中直接对 XML 进行操作,但 XSL 让我们使用陈述的方法,将 XML 转换到显示输出(在此例中为 HTML),这种方法几乎不需要代码(和劳神)。XSL 使您不必编写很多涉及分支的代码 —如果您在 XML 文件中嵌套了复杂的层次,则此效果会特别明显。在此例中,我们可以使用任意数目的 TOPICS 层次;XSL 均可很好地对此进行处理。

让我们来看一下 XSL 代码。

列表 2:list.xsl




<head>
List <xsl:value-of select="TOPICLIST/@TYPE" />
<link> REL="stylesheet" TYPE="text/css" HREF="list.css" />
<script TYPE="text/javascript" LANGUAGE="javascript" SRC="list.js"></script>
</head>
<body>


List




</body>










    • http://msdn.microsoft.com












  • 如您所见,我们使用了众多 HTML 标记符和少量的 "xsl:" 元素。我们明确告诉处理器这是一个 XSL 文件并作为 XSL 文件的开始,然后声明两个 xsl:template 元素块,

    转换根目录
    第一个块 通知处理器从由斜杠指示的 XML 文件的根目录开始转换。在本块中,我们要做两件事:“写下”我们的 HTML 输入的结构和类属元素,并有条件地挂接到任何其他模板块中。我们采用 TOPICLIST 元素 TYPE 属性的值 — Web 开发参考 — 并将其放入 和 <H1> HTML 元素中;我们还挂接脚本 (list.js) 和样式表 (list.css) 文件,它们将提供对 DHTML 外观和行为的处理。我们使用脚本文件中的两个函数,在顶端绘制了一些供用户显示或隐藏所有 TOC 节点的按钮,在底端添加了另一个按钮,来查看警报框中的 HTML 源文件。<br /><br />第一个块中最有趣的元素是 <xsl:apply-templates select="TOPICLIST/TOPICS" />。它通知处理器转换 XML 文档的所有 TOPICS 节点,这些节点是根目录 TOPICLIST 节点的子节点。如果您查看一下上面的 XML 文件,您会注意到它是由 TYPE "DHTML"、"CSS" 和 "XML" 的 TOPICS 节点组成的。在这里,XSL 处理器将从此第一个块开始分支,并在样式表中搜索另一个 xsl:template 块,它与我们的 select="TOPICLIST/TOPICS" 属性相匹配。正如您可能猜到的,这就是我们的第二个块。<br /><br />转换 TOPICLIST<br />第二个模板块 <xsl:template match="TOPICS"> 才是乐趣的开始。我们的三个节点的 TOPICS 中的每一个的上下文从第一个块传递到本块,并在此得以处理。首先,我们打开一个 HTML 列表项元素 (LI),并赋予其 "clsHasKids" 的 CLASS 属性,我们后面将在 DHTML 中用到它;然后,我们输出正在处理的 TOPICS 节点的 TYPE,这是通过 <xsl:value-of select="@TYPE" /> 处理的。为获取 XSL 中的节点值,使用了 xsl:value-of 元素。如果获取了某一属性的值,则属性名的开始处将会加上一个 "@"。<br /><br />接下来,我们打开一个 HTML 无序列表 (<UL>),它将包括当前 TOPICS 元素的所有子元素。使用 xsl:for-each 循环结构,它也可以将每个 TOPIC 子元素上下文更改为该元素(此时为 TOPIC),我们可以创建一个 <LI> 元素,并将其 TITLE 包在一个 A 链接中输出,该链接的 HREF 属性被设为 URL 元素的值。如果要以 XSL 将某一属性动态添加到一个 HTML 输出元素中,我们可以使用 xsl:attribute,其 name 属性设为我们希望创建的 HTML 属性;正如:<xsl:attribute name="HREF">。我们用服务器名称(http://msdn.microsoft.com)以及 TOPIC URL, <xsl:value-of select="URL" /> 植入 HREF 值。<br /><br />好了,我们已经写出了顶端组中的所有链接,但我们还没有涉及 TOPICS 的子 TOPICS — 主题的嵌套列表。这是一个 XSL 真正表现出色的区域,它可以使用一条语句处理所有的递归!关闭进入第二个块先开始处理 TOPICS 元素时打开的容器 <UL> 及其父级 <LI> 之前, 我们要声明 <xsl:if test="TOPICS"><xsl:apply-templates /></xsl:if>。通过使用将上下文更改为我们正在测试的元素的 xsl:if 条件语句,我们可以探询该树是否存在一个子 TOPICS 节点。如果存在,则 <xsl:apply-templates /> 将通知处理器无论当前上下文是什么都与之匹配。由于我们已询问了 TOPICS,如果此子节点存在,则再次与这第二个块相匹配,然后循环返回到其中去。这样,在第三个 TOPICS 元素 "XML" 的情形中,匹配两个子 TOPICS 元素,然后重新进入这个 XSL 块,以便将这些内容输出到 HTML。相应的嵌套会自动得以保留。很棒,是不是?<br /><br />请看直接来自转换的 HTML 输出。<br /><br />XSL 代码就讨论到这里。我们已经通过在 XML 文档内的递归生成了一组嵌套的 HTML 列表。既然我们已经得到了该输出,则让我们现在来快速浏览一下使 TOC 变为动态 .js 和 .css 的代码。<br /><br />使用脚本显示和隐藏列表节点<br />共有四个函数处理我们的 HTML TOC 中的所有“操作”。ShowAll() 和 HideAll() 只需要一个 tagName 参数,它们在页面上构建一个该标记(除了第一个)的所有元素的集合,然后将每个元素的 style.display 属性设定为 "block"(显示)或 "none"(隐藏)。前两个函数,document.onclick() 和 GetChildElem() 协同运行,以显示或隐藏父 <LI> 被单击的某个 <UL>。实际上我们可能已经在 XSL 中编写了每个 <LI> 的 ONCLICK 属性,但像我们的同事 DHTML Dude (英文)一样,我们喜欢 Internet Explorer 事件排序的抽象、能力和灵活性。<br /><br />document.onlclick() 将文档的 onclick() 事件与本函数联系起来,因此在文档上的单击都在此得以处理。现在,我们只希望在单击带有子 <UL> 的 <LI> 时执行某种操作,我们首先检查用户是否单击了类名 为 "clsHasKids" 的元素。然后,执行一些预防性的异常处理后,使用 GetChildElem() 要么返回对某个有效子 <UL> 的引用,要么返回错误,如果它不存在的话。最后,我们使用三组 JScript 条件语句将 style.display 设为其当前设置的补充。<br /><br />列表 3:list.js<br />function GetChildElem(eSrc,sTagName)<br />{<br /> var cKids = eSrc.children;<br /> for (var i=0;i<cKids.length;i++)<br /> {<br /> if (sTagName == cKids[i].tagName) return cKids[i];<br /> }<br /> return false;<br />}<br /><br />function document.onclick()<br />{<br /> var eSrc = window.event.srcElement;<br /> if ("clsHasKids" == eSrc.className && (eChild = GetChildElem(eSrc,"UL")))<br /> {<br /> eChild.style.display = ("block" == eChild.style.display ? "none" : "block");<br /> }<br />}<br /><br />function ShowAll(sTagName)<br />{<br /> var cElems = document.all.tags(sTagName);<br /> var iNumElems = cElems.length;<br /> for (var i=1;i<iNumElems;i++) cElems[i].style.display = "block";<br />}<br /><br />function HideAll(sTagName)<br />{<br /> var cElems = document.all.tags(sTagName);<br /> var iNumElems = cElems.length;<br /> for (var i=1;i<iNumElems;i++) cElems[i].style.display = "none";<br />}<br /><br />使用 CSS 美化外观<br />最后,我们使用一点 CSS 小技巧来美化 TOC 的外观。本示例中的 CSS 相当简单;您可以容易地完成一些更为复杂(也更为漂亮)的工作,如 Web Workshop(英文)中的 TOC。这里的任意结果的样式规则仅适用于 <UL> 和 <LI> 的。我们将所有是 <LI> 的子元素的 <UL> 元素的最初显示设为 "none",将给那些 className 为 "clsHasKids" 的 <LI> 元素赋予“手”形光标,表示单击它会完成某种操作(这里表示显示或隐藏子 <UL>), 并调整 <UL> 和 <LI> 的列表样式类型和页边距。<br /><br />列表 4:list.css<br /><pre class='overflow'>BODY { font-family:verdana; font-size:70%; }<br />H1 { font-size:120%; font-style:italic; }<br /><br />UL { margin-left:0px; margin-bottom:5px; }<br />LI UL { display:none; margin-left:16px; }<br />LI { font-weight:bold; list-style-type:square; cursor:default; }<br />LI.clsHasKids { list-style-type:none; cursor:hand; }<br /><br />A:link, A:visited, A:active { font-weight:normal; color:navy; }<br />A:hover { text-decoration:none; }<br /><br />BUTTON { font-family:tahoma; font-size:100%; }</pre><br /><br />显示不同的 TOC 视图<br />正如上面提到的,在 XML 存储数据的一个优点就是可以使用不同的样式表进行转换,很容易地生成同一数据的不同视图。可下载的示例代码包括四个附加的 XSL 样式表(以及脚本和样式文件):divs.xsl 可以直观的层次 DIV 生成 TOPIC,flat.xsl 在相同层次上生成所有 TOPIC,links.xsl 打印某个 TABLE 中的实际 URL,而 list_pp.xs、l 则对 list.xsl 稍作修改,以便生成较规整的 HTML 源代码。<br /><br />对所有浏览器进行处理:在服务器上进行转换<br />示例是基于在客户机的 Internet Explorer 5 上运行而编写的,它使用了 XML mime-type。无论怎样,在跨浏览器的情形中,在服务器上转换 XML 并将其下传“确实”是很容易的。下面的代码(它也在可下载的 .zip 文件中)就是针对这一问题的。用户只需将示例文件放在 Internet Information Server(IIS) 服务器上,装载 webdev.asp, 并传递一个 XSL 文件名作为可选查询字符串参数;例如,http://<yourmachinename>/codecorner/xml/webdev.asp?xsl=divs.xsl。您还可以装载 default.asp 页面,该页面有一个到各种 XML/XSL 组合的链接列表。<br /><br />列表 5:webdev.asp<br /><pre class='overflow'><% @LANGUAGE="JScript" %><br /><%<br /> var sXml = "webdev.xml"<br /> var sXsl = new String(Request.QueryString("xsl"));<br /> if ("undefined" == sXsl) sXsl = "list.xsl"<br /> <br /> var oXmlDoc = Server.CreateObject("MICROSOFT.XMLDOM");<br /> var oXslDoc = Server.CreateObject("MICROSOFT.XMLDOM");<br /> oXmlDoc.async = false;<br /> oXslDoc.async = false;<br /> oXmlDoc.load(Server.MapPath(sXml));<br /> oXslDoc.load(Server.MapPath(sXsl));<br /> Response.Write(oXmlDoc.transformNode(oXslDoc)); <br />%></pre><br /><br /> <br> <a href="/j2ee/index.html">↑返回目录</a> <BR> 前一篇: <a href='/j2ee/1/2845.html'>利用 Jsp+Taglib+JavaBean 快速构建 动态数据库查询模板 </a> <br> 后一篇: <a href='/j2ee/1/2847.html'>如何使用WebSphere 6.0 Rapid Development and </a> </div> <!-- end: 正文 --> <!-- #EndEditable --> <!-- begin: footer --> <div id=footer><center> <a href="http://www.javanb.com/index.html">首页</a> | <a href="http://www.javanb.com/java-sitemap-bd.html">全站 Sitemap</a> | <a href="http://www.javanb.com/contact.html">联系我们</a> | <a href="#" onclick="this.style.behavior='url(#default#homepage)';this.setHomePage('http://www.javanb.com/');return(false);">设为首页</a> | <a href="#" onclick="window.external.AddFavorite('http://www.javanb.com/', 'Java 编程资料牛鼻站');return false;">收藏本站</a> <br>版权所有 Copyright © 2006-2007, Java 编程资料牛鼻站, All rights reserved <br>   </center></div> <!-- end: footer --> </div> </body><!-- #EndTemplate --></html>