DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> 在XSLT中用遞歸實現循環
在XSLT中用遞歸實現循環
編輯:XML詳解     

XSLT 是圖靈完成的(Turing complete)。也就是說,如果有足夠的內存,那麼 XSLT 可以完成其他任何圖靈完成語言(如 C++)所能完成的計算。對於屬性更傳統的語言的程序員來說,這可能有點奇怪。畢竟 XSLT 缺少對很多算法來說極其重要的特性,其中包括循環和可變的變量。

  注意:XSLT 所謂的變量在其他多數語言中稱為常量。它們更像是代數變量而不是傳統的編程變量。

  函數式編程

  上述的遺漏並非疏忽所致。XSLT 是一種函數式語言而不是過程性語言。在 C 或 Pascal 這樣的過程性語言中,程序被定義成一系列的步驟,這些步驟按照規定的順序執行,並在最後一步產生最終結果。在函數式語言中,程序被定義成由其他函數組成的函數,函數求值形成最終的結果。函數式語言的最大優點是執行的順序無關緊要。作為一個簡單的例子,考慮下面兩個(代數)函數:

f(x) = 2*x
g(x) = x - 3

  設函數 h(x) 是 f 與 g 的復合函數:

h(x) = f(g(x))

  對該函數求值可以先計算 g:

h(x) = f(x - 3) = 2 * (x - 3) = 2x - 6

  也可以先計算 f:

h(x) = 2 * g(x) = 2 * (x - 3) = 2x - 6

  兩者的結果是一樣的。語言的函數式使其更適合並行處理,因為問題的多個部分可以同時計算,無需擔心其中的一部分要先於其他部分計算。線程安全是自動實現的。

  函數式語言包括 XSLT,但不能包含傳統的循環,因為循環在時間上是有序的。就是說,典型循環的編寫和編譯必須保證 i==1 出現在 i==2 之前。當然,也可以反向而不是正向運行循環,或者使用 1 之外的循環計數器增量,甚至像 while 語句那樣完全取消循環計數器。但是無論什麼類型的循環,執行的順序都至關重要,這一點與函數式編程正好相反。

  遞歸

  函數式編程中,傳統語言中用循環完成的多數任務都可以使用遞歸來完成。參數代替了變量。比如,最近有人問我如何輸出在編譯時不知道數量的點(句點)。比方說,格式化菜單時可能要用到,因為在菜名和價格之間常常需要不同數量的點:

Crawfish Etoufee.......$9.95
FrIEd Chicken..........$6.95

  在 C 語言中可以編寫一個簡單的函數:

void printDots(int n) {
 int i;
 for (i = 0; i < n; i++) {
  printf(".");
 }
 
}

  但是這並不是解決問題的惟一辦法。可以用遞歸代替循環,比如:

void printDotsRecursively(int n) {
 if (n > 0) {
  printf(".");
  printDots(n-1);
 }
 
}

  在 C 中很少這樣做,但是在 XSLT 中,這是惟一的辦法。

  下面的模板准確地生成 count 參數所傳遞的數量的點。邏輯很簡單:如果 $count 的值大於零,就輸出一個點,將 count 參數減去 1 後再調用這個函數;否則什麼也不做。這與 printDotsRecursively 函數采用的算法基本相同,只不過是用 XSLT 而非 C 實現的:

 <xsl:template name="dots">
 
   <xsl:param name="count" select="1"/>
   <xsl:if test="$count > 0">
    <xsl:text>.</xsl:text>
    <xsl:call-template name="dots">
     <xsl:with-param name="count" select="$count - 1"/>
    </xsl:call-template>
   </xsl:if>
   
 </xsl:template>

  比如要輸出 100 個點,用 100 count 參數值調用該函數:

  <xsl:call-template name="dots">
   <xsl:with-param name="count" select="100"/>
  </xsl:call-template>

  如果不希望傳遞一個常數值,那麼還可以根據其他數據計算要打印的點數。比如,下面的指令分別計算價格和菜名的長度(更具體地說,是上下文節點中 price 和 entree 子元素的 string-values 函數值)後,輸出足夠做的點數將每個菜單行填充到 80 個字符:

  <xsl:call-template name="dots">
   <xsl:with-param name="count"
        select="80 - string-length(entree) - string-length(price)"/>
  </xsl:call-template>

  結束語

  無論是在 C、XSLT 中,還是在 Scheme 中,都應用了使用遞歸代替循環。但是這種技術非常優雅。在 XSLT 中不需要經常使用這種技術,但使用這種技術可以完成用其他任何標准 XSLT 技術都做不到的技巧性任務。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved