xml+xsl 自动生成 二叉树

时间:2022-02-14 03:31:13
在myhyli和赛羊的帮助下完成了二叉树的基本定位显示

演示地址:
http://www.wy1997.com/gfxml/13.xml
 
(最近网络奇差,所以先放上一部分)

11 个解决方案

#1


xml+xsl 自动生成 二叉树

演示地址:
myhyli.digichina.net/share/13.xml

图片预览:
myhyli.digichina.net/share/13.jpg

#2


二叉树思路(1)

最初想起做二叉树是因为需要做一个公司结构图。

        以前的做法都是直接用图象软件画出来一个图片。
        很好看,但每次有变动后都需要重新画一个新的。
        
        另一方面,网页上对线条的显示、布局相当局限。
        根据动态生成的数据进行排版、定位都相当困难,
        而且在美观上也差强人意。

        做了各种尝试以后,决定用XML+XSL作数据运算;
        用VML来美化线条,用JAVASCRIPT来给对象定位。
        
        [code]
                <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的基本格式,我就不详细讲解了。
        [/code]

        XML是树型结构,我们读取每个数据就需要对这个
        XML数据树进行遍历。而递归运算是XSL优势之一。
        我也是在用其它多种方法进行遍历运算失败后才
        决定使用XSL的。

        [code]
                <FlowRoot>
                        <vcTitle>二叉树--结构图</vcTitle>
                        <Author>车仔</Author>
                        <Email>carboy@blueidea.com</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>
        [/code]

        逻辑上很简单,当前节点(1)下面有两个子节点(2,3)。
        只需要将节点2和节点3定位在节点1的左下方和右下方就可以了。
        这里我将左右节点的连接线分别用了绿色和红色,方便显示。


        前面我们说到了XSL的递归功能,为了更清楚的看到每一个详细的
        显示步骤,只需要仿照下面的代码,加一个alert语句就可以了。

        [code]
                <xsl:template match="FlowNode">
                        …
                        <SCRIPT language="JavaScript1.2">
                                …
                                alert('逐步显示');
                                …
                        </SCRIPT>
                        …
                </xsl:template>
        [/code]

        看了上面的慢动作,是否能让大家了解到我的思路。

#3


二叉树思路(2)

我的思路很简单:
        (1)读取当前节点的资料,用VML生成一个新的对象。
             给对象赋初始数值(如 name,id,style样式等)
        (2)用脚本控制来给当前对象定位
        (3)当前节点和它的父亲节点之间加箭头,线条。
        (4)继续找当前节点的子节点,一直循环定位到结束。
             也就是所有节点都遍历完毕,已经生成好了树。
        
        
        [code]
                <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>
        [/code]

        整个递归过程就是靠上面这三个模块(template)来完成的。
        第一个template在匹配当前节点中每一个子节点的模板的时候
        调用了后面两个template; 而后面两个template又在具体执行
        的时候调用了第一个template ,这就相当于一个递归函数。
        
        语法:
        [code]
                要依次匹配当前节点中的每个子节点的模板,应使用该元
                素的基本形式 <xsl:apply-templates />。
                否则,匹配的节点由 select 参数中 XPath 表达式的值决
                定,如 <xsl:apply-templates select="./FlowNode" />
        [/code]
        
        (1)和(2)的作用都是返回由 select 参数给出的表达式的字符串值。
        他们的搜索条件相同,所以返回的值也一样。
        只不过是使用的场合不同,他们的书写形式也就不一样。
        [code]
                (1) <xsl:value-of select="./iProcess/text()" />
                (2) {./iProcess/text()}
        [/code]

        这里定义了一些变量,节点的定位就是根据这些变量来调用运算公式的。
        [code]
                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                        //当前对象的所有子节点中叶子数

                叶子:是指当前节点没有子节点
        [/code]


        节点的定位公式:

        (1) 当前节点是根节点
        [code]
                //根的位置
                SobjOval.style.left=parseInt(root_left);
                SobjOval.style.top=parseInt(root_top);
                //parseInt() 函数的作用是取整数值,如果不是则为NAN
                //isNaN()函数的作用是判断parseInt取得的是否为整数
        [/code]

        (2)当前节点是父节点的左边子节点
        [code]
                1)判断的条件是: 当前对象父节点的名称='iNextYes'
                …
                2)如果存在右边子叶子,则公式为:
                        当前节点的left=父节点的left - 当前节点的右边子叶子的总宽度- 当前节点的宽度         

                3)如果不存在右边子叶子,但存在左边子叶子,则公式为:
                        当前节点的left=父节点的left - 当前节点的左边子叶子的总宽度

                4)如果当前节点本身就是叶子,则公式为:
                        当前节点的left=父节点的left - 当前节点的宽度 
                …
        [/code]

        (3)当前节点是父节点的右边子节点
        [code]
                1)判断的条件是: 当前对象父节点的名称='iNextNo'
                …
                2)如果存在左边子叶子,则公式为:
                        当前节点的left=父节点的left + 当前节点的左边子叶子的总宽度 + 当前节点的宽度         

                3)如果不存在左边子叶子,但存在右边子叶子,则公式为:
                        当前节点的left=父节点的left + 当前节点的右边子叶子的总宽度

                4)如果当前节点本身就是叶子,则公式为:
                        当前节点的left=父节点的left + 当前节点的宽度 
                …
        [/code]
        
        (2)和(3)的公式都是得到当前节点的left,我们还需要得到当前节点的top
        很简单的公式:当前节点的top=父节点的top + 偏移量(80)

