最初想起做二叉树是因为须要做一个公司构造图。 之前的做法都是直接用图象软件画出来一个图片。很悦目,但每次有更改后都须要从新画一个新的。 另一方面,网页上对线条的显现、规划相称范围。依据动态生成的数据举行排版、定位都相称难题, 而且在雅观上也差强人意。 做了种种尝试今后,决议用xml+XSL作数据运算; 用VML来美化线条,用javaSCRipT来给对象定位。
材料:
XML卷之构造树图
有2个文件:flow2.xml 和 flow2.xsl
效果:
阅读这里
解说:
二叉树思绪(1)
<html xmlns:v="urn:schemas-microsoft-com:vml"> <STYLE> v\:* { BEHAVIOR: url(#default#VML) } </STYLE> <v:group id="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:template match="FlowNode"> … <SCRIPT language="Javascript1.2"> … alert('逐渐显现'); … </SCRIPT> … </xsl:template>
看了上面的慢动作,是不是能让人人相识到我的思绪。
二叉树思绪(2)
我的思绪很简朴:
(1)读取当前节点的材料,用VML生成一个新的对象。
给对象赋初始数值(如 name,id,style款式等)
(2)用剧本掌握来给当前对象定位
(3)当前节点和它的父亲节点之间加箭头,线条。
(4)继承找当前节点的子节点,一向轮回定位到终了。
也就是一切节点都遍历终了,已生成好了树。
<xsl:template match="FlowNode">
… <xsl:apply-templates /> … </xsl:template> <xsl:template match="iNextYes"> <xsl:apply-templates select="./FlowNode" /> </xsl:template> <xsl:template match="iNextNo"> <xsl:apply-templates select="./FlowNode" /> </xsl:template>
全部递归历程就是靠上面这三个模块(template)来完成的。
第一个template在婚配当前节点中每一个子节点的模板的时刻
挪用了背面两个template; 而背面两个template又在详细实行
的时刻挪用了第一个template ,这就相称于一个递归函数。
语法:
要顺次婚配当前节点中的每一个子节点的模板,应运用该元
素的基础情势 <xsl:apply-templates />。
不然,婚配的节点由 select 参数中 XPath 表达式的值决
定,如 <xsl:apply-templates select="./FlowNode" />
(1)和(2)的作用都是返回由 select 参数给出的表达式的字符串值。
他们的搜刮前提雷同,所以返回的值也一样。
只不过是运用的场所差别,他们的誊写情势也就不一样。
(1) <xsl:value-of select="./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-of select="./iProcess/text()" /> ;
(2) {./iProcess/text()}
(1)和(2)的作用都是返回由 select 参数给出的表达式的字符串值。
他们的搜刮前提雷同,所以返回的值也一样。
只不过是运用的场所差别,他们的誊写情势也就不一样。
<xsl:apply-templates select="team" order-by="blue_ID"/>
比方我们想生成以下代码
<p 称号=“参数值”>内容</p>
我们假定称号为“name”,参数值为XML数据中当前节点下面的子节点book的值
第一种写法是先加属性称号,再加参数值
<p> <xsl:attribute name="name"> <xsl:value-of select="./book/text()"/> </xsl:attribute> 内容 </p>
第二种写法是直接加属性称号和参数值
<p name="{./book/text()}">内容</p>
详细的运用你能够看我写的代码中的例子。
XSL在正式的 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 的规范里
<xsl:value-of select="./book/text()"/>
作用是:只是把他的文本值写出来,而
<xsl:value-of select="./book"/>
是把他的文本值和他的一切子节点的内容显现出来。
人人能够实验一下,输出一个有子节点的,一个无子节点的
看看显现的效果是不是雷同。
(2)须要注重:
IE5 不支持 <tag att="{xpath}">
要用
<tag><xsl:attribute name="att"><xsl:value-of select="xpath"></xsl:attribute>
定名空间要用
xmlns:xsl="http://www.w3.org/TR/WD-xsl"
<?xml version="1.0" encoding="gb2312" ?>
别的说一点:
在大多的XML教科书中所显现的代码中很少会加上encoding="gb2312" ,
因而我们在XML中用到中文的时刻会报错,缘由就是没有写这个说明。
以上就是 XML实战秘笈第五卷:构造树图的细致内容,更多请关注ki4网别的相干文章!