DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> XML 編程思想: 研讀XML Hacks
XML 編程思想: 研讀XML Hacks
編輯:XML詳解     

 XML Hacks是一本介紹 XML 技巧和竅門的書籍。這是一本很有用的參考資料,其內容十分廣泛,但如果某些材料能夠進一步展開或者改寫的話,可能會更好。Uche Ogbuji 提供了該書的應用報告。

  在 上一期文章中,我評論了 Elliotte Rusty Harold 所著的 Effective XML,所有 XML 專業人員都應該讀一讀這本很棒的著作。在本期文章中,我把目光投向了另一本實用 XML 書籍,Michael Fitzgerald 編纂的 XML Hacks(O'Reilly and Associates,2004 年)。這本書涉及的范圍很廣,包括入門性的基礎知識、中階和高階的設計與實現技術,以及一些工具的使用技巧。本專欄和其他 developerWorks文章的讀者,可能更希望我能專注於 XML 設計和 XML 詞匯表的問題。 XML Hacks論述更多的是實現細節和工具使用,但是這些知識也很重要,在本期文章中,我將介紹我自己應用書中內容的一些實際觀察。與關於 Effective XML的文章一樣,本文並不是書評,而是受該書啟發想到的一些東西,本書是為不具備這些知識的讀者編寫的。

  使用 XInclude 包含外部文本文檔

  在這本書的第 26 章“Include External Documents with XInclude”中,說明了如何以類似 XML 內置外部已解析實體的方式使用 XInclude(請參閱 Resources)。書中給出了一個示例文檔,其中插入了由 HTTP URL 指定的外部 XML 文檔。XInclude 確實為這種混合增加了為數不多的一些技巧,比如後退支持(出現錯誤時提供替代內容),以及處理程序發出 HTTP 請求時指定內容協商方式的機制。但是我認為與已解析實體機制相比,XInclude 的兩個最主要優點是:

  • 能夠使用 XPointer 從目標文檔中選擇要包含的部分。
  • 能夠改變解析機制,將外部文檔作為完全轉移的文本文件而不是 XML 文檔插入。

  如果正在撰寫包含代碼清單或者示例的 XML 文檔,第二點尤其方便。比方說,假設您撰寫的文檔中要包含清單 1 所示的 Python 語言代碼。

清單 1. 作為清單插入 XML 文檔的 Python 實例代碼

  def game_show(contestant_guess, prices):
  if prices[contestant_guess] < 1000:
    print "you win!"
  else:
    print "you lose!"
 

  您應該在單獨的文件中開發這些代碼,這樣,就可以在將它們放入文檔之前對其進行測試,以確保它們能像您期望的那樣工作。首先您可以把這些代碼剪切並粘貼到 XML 文件中,如清單 2 所示。

  清單 2. 直接剪切粘貼示例代碼的插入文檔

  <?XML version='1.0' encoding='iso-8859-1'?>
<!DOCTYPE Html PUBLIC
 "-//W3C//DTD XHtml 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xHtml1-transitional.dtd">
<html XMLns="http://www.w3.org/1999/xHtml" lang="en-US" XML:lang="en-US">
<head>
 <title>On-line game show programming in Python</title>
</head>
<body>
 <div class="section">
  <h3>A simple example</h3>
  <p>Examine the following code:
  </p>
  <div class="code-listing">
   <div class="caption">example 1</div>
<!-- paste Python code here -->
  </div>
 </div>
</body>
</Html>
 

  這樣會造成錯誤,因為 if prices[contestant_guess] < 1000: 這一行包含沒有轉義的小於號(<)。您可以手工將它轉義成 < ,但是這樣做太麻煩,而且修改代碼可能造成錯誤;然後您還需要修改外部文件和測試文件,最後修改粘貼的文件,並將其重新轉義到您的文檔中。一種解決方案是使用 CDATA 部分,如清單 3 所示,將代碼直接粘貼到這個代碼塊,這樣就不需要進行進一步的轉義了。

 清單 3. 通過剪切粘貼到 CDATA 節插入示例代碼的文檔

  <?XML version='1.0' encoding='iso-8859-1'?>
<!DOCTYPE Html PUBLIC
 "-//W3C//DTD XHtml 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xHtml1-transitional.dtd">
<html XMLns="http://www.w3.org/1999/xHtml" lang="en-US" XML:lang="en-US">
<head>
 <title>On-line game show programming in Python</title>
</head>
<body>
 <div class="section">
  <h3>A simple example</h3>
  <p>Examine the following code:
  </p>
  <div class="code-listing">
   <div class="caption">example 1</div>
<![CDATA[
<!-- paste Python code here -->
]]>
  </div>
 </div>
</body>
</Html>
 

  這種方法無疑能夠避免了轉義錯誤,但是您必須注意那些估計可能很少出現的字符串“]]>”,如清單 4 中所示。

  清單 4. 作為清單插入 XML 文檔的 Python 示例代碼

  def game_show(guesses, contestant, prices):
  if prices[guesses[contestant]]>1000:
    print "you win!"
  else:
    print "you lose!"
 

  為了在 CDATA 部分中正確轉義這一行,您至少需要像 if prices[guesses[contestant]]]]><![CDATA[>1000: 這樣復雜的代碼。還要注意的是,我使用的是 Python 代碼,多數情況下,Python 需要轉義的地方相對較少。如果編寫的是關於 XML 的文檔,手工轉義可能就無法勝任了。而且出現“]]>”這個字符串組合的機會也多得多(比如 XML 清單可能本身包含 CDATA 部分)。

 當然,您可以選擇自己的方法繞開這個障礙,但是我發現,處理文章中所包含代碼的最簡單的方法就是使用 XInclude 的 parse="text" 功能。只要在 xi:include 元素中添加該屬性,就能自動將代碼作為 XML CDATA 解析,從而自動轉義包含的內容。清單 5 就是以這種方式使用 XInlude 的一個例子:

  清單 5. 使用文本行 XInclude 插入示例代碼的文檔

  <?XML version='1.0' encoding='iso-8859-1'?>