#4


好同志~~

#5


二叉树思路(3)

连接线条的定位思路:

        (1)找到当前节点和父节点的位置
        (2)判断当前节点是父节点的左边子节点,还是右边子节点
        (3)画线条


        这里定义了一些变量。
        [code]
                objOval                                //当前节点,是一个object
                objParentOval                        //当前对象的父节点,是一个object
                objLine                                //当前线条,是一个object
        [/code]

        线条的定位公式:
        
        [code]
        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) 
        [/code]



        我所能想到的也就这么多了。

        如果只是单纯的做一个公司结构图的话,会更简单很多。
        下面是赛扬的思路,我也是在他的基础上深入一点而已。
        [code]
        首先计算最下层节点个数,得出宽度,
        然后应该根据节点的从属关系计算其上层节点位置,递归。
        每一层级的节点要按从属关系先排序
        首先设“基本值”=节点应向右偏移量
        每个包含子节点的节点的left值等于它所拥有的节点所占宽度的一半加上基本值
        [/code]


        后话:

        最近不知为何,网络一直都不好。断线的时间比在线的时间多。
        所以没对代码简化,其实,要完善的功能还有很多,比如:
        需要加右键菜单
        右键菜单内含新建节点、修改节点名称、改变关联关系等
        在每一个节点上都可右键打开这个节点的右键菜单

#6


good 

:_)

#7


up!
学习中...

#8


http://eaoo.com/design/list.asp?classid=1&Nclassid=6

#9


楼上的兄弟,你具体指什么?

#10


我只会做程序,真要写说明的时候还真难为偶
写的很累,感觉还不通俗,但已经能够把我想说的说了 。

感觉XML的应用更多的体现在数据传递和页面无刷新处理数据上 。
这方面对XML应用的人很少。

#11


帮忙测试:你们看了有没有这个情况

程序在IE5.0下面显示错误
第139行 28 字符,缺少;分号
只能看到第一个节点.


在IE6环境中正常。IE5.5不清楚,但IE5肯定报错。
很奇怪,同样的文件放在不同的电脑里居然回不同效果  

#1


xml+xsl 自动生成 二叉树

演示地址:
myhyli.digichina.net/share/13.xml

图片预览:
myhyli.digichina.net/share/13.jpg

#2


二叉树思路(1)

最初想起做二叉树是因为需要做一个公司结构图。

        以前的做法都是直接用图象软件画出来一个图片。
        很好看,但每次有变动后都需要重新画一个新的。
        
        另一方面,网页上对线条的显示、布局相当局限。
        根据动态生成的数据进行排版、定位都相当困难,
        而且在美观上也差强人意。

        做了各种尝试以后,决定用XML+XSL作数据运算;
        用VML来美化线条,用JAVASCRIPT来给对象定位。
        
        [code]
                <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的基本格式,我就不详细讲解了。
        [/code]

        XML是树型结构,我们读取每个数据就需要对这个
        XML数据树进行遍历。而递归运算是XSL优势之一。
        我也是在用其它多种方法进行遍历运算失败后才
        决定使用XSL的。

        [code]
                <FlowRoot>
                        <vcTitle>二叉树--结构图</vcTitle>
                        <Author>车仔</Author>
                        <Email>carboy@blueidea.com</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>
        [/code]

        逻辑上很简单,当前节点(1)下面有两个子节点(2,3)。
        只需要将节点2和节点3定位在节点1的左下方和右下方就可以了。
        这里我将左右节点的连接线分别用了绿色和红色,方便显示。


        前面我们说到了XSL的递归功能,为了更清楚的看到每一个详细的
        显示步骤,只需要仿照下面的代码,加一个alert语句就可以了。

        [code]
                <xsl:template match="FlowNode">
                        …
                        <SCRIPT language="JavaScript1.2">
                                …
                                alert('逐步显示');
                                …
                        </SCRIPT>
                        …
                </xsl:template>
        [/code]

        看了上面的慢动作,是否能让大家了解到我的思路。

#3


二叉树思路(2)

