首頁  >  文章  >  後端開發  >  XML卷之實戰錦囊(5):結構樹圖

XML卷之實戰錦囊(5):結構樹圖

黄舟
黄舟原創
2017-02-10 16:22:171638瀏覽

動機:
最初想起做二元樹是因為需要做一個公司結構圖。 以前的做法都是直接用圖象軟體畫出來一張圖片。很好看,但每次有變動後都需要重新畫一個新的。 另一方面,網頁上線條的顯示、版面相當侷限。根據動態產生的資料進行排版、定位都相當困難, 而且在美觀上也差強人意。 做了各種嘗試以後,決定用XML+XSL作資料運算; 用VML來美化線條,用JAVASCRIPT來定位物件。

材料:
XML卷之結構樹圖
有2個檔案:flow2.xml 和flow2.xsl 
效果:
瀏覽這裡 
講解:
二叉樹(​​1)

瀏覽這裡 

解說:
二叉樹ML(1)

reee 格式都是以上這些基本思路的基本思路,我就不詳細講解了。

 

XML是樹型結構,我們讀取每個資料就需要對這個
XML資料樹進行遍歷。而遞歸運算是XSL優勢之一。

我也是在用其它多種方法進行遍歷運算失敗後才

決定使用XSL的。

<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>


邏輯上很簡單,目前節點(1)下面有兩個子節點(2,3)。

只需要將節點2和節點3定位在節點1的左下方和右下方就可以了。

這裡我將左右節點的連接線分別用了綠色和紅色,方便顯示。

前面我們說到了XSL的遞歸功能,為了更清楚的看到每一個詳細的

顯示步驟,只需要仿照下面的程式碼,加上一個alert語句就可以了。

<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>

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





二叉樹思路(2)
我的思路很簡單:
(1)讀取目前節點的資料,用VML產生一個新的物件。
將物件賦初始數值(如 name,id,style樣式等)
(2)用腳本控制來為目前物件定位
(3)目前節點和它的父親節點之間加箭頭,線條。

(4)繼續找目前節點的子節點,一直循環定位到結束。

也就是所有節點都遍歷完畢,已經生成好樹了。

 

<xsl:template match="FlowNode">…<SCRIPT language="JavaScript1.2">…alert(&#39;逐步显示&#39;);…</SCRIPT>…</xsl:template>

 

整個遞歸過程就是靠上面這三個模組(template)來完成的。
第一個template在匹配當前節點中每一個子節點的模板的時候

調用了後面兩個template; 而後面兩個template又在具體執行

的時候調用了第一個template ,這就相當於一個遞歸函數。

語法:

 

要依序匹配目前節點中的每個子節點的模板,應使用該元
素的基本形式

否則,匹配的節點由select 參數中XPath 表達式的值決

定,如

 

(1)和(2)的作用都是傳回由select 參數給出的表達式的字串值。

他們的搜尋條件相同,所以回傳的值也是一樣。

只不過是使用的場合不同,他們的書寫形式也就不一樣。

(1)

(2) {./iProcess/text()}

這裡定義了一些變量,節點的定位就是根據這些變數來呼叫運算公式​​的。

root_left //根的左邊距=所有葉子的分配寬度(y*10) + 所有葉子的寬度(y*50) + 左邊距基本值(10)
root_top //根的上邊距=上邊距基本值(10)
objOval //當前對象,是一個object
objOval_iProcess //當前對象的步驟值
objParentOval //當前對象的父節點,是一個object
objParentOval_iProcess //當前對象父節點的步驟值
/目前物件父節點的名稱
Leaf_left //目前物件的所有子節點中的左邊葉子數

Leaf_right //目前物件的所有子節點中的右邊葉子數

Leaf_sum //目前物件的所有子節點中葉子數

葉子:是指目前節點沒有子節點

 

節點的定位公式:

(1) 目前節點是根節點

<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>

(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"/>


比如我们想生成以下代码
bba950c6d155ac5073309a6041296da9内容94b3e26ee717c64999d7867364b1b4a3


我们假设名称为“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 不支持 c55c83ef8ee979923031582b93a38c44
要用

<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卷之实战锦囊(5):结构树图的内容,更多相关内容请关注PHP中文网(www.php.cn)!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn