XML卷之实战锦囊(5):结构树图
动机:
最初想起做二叉树是因为需要做一个公司结构图。以前的做法都是直接用图象软件画出来一个图片。很好看,但每次有变动后都需要重新画一个新的。另一方面,网页上对线条的显示、布局相当局限。根据动态生成的数据进行排版、定位都相当困难,而且在美观上也差强人意。做了各种尝试以后,决定用XML+XSL作数据运算;用VML来美化线条,用JAVASCRIPT来给对象定位。
材料:
XML卷之结构树图
有2个文件:flow2.xml和flow2.xsl
效果:
浏览这里
讲解:
二叉树思路(1)
<htmlxmlns:v="urn:schemas-microsoft-com:vml">
<STYLE>
v\:*{BEHAVIOR:url(#default#VML)}
</STYLE>
<v:groupid="group1"name="group1"coordsize="100,100">
…
</v:group>
以上这些都是VML的基本格式,我就不详细讲解了。
XML是树型结构,我们读取每个数据就需要对这个
XML数据树进行遍历。而递归运算是XSL优势之一。
我也是在用其它多种方法进行遍历运算失败后才
决定使用XSL的。
<FlowRoot>
<vcTitle>二叉树--结构图</vcTitle>
<Author>Sailflying</Author>
<Email>sailflying@163.net</Email>
<FlowNode>
<iProcess>1</iProcess>
<vcCourse>第一个节点</vcCourse>
<iNextYes>
<FlowNode>
<iProcess>2</iProcess>
<vcCourse>第二个节点</vcCourse>
<iNextYes>…</iNextYes>
<iNextNo>…</iNextNo>
</FlowNode>
</iNextYes>
<iNextNo>
<FlowNode>
<iProcess>3</iProcess>
<vcCourse>第三个节点</vcCourse>
<iNextYes>…</iNextYes>
<iNextNo>…</iNextNo>
</FlowNode>
</iNextNo>
</FlowNode>
</FlowRoot>
逻辑上很简单,当前节点(1)下面有两个子节点(2,3)。
只需要将节点2和节点3定位在节点1的左下方和右下方就可以了。
这里我将左右节点的连接线分别用了绿色和红色,方便显示。
前面我们说到了XSL的递归功能,为了更清楚的看到每一个详细的
显示步骤,只需要仿照下面的代码,加一个alert语句就可以了。
<xsl:templatematch="FlowNode">
…
<SCRIPTlanguage="JavaScript1.2">
…
alert("逐步显示");
…
</SCRIPT>
…
</xsl:template>
看了上面的慢动作,是否能让大家了解到我的思路。
二叉树思路(2)
我的思路很简单:
(1)读取当前节点的资料,用VML生成一个新的对象。
给对象赋初始数值(如name,id,style样式等)
(2)用脚本控制来给当前对象定位
(3)当前节点和它的父亲节点之间加箭头,线条。
(4)继续找当前节点的子节点,一直循环定位到结束。
也就是所有节点都遍历完毕,已经生成好了树。
<xsl:templatematch="FlowNode">
…
<xsl:apply-templates/>
…
</xsl:template>
<xsl:templatematch="iNextYes">
<xsl:apply-templatesselect="./FlowNode"/>
</xsl:template>
<xsl:templatematch="iNextNo">
<xsl:apply-templatesselect="./FlowNode"/>
</xsl:template>
整个递归过程就是靠上面这三个模块(template)来完成的。
第一个template在匹配当前节点中每一个子节点的模板的时候
调用了后面两个template;而后面两个template又在具体执行
的时候调用了第一个template,这就相当于一个递归函数。
语法:
要依次匹配当前节点中的每个子节点的模板,应使用该元
素的基本形式<xsl:apply-templates/>。
否则,匹配的节点由select参数中XPath表达式的值决
定,如<xsl:apply-templatesselect="./FlowNode"/>
(1)和(2)的作用都是返回由select参数给出的表达式的字符串值。
他们的搜索条件相同,所以返回的值也一样。
只不过是使用的场合不同,他们的书写形式也就不一样。
(1)<xsl:value-ofselect="./iProcess/text()"/>
(2){./iProcess/text()}
这里定义了一些变量,节点的定位就是根据这些变量来调用运算公式的。
root_left//根的左边距=所有叶子的分配宽度(y*10)+所有叶子的宽度(y*50)+左边距基本值(10)
root_top//根的上边距=上边距基本值(10)
objOval//当前对象,是一个object
objOval_iProcess//当前对象的步骤值
objParentOval//当前对象的父节点,是一个object
objParentOval_iProcess//当前对象父节点的步骤值
objParent_name//当前对象父节点的名称
Leaf_left//当前对象的所有子节点中的左边叶子数
Leaf_right//当前对象的所有子节点中的右边叶子数
Leaf_sum//当前对象的所有子节点中叶子数
叶子:是指当前节点没有子节点
节点的定位公式:
(1)当前节点是根节点
//根的位置
SobjOval.style.left=parseInt(root_left);
SobjOval.style.top=parseInt(root_top);
//parseInt()函数的作用是取整数值,如果不是则为NAN
//isNaN()函数的作用是判断parseInt取得的是否为整数
(2)当前节点是父节点的左边子节点
1)判断的条件是:当前对象父节点的名称="iNextYes"
…
2)如果存在右边子叶子,则公式为:
当前节点的left=父节点的left-当前节点的右边子叶子的总宽度-当前节点的宽度
3)如果不存在右边子叶子,但存在左边子叶子,则公式为:
当前节点的left=父节点的left-当前节点的左边子叶子的总宽度
4)如果当前节点本身就是叶子,则公式为:
当前节点的left=父节点的left-当前节点的宽度
…
(3)当前节点是父节点的右边子节点
1)判断的条件是:当前对象父节点的名称="iNextNo"
…
2)如果存在左边子叶子,则公式为:
当前节点的left=父节点的left+当前节点的左边子叶子的总宽度+当前节点的宽度
3)如果不存在左边子叶子,但存在右边子叶子,则公式为:
当前节点的left=父节点的left+当前节点的右边子叶子的总宽度
4)如果当前节点本身就是叶子,则公式为:
当前节点的left=父节点的left+当前节点的宽度
…
(2)和(3)的公式都是得到当前节点的left,我们还需要得到当前节点的top
很简单的公式:当前节点的top=父节点的top+偏移量(80)
二叉树思路(3)
连接线条的定位思路:
(1)找到当前节点和父节点的位置
(2)判断当前节点是父节点的左边子节点,还是右边子节点
(3)画线条
这里定义了一些变量。
objOval//当前节点,是一个object
objParentOval//当前对象的父节点,是一个object
objLine//当前线条,是一个object
线条的定位公式:
from="x1,y1"to="x2,y2"是VML里定位线条的方式
当前节点是父节点的左边子节点,则公式为:
from=父节点的left+偏移量(15),父节点的top+偏移量(32)
to=父节点的left+偏移量(30),父节点的top-偏移量(2)
当前节点是父节点的右边子节点,则公式为:
from=父节点的left+偏移量(35),父节点的top+偏移量(32)
to=父节点的left+偏移量(20),父节点的top-偏移量(2)
我所能想到的也就这么多了。
如果只是单纯的做一个公司结构图的话,会更简单很多。
下面是赛扬的思路,我也是在他的基础上深入一点而已。
首先计算最下层节点个数,得出宽度,
然后应该根据节点的从属关系计算其上层节点位置,递归。
每一层级的节点要按从属关系先排序
首先设“基本值”=节点应向右偏移量
每个包含子节点的节点的left值等于它所拥有的节点所占宽度的一半加上基本值
后话:
最近不知为何,网络一直都不好。断线的时间比在线的时间多。
所以没对代码简化,其实,要完善的功能还有很多,比如:
需要加右键菜单
右键菜单内含新建节点、修改节点名称、改变关联关系等
在每一个节点上都可右键打开这个节点的右键菜单
讲解:
1)flow2.xml是数据文件,相信大家都不会有问题。
2)flow2.xsl是格式文件,有几个地方要注意。
(1)脚本中:
(1)<xsl:value-ofselect="./iProcess/text()"/>;
(2){./iProcess/text()}
(1)和(2)的作用都是返回由select参数给出的表达式的字符串值。
他们的搜索条件相同,所以返回的值也一样。
只不过是使用的场合不同,他们的书写形式也就不一样。
<xsl:apply-templatesselect="team"order-by="blue_ID"/>
比如我们想生成以下代码
<div名称=“参数值”>内容</div>
我们假设名称为“name”,参数值为XML数据中当前节点下面的子节点book的值
第一种写法是先加属性名称,再加参数值
<div>
<xsl:attributename="name">
<xsl:value-ofselect="./book/text()"/></xsl:attribute>
内容
</div>
第二种写法是直接加属性名称和参数值
<divname="{./book/text()}">内容</div>
具体的使用你可以看我写的代码中的例子。
XSL在正式的xmlns:xsl="http://www.w3.org/1999/XSL/Transform"的标准里
<xsl:value-ofselect="./book/text()"/>
作用是:只是把他的文本值写出来,而
<xsl:value-ofselect="./book"/>
是把他的文本值和他的所有子节点的内容显示出来。
大家可以试验一下,输出一个有子节点的,一个无子节点的
看看显示的结果是否相同。
(2)需要注意:
IE5不支持<tagatt="{xpath}">
要用
<tag><xsl:attributename="att"><xsl:value-ofselect="xpath"></xsl:attribute>
命名空间要用
xmlns:xsl="http://www.w3.org/TR/WD-xsl"
<?xmlversion="1.0"encoding="gb2312"?>
另外说一点:
在大多的XML教科书中所显示的代码中很少会加上encoding="gb2312",
因此我们在XML中用到中文的时候会报错,原因就是没有写这个申明。
后记:
这里说的是一种思路。如果触类旁通,自然能够派上用场。
相关文章
- C# 操作XML文件 XmlDocument和XElement
- 如何WordPress5.5 自带默认 XML 站点地图 wp-sitemap.xml 移除教程
- 【Groovy】xml 序列化 ( 使用 MarkupBuilder 生成 xml 数据 | 标签闭包下创建子标签 | 使用 MarkupBuilderHelper 添加 xml 注释 )
- ORA-41626: invalid XML element “string” in rule class properties ORACLE 报错 故障修复 远程处理
- 织梦dedecms中html和xml格式的网站地图sitemap制作方法详解程序员
- ISO swift下XML数据解析详解手机开发
- 详解Java中解析xml的四种方法编程语言
- MySQL导入XML文件的步骤(mysql导入xml)
- Linux系统下xml文件解析方式研究(linuxxml解析)
- XML文件配置Redis环境指南(xml文件配置redis)
- MySQL和XML表相结合的完美解决方案(mysql xml 表)
- 使用 MySQL 存储和解析 XML 格式的数据(mysql xml格式)
- MySQL与XML相遇,开启数据管理新时代(mysql xml数据库)
- MySQL处理XML小于符号的方法(mysql xml小于)
- 使用MySQL处理大于XML数据时的技巧(mysql xml 大于)
- 数据Oracle中的XML数据导入指南(oracle中导入xml)
- 解决Oracle中XML乱码问题(oracle中xml乱码)
- Mysql数据库如何处理XML文件(mysql xml文件)
- Oracle中XML数据的读取研究(oracle xml读取)
- 利用Oracle XML组件让数据处理更高效(oracle xml组件)
- Oracle XML日志发掘数据的奥秘之路(oracle xml日志)
- 籍Oracle XML编程实战指南(oracle xml 书)
- XML轻松学习手册(五):XML语法
- XML卷之实战锦囊(2):动态查询
- jQuery在IE下使用未闭合的xml代码创建元素时的Bug介绍
- ASP.NET中XML转JSON的方法实例
- php操作xml入门之xml标签的属性分析