搜索文章:

首页  |  Java技术  |  Asp.net  |  Asp编程  |  VC/C++  |  Delphi  |  VB编程

用XSLT轻松实现树形折叠导航栏

 一般我们见到的xml文件是以元素为结点的,随着层次的不断加深,逐渐成了一棵树,这种文件的好处是我们一看就很明白其中的子、父、祖宗、兄弟关系,不方便之处在于,我个人认为,如果层次很深又有很多的兄弟结点的话,那么文件可能很大而影响处理的效率。正由于xml对描述数据结构的灵活性,所以在某些环境下采用属性值来描述元素之间的关系。例如花园左边的toc(table of content),实现它的xml文件通过属性值来说明元素的类型(node or leaf),不过里面仍有子结点存在,所以用来transform它的xsl文件很复杂,分了好几种情况。当然今天我们不是谈花园toc的实现方法而是用一种更快速、更巧妙的方法来实现类似的toc,当然也可以叫"树形折叠导航栏"。好了,废话少说,进入正题。先来看一个很简单的dtd。 navigator.dtd
<!element navigation (navigator*)>
<!element navigator empty>
<!attlist navigator id cdata #implied ancestorid cdata #implied layer cdata #implied title cdata #implied childs cdata #implied url cdata #implied image cdata #implied>

文件很简单,可以这样理解,顶层元素navigation包含了多个navigator元素定义了,navigator不包含元素但有一系列属性。 也许您已经发现, 属性中有两个叫ancestorid childs的,对了,这两个属性是关键, 当然还有layer, 在他们的共同作用下, navigator元素之间的关系将被明确描述。 好了, 我们来看navi.xml文件, 以花园toc做为例子。

查看花园toc例子:

navi.xml
<?xml version="1.0" encoding="gb2312"?>
<!doctype navi system "navigator.dtd">
<?xml-stylesheet type="text/xsl" href="navigator.xsl" ?>
<navigation>
<navigator id=1 ancestorid=1 layer=0 title=花园首页 childs=0 url=default.asp image=images/dc.gif/>
<navigator id=2 ancestorid=2 layer=0 title=我的花园 childs=4 url=# image=default/>
<navigator id=3 ancestorid=2 layer=1 title=收藏夹 childs=4 url=# image=default/>
<navigator id=21 ancestorid=3 layer=2 title=我管理的花坛 childs=0 url=mybbs.asp?cat=g image=images/dc-new.gif/>
<navigator id=22 ancestorid=3 layer=2 title=我种下的种子 childs=0 url=mybbs.asp?cat=t image=images/dc-new.gif/>
<navigator id=23 ancestorid=3 layer=2 title=我喜欢的花园 childs=0 url=myfavorite.asp?cat=g image=images/dc-new.gif/>
<navigator id=24 ancestorid=3 layer=2 title=我收藏的文章 childs=0 url=myfavorite.asp?cat=t image=images/dc-new.gif/>
<navigator id=4 ancestorid=2 layer=1 title=个人工具箱 childs=2 url=# image=default/>
<navigator id=25 ancestorid=4 layer=2 title=配置和管理 childs=0 url=personal.asp image=images/dc-config.gif/>
<navigator id=26 ancestorid=4 layer=2 title=花瓣兑换点 childs=0 url=apetal.asp image=images/dc-config.gif/>
<navigator id=27 ancestorid=2 layer=1 title=我的日记本 childs=0 url=mydiary.asp image=images/dc-diary.gif/>
<navigator id=6 ancestorid=2 layer=1 title=好友和短讯 childs=0 url=myfriend.asp image=images/dc-friends.gif/>
<navigator id=7 ancestorid=7 layer=0 title=计算机技术 childs=2 url=# image=default/>
<navigator id=8 ancestorid=7 layer=1 title=dhtml,jscript childs=0 url=bbsgroup.asp?c=6&g=16 image=images/dc.gif/>
<navigator id=9 ancestorid=7 layer=1 title=.net,asp+探讨 childs=0 url=bbsgroup.asp?c=6&g=17 image=images/dc.gif/>
<navigator id=10 ancestorid=7 layer=1 title=asp互助 childs=0 url=bbsgroup.asp?c=6&g=18 image=images/dc.gif/>
<navigator id=11 ancestorid=11 layer=0 title=箐箐校园 childs=2 url=# image=default/>
<navigator id=12 ancestorid=11 layer=1 title=南京大学 childs=0 url=bbsgroup.asp?c=7&g=19 image=images/dc.gif/>
<navigator id=13 ancestorid=11 layer=1 title=东南大学 childs=0 url=bbsgroup.asp?c=7&g=20 image=images/dc.gif/>
<navigator id=14 ancestorid=14 layer=0 title=花园·有个广场 childs=2 url=# image=default/>
<navigator id=15 ancestorid=14 layer=1 title=意见箱 childs=0 url=bbsgroup.asp?c=8&g=21 image=images/dc.gif/>
<navigator id=16 ancestorid=14 layer=1 title=花园·人物故事 childs=0 url=bbsgroup.asp?c=8&g=22 image=images/dc.gif/>
<navigator id=17 ancestorid=17 layer=0 title=园丁办公室 childs=0 url=bbsgroup.asp?c=9&g=23 image=images/dc-key.gif/>
<navigator id=18 ancestorid=18 layer=0 title=青青芳草地 childs=0 url=bbsgroup.asp?c=9&g=24 image=images/dc.gif/>
<navigator id=19 ancestorid=19 layer=0 title=统计信息 childs=0 url=viewlog.asp image=images/dc-chart.gif/>
<navigator id=20 ancestorid=20 layer=0 title=activecard childs=0 url=activecard?fromgarden image=images/dc-card.gif/>
</navigation>

