DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> XML卷之實戰錦囊(5):結構樹圖
XML卷之實戰錦囊(5):結構樹圖
編輯:XML詳解     

  動機:
  最初想起做二叉樹是因為需要做一個公司結構圖。 以前的做法都是直接用圖象軟件畫出來一個圖片。很好看,但每次有變動後都需要重新畫一個新的。 另一方面,網頁上對線條的顯示、布局相當局限。根據動態生成的數據進行排版、定位都相當困難, 而且在美觀上也差強人意。 做了各種嘗試以後,決定用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>[email protected]</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"/>
  比如我們想生成以下代碼
  <div 名稱=“參數值”>內容</div>

  
  我們假設名稱為“name”,參數值為XML數據中當前節點下面的子節點book的值

  
  第一種寫法是先加屬性名稱,再加參數值
  <div>
  <xsl:attribute name="name">
  <xsl:value-of select="./book/text()"/> </xsl:attribute>
  內容
  </div>

  第二種寫法是直接加屬性名稱和參數值
  <div name="{./book/text()}">內容</div>

  具體的使用你可以看我寫的代碼中的例子。

  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學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved