遠離 Xslt
2003 年 9 月 20 日
本網站的所有內容都以簡單的 XML 文件撰寫,並轉換為 HTML。我發現這樣做效果很好,而且表示我永遠不必擔心處理 HTML 格式。(從你看到的就知道,花俏的版面不是我的風格。)我甚至以這種方式寫了一整本書。
在這段時間的大部分,我使用 XSLT 作為我的轉換語言。我已經相當擅長使用 XSLT,並讓它執行我想要執行的動作。
但不再了。
當我為這個 Bliki 撰寫軟體(在長途飛行中)時,我用 Ruby 撰寫。在那之前,我使用 Ruby 製作了我的首頁新版本。我從這個練習中得出的結論是,使用 Ruby 進行 XML 轉換比使用 XSLT 容易得多。
- XML 對於程式語言來說是一個糟糕的語法。其中有太多雜訊,結果是您看不到程式。
- XSLT 使呼叫子程式變得如此痛苦,以至於你會非常不願意使用它們,這會導致重複的程式碼。
- XSLT 可以很好地處理簡單的任務,但在處理更複雜的事情時卻很繁瑣。確實有些事情是不可能的,你必須跳到另一種語言中。
- Ruby 為我提供了一個乾淨的 OO 語言,具有清晰的語法和一個強大的 XML 程式庫。(Python 也很棒,我沒有試過。)
- 我可以將範本樣式程式碼與轉換器樣式程式碼混合使用。
XSLT 的設計會影響我使用程式的方式。我的基本轉換任務是用遞迴的 apply 函數處理,就像 XSLT 的 apply-template 指令一樣。在這個情況下,我使用 Ruby 的反射機制讓它運作良好。轉換器的核心是
class ElementHandler def apply anElement anElement.each {|e| handle(e)} if anElement end def handle aNode if aNode.kind_of? REXML::Text handleTextNode(aNode) elsif aNode.kind_of? REXML::Element handle_element aNode else return #ignore comments and processing instructions end end def handle_element anElement handler_method = "handle_" + anElement.name.tr("-","_") if self.respond_to? handler_method self.send(handler_method, anElement) else default_handler(anElement) end end ...
基本上,handle_element
方法使用反射機制呼叫處理常式物件中適當命名的函數。我為特定類型的頁面建立 ElementHandler 的子類別。因此,我有一個問題標籤,用於顯示在特定頁面上的問題。針對這個問題,我撰寫一個簡短的轉換常式。
def handle_question anElement @html.p {@html.element('b'){apply anElement}} end
@html.element
方法會將 b 標籤傳送到輸出中。在這些 b 標籤內,是執行程式區塊 {apply anElement}
的結果,這個區塊會繼續遞迴。這裡 Ruby 的區塊非常有用。
可能有很多方法可以改善這個程式,但我從讓 bliki 上線後就沒有需要動到這個程式碼。在我動到它的時候,我發現它比 XSLT 容易處理多了。
我想這可能會引發一些關於 XSLT 的實際問題。我仍然很喜歡 XSLT 的功能,但我討厭它的語法和不斷碰到的限制。我不會在明天就把整個網站轉換成 Ruby,大部分的 XSLT 都運作良好,但我確實可以看到在未來的某個時間點這樣做的可能性。但更大的問題是,對於這種任務,使用指令碼語言是否比 XSLT 更好。