结合上面我讲的和花园左边的toc, 仔细分析这个文件后, 找出元素间存在的关系是很容易的, 难的是怎么想到这么来创建xml文件的。 好了, 有了数据, 下一步就是如何manupilate了。

  我引用花园的toc,一是让大家能有个初步印象,等文章完成后, 把几个文件c&p加上几个图片, 在ie5以上的机器上象打开一个html文件一样打开navi.xml后,就会出现跟花园很类似的toc了;二是希望大家根据它的层次结构来分析我的xml文件, 因为除顶层外, 我的层次安排和花园是一样的。 我来解释一下:layer相同表示元素处在同一层次即兄弟关系, childs的值表示该元素是否有子结点, 父子之间用ancestorid和id联系, 依次类推可以扩充至无限次深。 在xsl文件中根据layer的值用padding-left属性来实现树形,根据layer的值用display:none或block来实现折叠。 原理即此, 好,来看看这个关键的navigator.xsl: <?xml version="1.0" encoding="gb2312" ?>
<html>
<head>
<title>xslt树形导航栏</title>
<link rel="stylesheet" type="text/css" href="navigator.css"/>
<script src="toggle.js"></script>
</head>
<body>

<div xmlns:xsl="http://www.w3.org/tr/wd-xsl" >
<table>
<tr>
<td><div nowrap="true" style="padding-left:0em;">有座花园分类目录</div></td>
</tr>
<xsl:for-each select="navigation/navigator">
<tr>
<xsl:attribute name="title"><xsl:value-of select="@title" /></xsl:attribute>
<xsl:attribute name="class">navigator<xsl:if test="@layer[.>0]">-hidden</xsl:if></xsl:attribute>
<xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
<xsl:attribute name="ancestorid"><xsl:value-of select="@ancestorid"/></xsl:attribute>
<xsl:attribute name="depth"><xsl:value-of select="@layer"/></xsl:attribute>
<xsl:if test="@childs[.>0]">
<xsl:attribute name="expanded">no</xsl:attribute>
</xsl:if>
<td style="cursor:hand">
<div nowrap="true"><xsl:attribute name="style">padding-left:<xsl:value-of select="@layer"/>em;</xsl:attribute>
<xsl:choose>
<xsl:when test="@childs[.>0]"><img src="images/bs.gif"></img></xsl:when>
<xsl:otherwise><img><xsl:attribute name="src"><xsl:value-of select="@image" /></xsl:attribute></img></xsl:otherwise>
</xsl:choose>
<a><xsl:if test="@childs[.>0]"><xsl:attribute name="onclick">toggle(<xsl:value-of select="@id" />)</xsl:attribute></xsl:if><xsl:attribute name="href"><xsl:value-of select="@url" /></xsl:attribute><xsl:value-of select="@title" /></a></div></td>
</tr>
</xsl:for-each>
</table>
</div>
</body>
</html>

当然, 少了navigator.css是不行的。

navigator.css

body
{
font-family:verdana;
cursor:default;
font-size:9pt;
}

table
{
font-size:110%;
}

a
{
color:"#003366";
text-decoration:none;
}

a:hover
{
text-decoration:underline;
color:#003366;
}

div img
{
margin-bottom: 0px;
margin-right: 5px;
margin-top: -3px;
vertical-align: middle
}

div a:hover
{
background-color: greenyellow
}
div a
{
font-weight: normal;
margin-right: 5px;
vertical-align: middle
}

.navigator
{
color: #003366;
}
.navigator-hidden
{
display:none;
}

现在运行navi.xml的话, 您就会看见所有layer=0的navigator了(因为那些layer>0的被class="navigator-hidden"隐藏起来了), 当然现在还不能实现展开和折叠, 缺少toggle这个函数。

展开和折叠其实就是显示或不显示(display:none or block)它与可见与不可见(visible or invisible)是有区别的, 前者不在页面预留空间。 这个toggle函数完成两个功能, 改变tr原来的hidden属性, 使原来不显示的显示; 改变img的src属性, 更改图片。

toggle.js

function toggle(id)
{
var thisrow = document.all.item(id);
if (thisrow)
{
if (thisrow.getattribute("expanded") == yes)
{
thisrow.setattribute("expanded", "no");
thisrow.children(0).children(0).children(0).src = "images/bs.gif";

var allrows = document.all.tags("tr");
for (var i=1; i < allrows.length; i++)
{
var row = allrows[i];
if (row.getattribute("ancestorid") == id)
{
if (row.getattribute("expanded") == yes) {
toggle(row.getattribute("id"));
}
row.classname = navigator-hidden;
}
}
thisrow.classname = navigator;
}
else
{
thisrow.setattribute("expanded", "yes");
thisrow.children(0).children(0).children(0).src = "images/bo.gif";

var allrows = document.all.tags("tr");
var depth = parseint(thisrow.getattribute("depth"));
for (var i=1; i < allrows.length; i++)
{
var row = allrows[i];
if (row.getattribute("ancestorid") == id &&
parseint(row.getattribute("depth")) == depth + 1 )
{
row.classname = navigator;
}
}
}
}
}

到此结束。

诚然这个toc的功能还是最基本的, 例如我还未做内容和目录的同步,其中有的地方还可以修改, 对xml和xsl文件可以进一步瘦身。 不过对一般用户来讲, 这已经足够了。
真诚希望这篇文章能对您有所启发、有所帮助, 以后做出更酷、更快、更方便、功能更强的toc。

()

相关文章:
© 2006   www.java-asp.net