我的思路很简单:
        (1)读取当前节点的资料,用VML生成一个新的对象。
             给对象赋初始数值(如 name,id,style样式等)
        (2)用脚本控制来给当前对象定位
        (3)当前节点和它的父亲节点之间加箭头,线条。
        (4)继续找当前节点的子节点,一直循环定位到结束。
             也就是所有节点都遍历完毕,已经生成好了树。
        
        
        [code]
                <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>
        [/code]

        整个递归过程就是靠上面这三个模块(template)来完成的。
        第一个template在匹配当前节点中每一个子节点的模板的时候
        调用了后面两个template; 而后面两个template又在具体执行
        的时候调用了第一个template ,这就相当于一个递归函数。
        
        语法:
        [code]
                要依次匹配当前节点中的每个子节点的模板,应使用该元
                素的基本形式 <xsl:apply-templates />。
                否则,匹配的节点由 select 参数中 XPath 表达式的值决
                定,如 <xsl:apply-templates select="./FlowNode" />
        [/code]
        
        (1)和(2)的作用都是返回由 select 参数给出的表达式的字符串值。
        他们的搜索条件相同,所以返回的值也一样。
        只不过是使用的场合不同,他们的书写形式也就不一样。
        [code]
                (1) <xsl:value-of select="./iProcess/text()" />
                (2) {./iProcess/text()}
        [/code]

        这里定义了一些变量,节点的定位就是根据这些变量来调用运算公式的。
        [code]
                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                        //当前对象的所有子节点中叶子数

                叶子:是指当前节点没有子节点
        [/code]


        节点的定位公式:

        (1) 当前节点是根节点
        [code]
                //根的位置
                SobjOval.style.left=parseInt(root_left);
                SobjOval.style.top=parseInt(root_top);
                //parseInt() 函数的作用是取整数值,如果不是则为NAN
                //isNaN()函数的作用是判断parseInt取得的是否为整数
        [/code]

        (2)当前节点是父节点的左边子节点
        [code]
                1)判断的条件是: 当前对象父节点的名称='iNextYes'
                …
                2)如果存在右边子叶子,则公式为:
                        当前节点的left=父节点的left - 当前节点的右边子叶子的总宽度- 当前节点的宽度         

                3)如果不存在右边子叶子,但存在左边子叶子,则公式为:
                        当前节点的left=父节点的left - 当前节点的左边子叶子的总宽度

                4)如果当前节点本身就是叶子,则公式为:
                        当前节点的left=父节点的left - 当前节点的宽度 
                …
        [/code]

        (3)当前节点是父节点的右边子节点
        [code]
                1)判断的条件是: 当前对象父节点的名称='iNextNo'
                …
                2)如果存在左边子叶子,则公式为:
                        当前节点的left=父节点的left + 当前节点的左边子叶子的总宽度 + 当前节点的宽度         

                3)如果不存在左边子叶子,但存在右边子叶子,则公式为:
                        当前节点的left=父节点的left + 当前节点的右边子叶子的总宽度

                4)如果当前节点本身就是叶子,则公式为:
                        当前节点的left=父节点的left + 当前节点的宽度 
                …
        [/code]
        
        (2)和(3)的公式都是得到当前节点的left,我们还需要得到当前节点的top
        很简单的公式:当前节点的top=父节点的top + 偏移量(80)

#4


好同志~~

#5


二叉树思路(3)

连接线条的定位思路:

        (1)找到当前节点和父节点的位置
        (2)判断当前节点是父节点的左边子节点,还是右边子节点
        (3)画线条


        这里定义了一些变量。
        [code]
                objOval                                //当前节点,是一个object
                objParentOval                        //当前对象的父节点,是一个object
                objLine                                //当前线条,是一个object
        [/code]

        线条的定位公式:
        
        [code]
        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) 
        [/code]



        我所能想到的也就这么多了。

        如果只是单纯的做一个公司结构图的话,会更简单很多。
        下面是赛扬的思路,我也是在他的基础上深入一点而已。
        [code]
        首先计算最下层节点个数,得出宽度,
        然后应该根据节点的从属关系计算其上层节点位置,递归。
        每一层级的节点要按从属关系先排序
        首先设“基本值”=节点应向右偏移量
        每个包含子节点的节点的left值等于它所拥有的节点所占宽度的一半加上基本值
        [/code]


        后话:

        最近不知为何,网络一直都不好。断线的时间比在线的时间多。
        所以没对代码简化,其实,要完善的功能还有很多,比如:
        需要加右键菜单
        右键菜单内含新建节点、修改节点名称、改变关联关系等
        在每一个节点上都可右键打开这个节点的右键菜单

#6


good 

:_)

#7


up!
学习中...

#8


http://eaoo.com/design/list.asp?classid=1&Nclassid=6

#9


楼上的兄弟,你具体指什么?

#10


我只会做程序,真要写说明的时候还真难为偶
写的很累,感觉还不通俗,但已经能够把我想说的说了 。

感觉XML的应用更多的体现在数据传递和页面无刷新处理数据上 。
这方面对XML应用的人很少。

#11


帮忙测试:你们看了有没有这个情况

程序在IE5.0下面显示错误
第139行 28 字符,缺少;分号
只能看到第一个节点.


在IE6环境中正常。IE5.5不清楚,但IE5肯定报错。
很奇怪,同样的文件放在不同的电脑里居然回不同效果