源码下载:
http://bbs.xml.org.cn/demo/XMLOrganize.rar
在线演示:
http://bbs.xml.org.cn/demo/XMLOrganize/Organize.xml
http://bbs.xml.org.cn/demo/XMLOrganize/Organize_T.xml
近日我正在潜心初学XML和XSL的相关技术,一日,漫漫长夜,无心睡眠,突心血来潮,想一试自己这段时间所学。因有感每日所用XML数据格式的层次性,总觉和树状结构的有相似之处,同时,受工作中要实现一组织结构图的鼓惑,故就尝试用XML和XSL来实现一个自己已用ASP实现的类似PowerPoint中的组织结构图,功成之时,不亦乐乎,掩饰不住的暗爽,真是不吐不快。故欲将其中的艰辛和喜悦,困难和收获一并拿出,希望能和象我一样初学XML的、或是已是高手高手高高手的各位分享之。好,口说无凭,列位上眼呐!
该组织结构图实现的主要功能为:
无层数限制的显示各个层之间的相关关系。
通过点击各节点旁边的“+”,“-”图标来展开或收缩该节点的下属层。
首先先来看一下相关的文件结构
Organize .xml数据文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="Organize.xsl"?>
<Root>
<Layer>
<id/>
<text/>
</Layer>
<Layer>
<id>01</id>
<text>XX集团</text>
</Layer>
<Layer>
<id>0101</id>
<text>上海分公司</text>
</Layer>
……
<Layer>
<id>0103</id>
<text>北京分公司</text>
</Layer>
<Layer>
<id>010101</id>
<text>人事部</text>
</Layer>
……
<Layer>
<id>010302</id>
<text>财务部</text>
</Layer>
<Layer>
<id>01030101</id>
<text>人事部经理</text>
</Layer>
<Layer>
<id>01030102</id>
<text>人事部助理</text>
</Layer>
……
<Layer>
<id>01010301</id>
<text>技术经理</text>
</Layer>
……
</Root>
Organize.xsl文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
<title>组织结构图</title>
</head>
<style type="text/css">
……
</style>
<body>
<center>
</br>
<span>组织结构图</span>
<div>
<xsl:call-template name="getLayer">
<xsl:with-param name="LayerID" select="/Root/Layer[1]/id"/>
</xsl:call-template>
</div>
</center>
</body>
</html>
</xsl:template>
<xsl:template name="getLayer">
<xsl:param name="LayerID"/>
<xsl:for-each select="//Layer[substring(id,1,string-length($LayerID))=$LayerID
and string-length(id)=string-length($LayerID)+2]">
<span>
…… ------ 省略了div的样式表
<img src="close.gif" alt="">
…… ------ 省略了img图标的相关操作
</img>
<span>
<a href="#" target="newWindow">
<xsl:value-of select="./text"/>
</a>
</span>
<div>
…… ------ 省略了div的样式表
<xsl:call-template name="getLayer">
<xsl:with-param name="LayerID" select="id"/>
</xsl:call-template>
</div>
</span>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
设计的思路为:
首先想到的是,组织结构在表现形式上是各个组织部门之间为:上层(权且以父层代替)以包含下层(权且以子层代替),同时各个同被父层包含的子层之间是并列平等的。
这样,我就想到对于每一层而言,都有相同的结构:对自己描述,和包含子层的容器,即为:
此主题相关图片如下:
想到这点,我就想到用
<SPAN>
<SPAN></SPAN> --------对自己的描述
<DIV></DIV> --------包含子层的容器
</SPAN>
结构来表示一个节点。因为这样既可保证各个相同层的节点是并列的,同时也实现了对每一节点,对自己的描述和所包含的子层在表现形式上是上下的。
确定了节点的表现结构后,再来考虑组织结构的数据表现格式,为保证获得组织结构数据结构的通用性和易获得性,我没有考虑按实际组织结构关系那样组织XML文件中各节点之间的关系。因为考虑到我的XML文件是从数据库中动态的生成的,如生成的XML文件格式为:
<Layer>
<id>01</id>
<text>aaaa</text>
<children>
<Layer>
<id>0101</id>
<text>bbbb</text>
<children>
……
</children>
</Layer>
</children>
</Layer>
虽然看上去挺明白,但小弟认为即不是很通用,同时,也是最关键的,用SQL语句从数据库中获得这样的数据结构,嘿嘿,小弟自觉的虽有些经纶,但还真的实现不了:),所以放弃了。选自认为最简单的实现方法,就是象上文Organize .xml中的那样,从各个节点看去,虽相互平等,但他们通过id来关联,子节点的id=父节点的id+序号,通过id来建立彼此的相互关系(即为:0101,0102,….010N都是01的子节点)。这样,小弟认为,即使一个初学者,掰一会的书,也会搞定生成这个数据结构的SQL语句来。看到此,暂且按住不表,俗话说,“真正为用户考虑的开发者,才是好的开发者”,在这字里行间,所显露的小弟的伟大和用心良苦之处,请大家暂停手中的一切事务,为小弟努力的呱唧呱唧。呵呵,终于,掌声四起。。。。。。
确定好了组织结构的数据表现格式,接下来所要考虑的最关键的XSL,就有了针对性了。因为,小弟所设想的流程是:
当检索到某一个节点时,首先要考虑的是提取该节点的对自己的描述,也即该节点的title,
同时对该节点,肯定还要查找是否有所属的子节点并提取之。对于每个节点依次进行相同的操作。
既然是这样,那根据小弟多年在编程中摸打滚爬,碰了东墙磕西墙历练出来的直觉,首先隐约感觉到的就是递归!。哈哈哈哈哈哈。。。。小弟自以为找到的解决的方案,各位看官意下如何?呵呵,暗爽呀。以下就是小弟根据所想的,实际的解决方案:
首先从根节点开始:<xsl:template match="/">
然后调用模板getLayer,将当前根节点的第一个子节点的id作为变参传入模板:
<xsl:call-template name="getLayer">
<xsl:with-param name="LayerID" select="/Root/Layer[1]/id"/>
</xsl:call-template>
在模板getLayer中,当检索到某一个节点,首先是提取该节点的对自己的描述。这可以通过XSLT语句
<xsl:value-of select="./text"/>
获得。(以下相关的XSLT语句更详细准确的描述,请查阅相关的资料和书籍)
同时,通过自身的id,在XML数据中检索出自己相关的所属子节点。这个是通过:
<xsl:for-each select="//Layer[substring(id,1,string-length($LayerID))=$LayerID
and string-length(id)=string-length($LayerID)+2]">
语句搞定的。在这个语句中,LayerID既为传入的父节点的id,通过该语句,可以检索出所有id前string-length($LayerID)位的内容=$LayerID并且总长度= string-length($LayerID) + 2 位序号长度的节点(这里,小弟暂定的每一节点的子节点的长度为该节点的长度+2位序号长度,可根据实际需要改动)。通过这个语句,也实现了另外一个功能,既:不需要考虑各个节点的顺序或位置。在XML文件中,子节点和父节点之间的顺序是可以跳跃的,各个Layer的顺序可以随意放置。我想,这应该也方便了在实际应用中的运用。
然后,依次根据每个检索到的子节点,递归调用模板getLayer。由此取得每个子节点的内容,填充到包含子层的容器中。
通过以上的设计思想和解决方案,生成了类PowerPoint组织结构图。而且,通过进一步的考虑,只改动XSL,利用同一个原XML文件,小弟还实现了类资源管理器的树状结构。如下图:
此主题相关图片如下:
实现的思想就是将同一层的节点布局由现在的水平排列改为上下的竖直排列,每一节点的文本方向由竖直改为水平,同时增加相应的缩进平即可。呵呵,是不是很简单!
通过这个学习和实践的过程,小弟虽稍有愚钝,却也感觉到了XML和XSL的灵活和强大功能。小弟以为,XML提供了数据的存储,XSL则提供了数据的操作和表现。XSL一如XML的外挂,内在的内容始终如一,而通过配合相应的不同的XSL,则可构造多样的表现形式和应用出来。不知各位意下如何。
以上是小弟初试所学,水平所限,当然其中会可能需要推敲和完善的地方,小弟之所以献丑,就是希望能与大家分享之余,能得到各位看官的赐教,能在各位看官的指点和批评中进步,这就是小弟的所希望的最大的收获了。