<!DOCTYPE Html PUBLIC
 "-//W3C//DTD XHtml 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xHtml1-transitional.dtd">
<html XMLns="http://www.w3.org/1999/xHtml" lang="en-US" XML:lang="en-US"
   XMLns:xi="http://www.w3.org/2001/XInclude"
>
<head>
 <title>On-line game show programming in Python</title>
</head>
<body>
 <div class="section">
  <h3>A simple example</h3>
  <p>Examine the following code:
  </p>
  <div class="code-listing">
   <div class="caption">example 1</div>
<xi:include href="gameshow1.py" parse="text" encoding="iso-8859-1"/>
  </div>
 </div>
</body>
</Html>
 

  xi:include 元素被替換為完全轉義的 gameshow1.py (比如 清單 1)的內容,該文件是相對於元素的基 URL 進行解析的。感謝 parse="text" ,轉義是自動完成的。我總是使用 encoding 屬性(如果使用 parse="xml" ,偶爾可以忽略它)。在我的應用中,Python 文件通常使用“iso-8859-1”編碼,而 XML 文件使用“utf-8”編碼,當然,您的環境中可能使用不同的編碼。

 我在為 developerWorks(它要求作者以精心設計的 XML 格式提供文稿)撰寫這些文章時,使用的就是已解析文本 XInclude 技術,並發現這樣極大提高了編輯速度。

  另一個注意事項是:該書使用的是當時正在開發之中的 XInclude 名稱空間 http://www.w3.org/2003/XInclude ,但是現在,這個名稱空間已經不存在了。在 2004 年 4 月 13 日發布的 Candidate Recommendation 中,W3C 工作組又回到了原來的名稱空間 http://www.w3.org/2001/XInclude 。據我了解,多數工具只支持後一種(2001)名稱空間形式,這可能是 W3C 決定回到原來的名稱空間的原因,但這種名稱空間的變化和撤銷確實帶來了一些混亂。該書作者就成了這種變化的無辜的犧牲品,我已經就此向出版商提供了一份刊誤表。

  更簡單的恆等轉換

  第 37 章“Generate an XSLT Identity Stylesheet with Relaxer”討論一種相當復雜的生成 恆等轉換的方法,即輸出和源文檔等價的 XML 的 XSLT 轉換。在以這種方法得到的轉換中,對應詞匯表中的每個元素都有一個模板,這的確很復雜。這樣做可能是為了提供一個樣本,以便用於創建更專門的轉換,但我認為它沒有給出一種簡單得多的恆等轉換,甚至 XSLT 規范中都作為例子給出了這樣的一個轉換。在後一章(38)“Pretty-Print XML Using a Generic Identity Stylesheet and Xalan”中,討論了這種更簡單的恆等轉換,其中包括為了獲得整齊的打印效果而經常采用的 <xsl:output method="XML" indent="yes"/> 。我建議您首先閱讀第 38 章,熟悉簡單的恆等轉換之後,再來研究 37 章中那種復雜的方法。這樣做的還有一種好處,理解這種簡單的恆等變換是熟悉和掌握幾種 XSLT 短語的關鍵,包括將源節點復制到輸出中的 xsl:copy-of 與常見 XPath 節點測試的細微差別: * 、 @* 和 node() 。

不使用 XSLT 2.0 生成多個輸出文檔

  第 45 章“Generate Multiple Output Documents with XSLT 2.0”討論了如何使用 XSLT 2.0 xsl:result-document 在一次轉換中序列化多個結果樹。整章都寫得不錯,除了最後出現的一句:

如果您仍然在使用 XSLT 1.0,那麼還可以生成多個結果文檔,但是只能通過擴展特性做到這一點,而擴展特性隨著處理程序的不同而不同。

  這句話是不對的,這要感謝 EXSLT(請參閱 Resources),它是 XSLT 1.0 處理程序的標准擴展名集合。EXSLT 提供了 exsl:document 擴展,得到了一些比較流行的 XSLT 處理程序的支持。與 XSLT 2.0 中的等價機制相比,這種方法更簡單,照我的觀點來看,它更優美一些。(它源自 XSLT 2.0 Working Draft 早期草案中關於該特性的一個建議。)我不准備重復書中使用 exsl:document 的那個長例子。清單 6 是一個更簡單的例子,這個轉換將 XHtml 源文檔中的每個段落元素都寫入新的結果文檔中。

  清單 6. 將 XHtml 文檔中所有段落元素寫入結果文檔的轉換

  <?XML version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
 XMLns:xsl="http://www.w3.org/1999/XSL/Transform"
 XMLns:exsl="http://exslt.org/common"
 XMLns:html="http://www.w3.org/1999/xHtml"
 extension-element-prefixes="exsl">
 <xsl:template match="Html:p">
  <exsl:document href="para-{generate-id()}.xml" method="XML" indent="yes">
    <xsl:copy-of select="."/>
  </exsl:document>
 </xsl:template>
</xsl:stylesheet>
 

  exsl:document 元素很關鍵。它通知處理程序准備一個新的輸出樹,通常是創建一個新文件。 href 屬性是一個資源名,它是根據擴展元素的基 URI 進行解析的。我使用 generate-id() 函數來確保創建的每個文件的名稱都不會重復。 method="XML" 和 indent="yes" 只是為 xsl:output 定義的普通屬性,在這個擴展元素中,可以使用任何屬性。

  該書在第 58 章介紹了 EXSLT,“Use EXSLT Extensions”,但是要避免讀者留下這樣的印象已經太遲了:獲得多個結果文檔的惟一簡便方法就是轉向 XSLT 2.0。我建議您盡可能地堅持使用 XSLT 1.0,因為 XPath 2.0( XSLT 2.0 需要該標准)有一些不必要的復雜性。EXSLT 為 XSLT 1.0 用戶提供了幾乎所有 XSLT 2.0 中包含的有用功能,甚至更多。

  結束語

  XML Hacks是一本集合了一些方便的技巧和竅門的書籍。但它對一些特定工具似乎帶有某種強烈地、不必要地偏愛,而且在某些地方,文字也不很通順(對於多人合作的書籍,這並不鮮見),因此,很難看出某些章節的主旨是什麼。本文嘗試對書中不太清楚但非常重要的幾個問題進行補充,在下一期文章中,我將繼續進行更多地考察。

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