您的位置:首页 > 其它

用XSL与XML实现多级菜单

2005-03-07 18:42 330 查看
XML是可扩展标记语言(地球人都知道),其文档内容具有良好的可读性。我们通常在项目中保存一些系统配置数据,也就它来做一些数据的交换。
 
而XSL本身也是xml,这是一种可扩展的样式表语言。 它为xml的数据表示和数据的转换定义一组标准的标签语言。我们可以用 xsl来控制xml数据显示为特定格式或者转换为特定媒体。
 
下面写个简单的例子来看看xml与xsl的关系(这个例子来自于Microsoft的xml文档)。我们有一个xml文档,:
<pre>
XML(hello.xml)
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="hello.xsl"?> <hello-world> <greeter>An XSLT Programmer</greeter>
<greeting>Hello, World!</greeting>
</hello-world>
</pre>
这个xml文档第2行是指定处理文档用的样式表文件。后面的是文档数据。下面的是XSL文件:
<pre>
XSL(hello.xsl)
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/hello-world">
<HTML>
<HEAD>
<TITLE></TITLE>
</HEAD>
<BODY>
<H1><xsl:value-of select="greeting"/></H1>
<xsl:apply-templates select="greeter"/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="greeter">
<DIV>from
<I><xsl:value-of select="."/></I>
</DIV>
</xsl:template>
</xsl:stylesheet>
</pre>
我们先将这两个文件存在同一个目录。因为在xml文档中指定了样式表文件,当我们从IE中打开xml文件时,IE会自动调用相应的XSL文件来处理xml数据。从xsl文档中我们看到很多熟悉的文字,没错,它们就是html标签。我们通过这个xsl文件将xml数据以html形式表现出来。这时我们会从IE中看到
Hello,World!
from An XSLT Programmer
 
XSL语言功能强大而奇妙。从上面的例子中,我们可以初步了解到,一个xsl文档中使用了很多类似"xsl:xxxxx"这样的标签,这些标签就是xsl语言的部分。一个xsl文档至少是由一个模板组成的,xsl的解析引擎会负责将xml数据按xsl的模板定义来转换。就像上面的例子,就有两个模板:
<xsl:template match="/hello-world">
<xsl:template match="greeter">
模板可以用来处理特定的xml数据,通过match属性来指定。match属性里的是一个xpath的表达式(xpath在本文先不作讨论),通过它可以匹配相关的xml节点给模板来处理。我们看到在模板中,大部分内容都是html的内容,只有少量的<xsl:xxxx>这样的标签,非<xsl:xxxx>标签的内容,在xsl引擎解析时,会原文保留。当遇到<xsl:xxxx>标签才做处理。像上面的例子中,有一个<xsl:value-of select="greeting"/>标签,它是将select属性指定的greeting节点输入到当前位置。通过xml文档我们看到greeting节点值是“Hello, World!”,输出时它正好在html的<H1>标签当时,所以它当然以大号的黑体字来显示了。
 
常用的xsl标签有很多,常用到的一般有:
xsl:value-of (选择节点并输出)
xsl:apply-templates (对匹配的节点应用相应的模板)
xsl:template (模板定义)
xsl:if (条件判断)
xsl:choose (多条件分支)
xsl:for-each (循环)
 
利用这些xsl的标签,我们可以实现一定的‘数据结构+算法’来完成一部分工作,所以我们说,xsl是一种程序语言,关于xsl 更详细的学习,你可以看Microsoft的XML SDK文档,它对xml, xsl甚至xpath的内容讲的非常详细(感谢Microsoft提供这么好的文档)。
 
下面回到正题,如何用xml/xsl实现一个多级树形菜单。
我来看一下树形菜单的xml文档类型定义:
<?xml version="1.0" encoding="UTF-8" ?>
<!ELEMENT tree ( menu+ ) >
<!ELEMENT menu ( menu* ) >
<!ATTLIST menu text CDATA #REQUIRED >
<!ATTLIST menu icon CDATA #IMPLIED >
<!ATTLIST menu url CDATA #IMPLIED >
<!ATTLIST menu target CDATA #IMPLIED >
<!ATTLIST menu folded CDATA #IMPLIED >
通过这个定义可以看到,我们的菜单xml结构是由一个tree根结点组成。tree节点可以包含多个menu节点。而每个menu节点也可以包含多个menu节点。这样就达到多级树形结构的要求。下面来看这个xml结构的例子:
 
<pre>
<tree>
<menu text="一级菜单" icon="xxx.gif" folded="false">
<menu text="二级菜单1" icon="yyy1.gif" url="www.yyy1.com" target="_blank"/>
<menu text="二级菜单2" icon="yyy2.gif" url="www.yyy2.com" target="_blank"/>
</menu>
</tree>

</pre>
menu节点具有5种属性,分别是:
text,用来作为菜单的显示文字
icon,菜单的图标
url, 点击菜单后的地址
target, 显示地址的目标框架
folded, 如果是菜单还有子菜单的话,此属性决定菜单是否折叠。
其中,text属性是必须,其它的根据需要取舍。
 
根据我们的DTD, 我们可以把这个菜单定义的任意复杂,可以嵌套任意层,程序实现上看起来有点复杂。还好,我们可以使用 xsl做一个模板,让模板自动递归调用,显示任意级数的菜单。我们的模板是这样:
<pre>
<xsl:template match="menu">
<tr bgcolor="#FFFFFF">
<td style="padding-left: 15px">
<div style="cursor: default">
<xsl:attribute name="onclick">toggle(<xsl:value-of select="generate-id
(@text)"/>,flagimg<xsl:value-of select="generate-id(@text)"/>)</xsl:attribute>
<xsl:if test="count(./*)>0">
<xsl:choose>
<xsl:when test="@folded='true'">
<img src="c.gif">
<xsl:attribute name="id">flagimg<xsl:value-of select="generate-id
(@text)"/></xsl:attribute>
</img>
</xsl:when>
<xsl:otherwise>
<img src="o.gif">
<xsl:attribute name="id">flagimg<xsl:value-of select="generate-id
(@text)"/></xsl:attribute>
</img>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<xsl:choose>
<xsl:when test="@url">
<a>
<xsl:attribute name="href"
4000
><xsl:value-of select="@url"/></xsl:attribute>
<xsl:attribute name="target"><xsl:value-of
select="@target"/></xsl:attribute>
<xsl:if test="@icon">
<img border="0">
<xsl:attribute name="src"><xsl:value-of
select="@icon"/></xsl:attribute>
</img>
</xsl:if>
<xsl:value-of select="@text"/>
</a>
</xsl:when>
<xsl:otherwise>
<xsl:if test="@icon">
<img border="0">
<xsl:attribute name="src"><xsl:value-of
select="@icon"/></xsl:attribute>
</img>
</xsl:if>
<xsl:value-of select="@text"/>
</xsl:otherwise>
</xsl:choose>
</div>
<table>
<xsl:attribute name="style">
<xsl:choose>
<xsl:when test="@folded='true'">display:none</xsl:when>
<xsl:otherwise>display:block</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name="id"><xsl:value-of select="generate-id(@text)"/></xsl:attribute>
<xsl:apply-templates/>
</table>
</td>
</tr>
</xsl:template>
>
 
</pre>
 
这个模板中,有一个地方用了<xsl:apply-templates/>标签,它会自动找到当前menu节点下所有的子节点并调用相应的 template. 由于menu节点下还是menu节点,当然就调用了模板自身,这就实现了所谓的递归,解决了无限级数的问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息