關於 XML 的一些基礎知識

1、HTML 的缺點以及 XML 的產生原因
HTML 最初是一種表義的標記語言。Tim Berners-Lee 最初發明 HTML 的主要目的是爲了與研究物理學的同事交流的方便(他當時是 CERN(歐洲粒子物理實驗室)的研究人員)。超鏈接可以很方便地把關於物理學研究的各種資源鏈接起來。HTML 最初只是設計用來交流文本信息的,最初的 HTML 顯示出來就是簡單的文本,沒有多少表示顯示格式的標記。Marc Andreessen 發現了 HTML 和超鏈接的商業價值,開發出了世界上第一個圖形界面的瀏覽器 NCSA Mosaic。Andreessen 隨後與別人合作開了 Netscape 公司,並且製造出當時最成功的瀏覽器 Netscape Navigator。爲了提高瀏覽器的表現能力,顯示更加豐富的內容,有必要擴充 HTML,添加各種與顯示格式有關的標記和屬性,並且把對多媒體的支持加進去。例如 <table>、<center>、<font>、<img>、align、bgcolor 等等。Netscape Navigator 大爲成功,尤其是在其後續版本推出強大的腳本語言 JavaScript、支持 plugin 並且能在頁面中運行 Java Applet 後。甚至有人認爲瀏覽器就是下一代的操作系統,將來開發的所有應用程序都應該是針對瀏覽器開發的(B/S 結構)。Netscape 是 1995 年 NASDAQ IPO(新股上市)最成功的公司,Marc Andreessen 一夜之間成爲了億萬富翁。這引起了軟件之王 M$ 的注意和警覺,M$ 認爲 Netscape 正在對其構成威脅,一定要把 Netscape 擊垮,佔據互聯網這個戰略制高點。而互聯網最重要的應用軟件就是瀏覽器,於是 M$ 推出了自己的瀏覽器 Internet Explorer,並且採用免費和捆綁等不正當競爭手段,在 5~6 年(從真正展開競爭的 1997 年 IE 3.0 推出並與 Windows 捆綁到 2003 年 AOL 徹底放棄 Netscape 瀏覽器)的時間裏將 Netscape 徹底趕出了瀏覽器市場。如今 Netscape 瀏覽器這個產品已經徹底滅亡,只留下了它開放源代碼後浴火重生的 Mozilla 繼續在與 IE 進行着頑強的抗爭。不過由於 Linux 桌面應用已經走向成熟,所以將來 Mozilla 也會有很好的前景,事實上支持 Mozilla 已經提上了很多 B/S 結構軟件開發商的議事日程。在 IE 與 Netscape 角力的幾年時間裏,兩大瀏覽器都爲了提高自己的表現能力各出奇招。他們不斷推出新的只有自己才支持的、互不兼容的 HTML 標記。W3C 爲了考慮工業界的需求也在不斷地擴充 HTML 規範,以求各種瀏覽器能夠有一個兼容的基礎。HTML 規範經歷了 2.0、3.2、4.0 等重要版本後已經非常龐大,完全背離了 HTML 最初設計主要用來表義的初衷,其中含有大量表示顯示格式的標記和屬性。結果是實現一個完全的 HTML 瀏覽器越來越困難和複雜,IE 和 Netscape 的規模都達到了 10M 以上。爲 HTML 減肥的呼聲越來越高。爲了解決這個問題,以利於 Web 的健康發展,W3C 設計了 XML。

XML 的設計思想來自於古老的 SGML(其實 HTML 的設計思想也是來自於 SGML)。SGML 是 IBM 創造的一個用於出版業的文檔格式標準,後來被 ISO 採納作爲國際標準(ISO 8879)。SGML 把文檔內容與文檔格式完全分離開,使得內容提供者的與排版人員的工作可以相互獨立。SGML 是一種非常嚴謹的標記語言,但是 SGML 的問題是過於複雜,一個基於 SGML 的出版系統開發成本高昂,價格不菲,只有象 IBM 一樣的大型企業纔有能力購買這樣的系統。SGML 過於重量級的特點使其完全不適合用於 Web 領域,而且 SGML 的設計完全是面向文檔的,而不是面向數據的,大量基於 Web 的應用是面向數據的應用。W3C 參考 SGML 設計了新一代的標記語言 XML,XML——可擴展標記語言是一種元語言(我們使用的 Eclipse 也可以稱做是一種元工具),它可以建造其它任意種類的標記語言。XML 實現了 W3C 最初設定的所有目標,輕量級、易於理解、擴展性好、平臺中立、兼顧文檔和數據。實際上 XML 規範只有幾十頁,只是 SGML 規範的 1/10 左右。

注:XML 1.0 規範的中文版可以在網上找到,地址是 http://lightning.prohosting.com/~qqiu/REC-xml-20001006-cn.html

2、XML 的外觀
我們來看看 XML 是什麼樣:

java代碼: 

 1 <book id="1">
 2     <title>XML 高級編程</title>
 3         <isbn>7-111-07315-0</isbn>
 4         <author>Didier Martin 等</author>
 5         <pages>944</pages>
 6 </book>


好了,這個就是 XML,如果你熟悉 HTML 的話學習 XML 不非吹灰之力。在 XML 中的可以自定義任意的標記。
一段最低要求的 XML(文檔或數據)只需要滿足以下 4 個要求:
a、所有的起始標記都必須有結束標記。對於空元素可以採用這種形式表示:
<img src="..." />
b、標記區分大小寫,起始標記與結束標記大小寫必須一致。
c、多個起始、結束標記之間不能發生順序錯誤,例如:
<title>
<isbn>
</title>
</isbn>
可以把 XML 看作一個堆棧,起始標記代表 push 操作,結束標記代表 pop 操作,所以必須採用後進先出的方式編寫 XML。
d、所有的屬性都必須有引號,引號可以是雙引號也可以是單引號。一般採用雙引號。

這就是最簡單的 XML 的規則,簡單吧?

XML 的內容當然不只這麼多,可以看看《無廢話 XML》以瞭解更多的內容。下面是一個更完整的 XML。

java代碼: 

  <?xml version="1.0"  encoding="ISO-8859-1"?>
  <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure 1.2//EN" "http://jetty.mortbay.org/configure_1_2.dtd">
  
  <!-- =============================================================== -->
  <!-- Configure the Jetty Server                                      -->
  <!-- =============================================================== -->
  <Configure class="org.mortbay.jetty.Server">
  
    <!-- =============================================================== -->
 10   <!-- Configure the Request Listeners                                 -->
 11   <!-- =============================================================== -->
 12 
 13   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
 14   <!-- Add and configure a HTTP listener to port 8080                       -->
 15   <!-- The default port can be changed using: java -Djetty.port=80     -->
 16   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
 17   <Call name="addListener">
 18     <Arg>
 19       <New class="org.mortbay.http.SocketListener">
 20         <Set name="Port"><SystemProperty name="jetty.port" default="8080"/></Set>
 21         <Set name="MinThreads">10</Set>
 22         <Set name="MaxThreads">100</Set>
 23         <Set name="MaxIdleTimeMs">30000</Set>
 24         <Set name="LowResourcePersistTimeMs">5000</Set>
 25       </New>
 26     </Arg>
 27   </Call>
 28 
 29   <!-- =============================================================== -->
 30   <!-- Configure the Contexts                                          -->
 31   <!-- =============================================================== -->
 32 
 33 
 34   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
 35   <!-- Add a all web application within the webapps directory.         -->
 36   <!-- + No virtual host specified                                     -->
 37   <!-- + Look in the webapps directory relative to jetty.home or .     -->
 38   <!-- + Use the webdefault.xml resource for the defaults descriptor   -->
 39   <!-- + Upack the war file                                            -->
 40   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
 41   <Set name="rootWebApp">root</Set>
 42   <Call name="addWebApplications">
 43     <Arg></Arg>
 44     <Arg><SystemProperty name="jetty.home" default="."/>/webapps/</Arg>
 45     <Arg>org/mortbay/jetty/servlet/webdefault.xml</Arg>
 46     <Arg type="boolean">true</Arg>
 47   </Call>
 48 
 49   <Call name="addWebApplication">
 50     <Arg>/gwwweb</Arg>
 51     <Arg>D:/WORK/gwwweb/webapps/default</Arg>
 52   </Call>
 53 
 54   <Call name="addWebApplication">
 55     <Arg>/publish</Arg>
 56     <Arg>D:/WORK/gwwweb/webapps/publish</Arg>
 57   </Call>
 58 
 59   <Call name="addContext">
 60     <Arg>/</Arg>
 61     <Set name="ResourceBase">D:/WORK/shljjnew/webapps/default</Set>
 62     <Call name="addHandler">
 63       <Arg><New class="org.mortbay.http.handler.ResourceHandler"/></Arg>
 64     </Call>
 65   </Call>
 66 
 67   <!-- =============================================================== -->
 68   <!-- Configure the Request Log                                       -->
 69   <!-- =============================================================== -->
 70   <Set name="RequestLog">
 71     <New class="org.mortbay.http.NCSARequestLog">
 72       <Arg><SystemProperty name="jetty.home" default="."/>/logs/yyyy_mm_dd.request.log</Arg>
 73       <Set name="retainDays">90</Set>
 74       <Set name="append">true</Set>
 75       <Set name="extended">false</Set>
 76       <Set name="buffered">false</Set>
 77       <Set name="LogTimeZone">GMT</Set>
 78     </New>
 79   </Set>
 80 
 81   <!-- =============================================================== -->
 82   <!-- Configure the Other Server Options                              -->
 83   <!-- =============================================================== -->
 84   <Set name="requestsPerGC">2000</Set>
 85   <Set name="statsOn">false</Set>
 86 
 87 </Configure>



事實上,這個就是我們做開發時使用的 Jetty 的配置文件中的一部分(刪除了一些內容以便於講解)。
在這個文件中:

java代碼: 

 1 <?xml version="1.0"  encoding="ISO-8859-1"?>


是所有 XML 文檔中都必須有的 XML 聲明,用途是告訴 XML 解析器文檔所遵從的 XML 規範的版本和使用字符集。目前 XML 規範的最高版本就是 1.0。除了 ISO-8859-1 外(這個就是缺省的字符集,所以也可以不寫),我們做開發時最常用的兩個字符集是 GBK 和 UTF-8。

包含在 <? ... ?> 中的內容叫做處理指令(Processing Instruction,PI),處理指令不是 XML 的一部分,它的作用是爲 XML 應用程序處理 XML 提供一些指示。注意,剛纔說的 XML 聲明雖然與處理指令很象,但是並不是處理指令。這個文檔中並沒有處理指令。我來舉一個處理指令的例子,例如在文檔中用到了 CSS 樣式單,那麼應該有這樣一個類似的處理指令:

java代碼: 

 1 <?xml-stylesheet href="style.css" type="text/css" ?>


這個處理指令就是告訴應用程序使用哪個樣式單來顯示 XML。

java代碼: 

 1 <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure 1.2//EN" "http://jetty.mortbay.org/configure_1_2.dtd">
 2 


是文檔類型定義(DTD),指出這個 XML 是哪一類的標記語言,應該遵從哪一類標記語言的定義。除了用 DTD 的方式來定義標記語言類型外還可以用 Schema 來定義標記語言的類型。例如:

java代碼: 

 1 <wjml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xxx.com/dagl wjml.xsd" xmlns="http://www.xxx.com/dagl">
 2 


這個 XML 中使用的是標準的 XML Schema。稍後我會詳細講解 DTD 和 Schema 的適用場合。

包含在 <!-- ... --> 中的內容是註釋,也不是 XML 的一部分,這個與 HTML 是相同的。

其它的內容都很容易理解了,注意看這個文檔是否完全滿足我上面講的 4 個條件。


3、處理 XML 的 API
基於 XML 的應用程序從邏輯上分成 3 個層次,下面是 XML 文檔或數據,中間是 XML 解析器,上面是 XML 應用程序。XML 解析器的作用是讀入 XML 文檔或數據,將 XML 建造(build)爲內存中的數據結構,便於應用程序處理,或者根據 XML 中包含的信息,調用應用程序提供的回調方法。由於 XML 是基於文本的,具有平臺中立性,各種語言都有相應的 XML 解析器。

處理 XML 的 API 有這幾種:DOM、SAX、JAXP、JDOM 和 DOM4J,這幾種是最常用的,還有其它的一些不常用的 API。其中 DOM 可以用於多種語言,SAX 可以用於 Java 與 C++,JAXP、JDOM 和 DOM4J 只能用於 Java。一個 XML 解析器至少需要實現 DOM 或 SAX 兩種 API 中的一種,不過現在常用的 Java XML 解析器都同時實現了 DOM、SAX 和 JAXP 3 種 API。JDOM 和 DOM4J 是由單獨的包(jar)來實現的,使用 JDOM 和 DOM4J 需要得到標準的 XML 解析器的支持。目前在衆多的 Java XML 解析器中使用最廣的是 Xerces 和 Crimson,它們都是開源軟件組織 Apache 軟件基金會資助的開源軟件。其中 Xerces 最初的代碼來自 IBM 的貢獻,Crimson 最初的代碼來自 Sun 的貢獻。JDK 1.4 以後的版本中已經包括有 XML 解析器,因此不再需要另外的 XML 解析器。IBM JDK 1.4 本帶的 XML 解析器是 Xerces 的早期版本,Sun JDK 1.4 本身帶的 XML 解析器是 Crimson 的早期版本(孩子總是自家的親)。不過即使使用 JDK 1.4,你仍然可以使用其它的 XML 解析器。在我們的開發中全部使用 Xerces,主要是因爲 Xerces 在所有 Java XML 解析器中功能是最豐富的,根據性能測試 Xerces 的性能要比 Crimson 好的多,而且我們在 Linux 上出於性能的考慮全部使用 IBM 的 JRE/JDK。

DOM 簡介:
DOM 對於 XML 的處理方式就是把整個 XML 讀到內存中形成一棵樹狀結構,然後用各種方法對這棵數進行遍歷、插入、刪除、修剪等操作。因爲 DOM 是 W3C 的正式標準,所有的語言都有支持 DOM 的解析器,包括 Java、C/C++、Perl、JavaScript 等等。DOM 的優點是信息量豐富(全部都在內存中),而且可以隨機訪問,尤其是在處理前後相互關聯的元素時非常方便。DOM 的缺點是 XML 應用程序在處理 XML 之前必須先由 XML 解析器把整個 XML 讀進內存並生成樹狀結構,如果 XML 非常大,例如 10M,解析的過程是非常慢的。如果再加上 XSLT 轉換(這是一種必須要使用 DOM 的操作)這類同樣耗費資源的操作,可能會耗盡系統的內存資源。所以標準 DOM 只適合於中小型 XML 的處理。

SAX 簡介:
爲了更好地解決大型 XML 處理的問題,Java 開發人員發明了 SAX。SAX 採用事件驅動的方式來處理 XML,它的處理方式是:爲每一個元素、屬性、內容(這些都認爲是事件)定義一個回調方法,這個回調方法由應用程序提供。解析器以數據流的方式讀入 XML,當遇到某個元素、屬性、內容時就調用相應的回調方法。SAX 的優點是處理效率高,適合處理大型 XML。缺點是 SAX 對 XML 是隻讀的,不能夠對 XML 進行寫操作,而且 SAX 處理 XML 中前後相互關聯的元素時也沒有 DOM 方便,因爲應用程序必須自己保留以前事件的狀態信息。但是 SAX 還是取得了巨大的成功,後來 SAX 還被移植到了 C++ 等語言中。SAX 更詳細的優缺點可以查看《XML 高級編程》第 6 章的內容,我們這裏有這本書的電子版。

JAXP 簡介:
你們對 XML 熟悉了以後可能會經常聽到 JAXP 這個詞。JAXP 其實不是一個獨立的 XML API,它的作用是爲了解決不同的 XML 解析器之間的兼容性問題的。在 Sun 推出 JAXP 之前,商業公司(IBM、Oracle、Sun,etc.)、XML 專業研究者以及開源軟件愛好者開發出來多種多樣的 XML 解析器。這些解析器有的僅僅實現了 DOM API,有的同時實現了DOM 和 SAX。在我學習 XML 的過程中,我所知道的 Java XML 解析器就有 7、8 種。這些不同的 XML 解析器各有各的特長,它們雖然都遵從 W3C DOM 或 SAX 的規範,但是或多或少存在着一些差別,這使得爲一種解析器編寫的應用程序移植到另一種解析器變得有些困難(也不是非常困難,只是不太方便)。爲了解決這個問題,Sun 在 DOM、SAX 的 API 之上加了一個抽象層(基本上就是加了一個抽象工廠的設計模式,如果你們對設計模式有所瞭解的話),這就是 JAXP。JAXP 主要採用反射的方式來工作,可以動態加載所使用的 XML 解析器。使用 JAXP 來做 XML 開發,可以完全忽略不同的 XML 解析器之間的差別,不需要修改代碼就可以更換成另外的 XML 解析器。JAXP 目前已經得到大多數 Java XML 解析器的支持。除了封裝 DOM、SAX 的那些工廠類外,JAXP 還包含用於 XSLT 轉換的 API(也是一些工廠類),這些功能在 javax.xml.transform 這個包裏。

JDOM 簡介:
除了 SAX,Java 開發人員還發明瞭 JDOM。雖然名字裏有 DOM,JDOM 其實與 DOM 毫無關係。JDOM 嚴格說來其實是一種對象模型,除了處理 XML,還可以用於很多其它用途。JDOM 的輸入可以有多種格式,輸出也可以有多種格式。這些格式包括 XML 文件或數據流、Java 屬性文件、標準 DOM 樹等等。JDOM 利用 SAX 或 DOM(一般是用 SAX,極少用 DOM)讀入 XML 中的信息後在內存中生成自己的數據結構,就是通過組合(composition)關係嵌套在一起的一系列對象,然後用 Java 程序員最習慣的面向對象的方式來處理這些數據,處理結束後可以非常方便地輸出成各種格式。和 DOM、SAX 相比,用 JDOM 來做 XML 開發更加容易(代碼量更少)。JDOM 的主要的缺點是最初的設計未考慮性能問題,因此性能很差,而且全部使用具體類來實現導致了靈活性較差,但是考慮到易用性和開發效率,JDOM 仍然得到了廣泛的使用。

DOM4J 簡介:
由於 JDOM 本身存在着一些設計缺陷,開發到一半,JDOM 的一些開發人員分了出來重新啓動了一個開源項目 DOM4J。DOM4J 與 JDOM 所要達到的目標是一樣的,即提供一套比 DOM、SAX 使用更加方便的處理 XML 的 API,同時避免 DOM、SAX 的主要缺點。DOM4J 重新做了設計,完全基於接口和多態,因此提高了靈活性。DOM4J 在概念上對 XML 的理解與 DOM 非常相似,只要你理解了 DOM,你就可以輕而易舉地理解 DOM4J,實際上 DOM4J 可以看做是一個更好的 DOM 實現。而且 DOM4J 保持了 JDOM 的易用性,性能上也比 JDOM 有了非常大的提高。最值得一提的是 DOM4J 完全支持 XPath,看看 DOM4J 的這段代碼:

java代碼: 

 1 List list = document.selectNodes( //foo/bar );
 2 Node node = document.selectSingleNode(//foo/bar/author);
 3 


這與我們前臺寫的 JavaScript 是非常相似的,我們學會 DOM4J 是幾乎不需要花什麼時間。
DOM4J 與 JDOM 一樣,通過 SAX 或 DOM(一般用 SAX)讀入 XML 中的信息在內存中生成自己的數據結構,因此 DOM4J 至少需要一個實現了 SAX 的 XML 解析器,我們可以直接使用 Xerces。
由於 DOM4J 具有易用性、性能、靈活性、功能強大等多方面的優勢,今後我們如果需要在服務器端做 XML 開發,DOM4J 將是我們主要採用的工具。

關於這幾種 API 的詳細內容,請參考《Java 與 XML》和《XML 高級編程》。關於 DOM4J,主要有這些資料:
http://dom4j.sourceforge.net/faq.html
http://www.csdn.net/develop/article/22/22753.shtm

聽了我上面的介紹你們可能會覺得 DOM 是比 SAX 更基礎的 API,因爲它是 W3C 的標準,所有的語言都支持,而 SAX 的使用僅侷限於少數幾種語言。某種程度上你是對的,但是在 Java 的世界裏,SAX 是比 DOM 更加基礎的 API。由於 SAX 處理效率很高,SAX 的應用範圍比 DOM 更廣。例如:我們中間件的低層框架 Avalon(也是 Apache 軟件基金會的產品)處理 XML 配置文件時使用的就是 SAX。另外,因爲 W3C 並沒有規定在內存中如何生成一棵 DOM 樹(W3C 只規定了如何操作這棵 DOM 樹),Xerces 採用高效率的 SAX 來讀入 XML,然後生成 DOM 樹。因此當你在用 Xerces 做 DOM 開發時發現經常需要捕獲 SAXException 就沒什麼可奇怪的了。JDOM 和 DOM4J 通常也是使用 SAX 讀入 XML,然後生成自己的數據結構。對於 JAXP、JDOM 和 DOM4J 來說,DOM 和 SAX 都是基礎的 API。

在我們公司做開發最常接觸的 XML 開發是使用 JavaScript 做 DOM 開發,因爲時間有限,所以我今天只詳細講一下在前臺使用 JavaScript 和 DOM API 做 XML 開發的過程。今天的目的主要是讓大家對於 XML 相關的知識有一個整體的瞭解。

大家知道 JavaScript 是嵌入在瀏覽器中的,創建 DOM 樹不是 JavaScript 的責任,瀏覽器已經創建好了,另外通常 JavaScript 也不能直接讀寫 XML 文件(在權限許可的情況下 JavaScript 可以讀寫本地文件)。JavaScript 處理的 XML 數據有兩個來源,一個是來自於頁面中的 XML 數據島,另外一個是來自於從 XMLHTTP 接口接收的後臺發來的 XML 數據。注意:在瀏覽器中的 DOM 有兩種,HTML DOM 和 XML DOM。如何處理 HTML DOM 在普通的 JavaScript 教材(《JavaScript 權威指南》等等)中已經講得很詳細了,我這裏只詳細講一下如何處理 XML DOM,下面所說的 DOM 都是指 XML DOM。在講 XML DOM 之前我首先要講一下 XPath。

什麼是 XPath?簡單地說,XPath 就是定位 XML 中某些節點(元素、屬性、內容、處理指令、文檔類型定義、註釋)的方法。XPath 的目的是爲 XSLT 和 XPointer 提供一個共同的、整合的語法,用來對應 XML 的各個部分,選擇 XML 中的某個或某些節點。XPath 是在 DOM 樹中查找節點、做 XSLT 轉換、定義文檔內部指針(XPointer)的基礎。有時候也把一個符合 XPath 規範的表達式稱做一個 xpath。我們通常把 XPath 表達式的結果稱爲一個節點集(node set)。節點集能夠被轉換、複製、忽略或執行其它的合法操作。XPath 除了包括定位語法外還包括很多函數定義,這些函數分成 4 類:節點集函數、字符串函數、布爾函數和數值函數。節點集函數,例如 position() 和 count(),通常以節點集作爲輸入(以 XPath 表達式的形式),然後做進一步處理。其它 3 種類型的函數,例如 substring()、not() 和 round() 提供基本的字符串處理、邏輯運算和數值運算的功能。關於 XPath 中各種函數定義的詳細內容可以參考《XML 高級編程》這本書。所有這些表達式語法或函數定義都是 XPath 規範或實現的一部分。

好了,長話短說,我在這裏主要講一下 XPath 如何使用。其實我們需要知道的基本上就是《無廢話 XML》中表 7.1 的內容。
XPath 的定位語法與操作系統目錄結構的語法非常相似。也分成兩種,相對路徑與絕對路徑。相對路徑從當前正在處理的節點開始,絕對路徑從文檔的根節點開始。我來舉些例子:

java代碼: 

  A                                        對應當前節點下所有名爲 A 的子元素。
  *                                        對應當前節點下所有子元素。
  */A                                        對應自當前節點開始,所有名爲 A 的孫元素。
  @A                                        對應一個附屬於當前節點,名爲 A 的屬性。
  @*                                        對應所有附屬於當前節點的屬性。
  text()                                對應當前節點的子元素中的所有文本節點。
  .                                        對應當前節點
  ..                                        對應當前節點的父節點。
  A[1]                                對應當前節點下,第一個名爲 A 的子元素。
 10 A[position()=1]                作用同上。
 11 A/[@B="true"]                對應當前節點下所有名爲 A 的子元素,這個子元素必須含有一個名爲 B 的屬性,其屬性?當匭?爲 "true"。
 12 A|B                                        對應當前節點下,所有名爲 A 或 B 的子元素;| 代表“或”的關係。
 13 .//A                                對應當前節點下,所有名爲 A 的元素;// 符號代表可跨?絞?。
 14 A//B                                對應到所有名爲 B 的元素,它們的上級(可跨?絞叮?必須有一個名爲 A 的元素,而且 A 元素必須是當前節點的子元素。
 15 /A                                        對應根節點下所有名爲 A 的子元素。
 16 //A                                        對應根節點下所有名爲 A 的元素。A 元素可以在任意層次。
 17 



我們在做前臺開發時,有兩個方法會用到 XPath,selectSingleNode() 和 selectNodes()。這兩個方法是 IE 的擴展,不屬於 W3C DOM 規範,但是使用起來非常方便,所以我們在 DOM4J 中也可以看到這兩個方法。

java代碼: 

 1 hwn.__drTags = sr1.selectSingleNode("./tag");
 2 var cxn = xn.selectNodes("./*[not(@m:f) or @m:f!='d']");



上面是從我們的前臺開發框架中 copy 出來的代碼。
selectSingleNode 用於獲得一個節點,如果有多個節點滿足條件,返回的是第一個節點。
selectNodes 用於獲得節點集,返回的結果是包含所有滿足條件節點的數組。

第二條語句的參數看起來有些複雜,它的意思是找到 xn 節點下所有不包含 m:f 屬性或者包含 m:f 屬性,但屬性值不等於 'd' 的所有子元素。


下面我來詳細講解 XML DOM 在 JavaScript 中的實現。
在瀏覽器中,無論 XML 的數據來源如何,最後都會由瀏覽器生成一棵 DOM 樹。這棵 DOM 樹所對應的對象類型爲 XMLDocument,這棵 DOM 樹上的所有節點(包括根節點)都是 XMLNodes 類型的對象。事實上 XMLDocument 也是 XMLNodes 的子類,所以你可以在任何一種 XMLNodes 派生出的對象上調用 selectSingleNode 和 selectNodes。

數據來自 XML 數據島:
例如在頁面中有這樣一個 XML 數據島,
<xml id="book">
...
</xml>

var xd = book.XMLDocument;

通過外部 XML 文件創建新的 DOM 樹:
var xd = new ActiveXObject("Microsoft.XMLDOM");
xd.load(data.xml);

或者將外部文件中的數據加載到 XML 數據島:
var xd = book.XMLDocument;
xd.load(data.xml);

注意:load() 這個方法的參數可以是任意合法的 URL,不一定限制爲文件名。

將數據保存到 XML 文件用
xd.save(data.xml);

通過字符串創建新的 DOM 樹:
var xd = new ActiveXObject("Microsoft.XMLDOM");
xd.loadXML("<"+hd.__hwnodes.style.rootTag+"></"+hd.__hwnodes.style.rootTag+">");


數據來自 XMLHTTP:
var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.open("GET","/hwsvr2/qe",false);
xmlhttp.send(null);
var xd = xmlhttp.responseXML;

得到 XML 文檔的根節點:
var xn = xd.documentElement;


我再來說說在 Mozilla 中創建 XML DOM 樹的方法,將來我們有可能會爲 Mozilla 開發頁面,所以對於如何保持腳本的兼容性有些瞭解是有好處的,這部分內容不是必須掌握的內容。
Mozilla 中並沒有 IE 的 XML 數據島這個概念,不過在 Mozilla 中模擬 XML 數據島是非常容易的,這裏有這方面的資料:
http://www.mozilla.org/xmlextras/xmldataislands/
感興趣的可以看看。

Mozilla 中內建有對 XML DOM 的支持,並沒有使用 ActiveX 之類外掛的方式(被 Mozilla 開發者譏笑爲打補丁的方式)。在 Mozilla 中訪問創建好的 DOM 樹的方法與 IE 中基本上是一樣的,所不同的是創建 DOM 的過程,Mozilla 採用的方法都是符合 W3C 標準的方法:

通過外部 XML 文件創建新的 DOM 樹:
var xd= document.implementation.createDocument("","",null);
xd.load("data.xml");

第一個參數是名字空間的 URL,第二個參數是 DOM 根元素名稱,第三個參數是定義 XML 格式的 DTD。在這裏這 3 個參數都可以不提供。

Mozilla 中沒有 loadXML() 這個簡單的方法,但是可以手工爲 Mozilla 添加這個方法,詳細信息在這裏:
http://webfx.eae.net/dhtml/xmlextras/xmlextras.html

數據來自 XMLHTTP:
var xmlhttp=new XMLHttpRequest();
xmlhttp.open("GET","/hwsvr2/qe",false);
xmlhttp.send(null);
var xd = xmlhttp.responseXML;


得到 XML 文檔的根節點:
var xn = xd.documentElement;

由上面可以看到只要創建了 XML DOM 樹後,訪問方法 IE、Mozilla 是完全一樣的,這部分的差異非常容易通過封裝的方法屏蔽掉。Mozilla 沒有提供 selectSingleNode() 和 selectNodes() 兩個方法,以前我寫過這兩個方法在 Mozilla 上的實現,貼在論壇上,感興趣的可以看看:
http://forum.hibernate.org.cn/viewtopic.php?t=965


下面我來講講訪問 DOM 樹常用的方法。

剛纔我們說到過,DOM 樹的訪問有兩個級別,文檔級別和節點級別。

在文檔級別,XMLDocument 對象上有這些方法:
abort():終止正在進行的異步下載
getElementByTagName():根據標記名稱查找當前節點的子元素。
load():從指定位置下載 XML。
save():將 XML 保存到指定位置。

XMLDocument 對象上有這些屬性:
async:指出 XML 是否可以異步下載。
doctype:返回 XML 的 DTD 節點。
documentElement:返回 XML 的根元素。
parseError:返回包含 parse error 信息的對象。

在節點級別,XMLNodes 對象上有這些方法:
createElement():在當前節點下創建一個子元素。
createTextNode():在當前節點下創建一個內容節點。

appendChild():在當前節點上添加新的子節點。
cloneNode():複製一個節點,返回值爲生成的新節點。
hasChildNodes():當前節點是否爲葉節點。
insertBefore():在某節點前插入新的節點。
removeChild():刪除當前節點的子節點。
replaceChild():替換當前節點的子節點。

XMLNodes 對象上有這些屬性:
childNodes:包含所有的子節點數組。
firstChild:當前節點的第一個子節點
lastChild:當前節點的最後一個子節點
nextSibling:當前節點的下一個兄弟節點
nodeValue:節點值
ownerDocument:當前節點對應的 XML 文檔
parentNode:當前節點的父節點。
parentElement:父元素的句柄。
xml:從當前節點開始子樹所生成的 XML。這個屬性只有 IE 支持。

對於所有的元素節點,可以使用這兩個方法:
setAttribute():設置當前元素的屬性。
getAttribute():獲得當前元素的屬性。
clearAttributes():清除當前元素的所有屬性。

另外還有 selectSingleNode() 和 selectNodes(),這兩個方法其實是最常用的了。由於 XML DOM 中可以使用強大的 XPath 查找你想要查找的任意節點,比 HTML DOM 中僅能用 all()、getElementById()、getElementByTagName() 幾個功能有限的方法方便得多。
只要你理解了 DOM 的概念,並且沒有忘記以前學的數據結構的知識,上面的這些方法理解起來是非常簡單的,我就不細講了,關鍵是要經常使用,熟能生巧。


4、XML 有效性驗證的方法和名字空間
符合第 2 部分講的 4 個條件的 XML 叫做格式正確的(well-formed)XML。還有一種有效的(valid)XML。什麼叫做有效的 XML 呢?
有效的 XML 就是通過某種格式定義來規定這個 XML 中只能有哪些元素、這些元素應該按照什麼順序出現,每個元素有哪些屬性,這些屬性的數據類型、取值範圍等信息。然後這一類的 XML 只要通過驗證符合這個格式定義就認爲是有效的 XML。那麼爲什麼 XML 需要通過驗證,這主要是電子商務的需要。舉個例子,如果你需要通過 Web 方式與客戶進行 B2B 交易,你把電子形式的發票發給客戶,客戶也會把他們的發票發給你,但是兩種發票的格式不同,就好象你在說漢語他在說英語,彼此無法正常交流,所以必須要有一個統一的格式(標準)才能夠開展正常的電子商務活動。XML 就是靠不同類型的格式定義來建造不同的標記語言的,每一種格式定義(標記語言)叫做一種詞彙表(vocabulary)。

XML 的格式定義有很多種方法,包括 DTD、XML Schema、RELAX NG 等等。DTD 是參考 SGML DTD 創造出的 XML 格式定義方法。DTD 的格式定義採用與 XML 不同的語法,這使得很難直接用解析器來解析 DTD,也很難動態(runtime)驗證 XML 的有效性。W3C 後來又創造了 XML Schema。Schema 是一種新型的 XML 格式定義方法,它完全採用 XML 語法,便於解析器處理,而且對於數據格式的定義更加嚴格和精確,所以 Schema 更加適合面向數據的應用。現在的 XML 解析器一般都支持做 DTD 驗證,也有同時支持做 DTD 和 Schema 驗證的,例如我們使用的 Xerces。那麼有了 Schema 是否我們就可以完全拋棄 DTD 呢?答案是否定的,由於 DTD 來自於 SGML,它非常適合面向文檔的應用(SGML 完全是爲文檔處理而設計的)。定義相同的 XML 格式,DTD 定義要比 Schema 簡練的多,Schema 定義則顯得很冗長,所以 DTD 更加適合面向文檔的應用,不過把 Schema 用於面向文檔的應用也不會有多大的問題。因爲 Schema 的格式定義很煩瑣,所有有人開發出了其它的格式定義方法,其中比較有前途的是 RELAX NG。RELAX NG 是一種以 RELAX(由日本人開發)與 TREX(由 XML 界的權威 James Clark 開發)爲基礎的模式語言。它的基本思想與 Schema 相同,也採用 XML 格式,所以程序處理起來也很方便,而且它的語法比 Schema 要簡單的多。但是目前 RELAX NG 還不是 W3C 的標準,所以大多數解析器都不支持(需要使用專門的軟件包)。我的看法是 Schema 可能會在今後參考 RELAX NG 而得到簡化,所以我們還是應該更多地使用 Schema。

現在我來講一下名字空間這個非常重要的概念。名字空間(namespace)在 XML 中的作用其實與 package 在 Java 中的作用非常象。XML 是一種元語言,可以建造出無窮多種標記語言。有些時候需要在同一個 XML 文檔中混用不同類型的標記語言,但是這些不同類型的標記語言中可能有重複的標記,例如:我爲書籍分類建造了一種標記語言,其中有 <title> 這個標記;我又爲影片分類建造了一種標記語言,其中也有 <title> 這個標記。但是在我的 XML 文檔中需要同時包含書籍和影片兩類的數據(假設這個 XML 文檔其實是用戶的一個購物車,他同時買了書和 DVD),我如何區分一個 <title> 究竟是書籍的 title 還是影片的 title 呢?這時候名字空間就可以幫你了。名字空間就是一個元素前綴與 URI 之間的一種映射關係。名字空間是用一個 XML 元素加上一個前綴組成的,比如 <book:title> 和 <picture:title>。這樣 XML 解析器可以在不使用不同的元素名字的情況下,區分上述兩個元素名字。元素前綴可以爲任意字符串,最終一個 XML 文檔中的每個元素前綴要映射到一個唯一的 URI,這個 URI 就是不同的 XML 詞彙表的標識。除了用於元素,名字空間同樣也可以用於屬性(下面我們馬上可以看到)。名字空間經常在 XML 文檔中使用,也可以在 Schema 及 XSLT 樣式單或者 XML 有關的規範中使用。下面我們看一下名字空間的具體使用方法:

java代碼: 

 1 <?xml version="1.0" encoding="gbk"?>
 2 <DocRoot xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation="http://www.xxx.com/dagl ./../mlzx/schemas/dz/wjnr.xsd" xmlns="http://www.xxx.com/dagl">
 3         ...
 4 </DocRoot>



我們可以看到在這個 XML 中聲明瞭兩個名字空間。聲明名字空間使用 xmlns:前綴=URI 的形式,其中前綴也可以沒有,用來設置 XML 文檔缺省的名字空間。可以在任何元素上聲明名字空間,聲明後名字空間在該元素管轄範圍(作用域)內起作用。在這個 XML 文檔中使用了 Schema 來做有效性驗證,因此必須聲明 Schema 的名字空間。前綴可以是任意字符串(通常使用 xsi),但是這個名字空間所對應的 URI 是固定的,代表的是一個 Schema 的實例(Schema 與 XML 文檔的關係就象是類和對象的關係一樣)。名字空間聲明後立即可以使用,所以在後面緊接着用這個名字空間前綴 xsi 設置了一個屬性 schemaLocation,這個屬性用來設置 Schema 文件的路徑。xmlns="http://www.xxx.com/dagl" 中沒有前綴設置了文檔的缺省名字空間,也就是說在本文檔中所有沒有前綴的元素、屬性都屬於這個缺省的名字空間。

我們再來看看在 Schema 文件中使用名字空間的情況:

java代碼: 

  <?xml version="1.0" encoding="gbk"?>
  <schema xmlns="http://www.w3.org/2001/XMLSchema"
          xmlns:dagl="http://www.xxx.com/dagl" 
          targetNamespace="http://www.xxx.com/dagl" 
          elementFormDefault="qualified">
  
      <complexType name="attrType">
          <simpleContent>
              <extension base="string">
 10                 <attribute name="code_category" type="string" />
 11                 <attribute name="id" type="string" />
 12             </extension>
 13         </simpleContent>
 14     </complexType>
 15 
 16     <complexType name="dmType">
 17         <sequence>
 18                     ...
 19                 <element name="flh" type="dagl:attrType"/>
 20                     ...
 21         </sequence>     
 22     </complexType>
 23         ...
 24 </schema>


這個摘自剛纔那個 XML 文檔對應的 Schema。我們看到這個 Schema 中除了缺省的名字空間外還聲明瞭一個前綴爲 dagl 的名字空間,而且這個名字空間的 URI 必須與 targetNamespace 的 URI 相同。我把 Schema 規範設置爲缺省名字空間是爲了簡化編寫 Schema 定義,如果不這樣做,那麼每一個 complexType、sequence、element 都需要加上前綴(通常使用 xsd),那樣是很麻煩的。targetNamespace 用來定義相應的 XML 文檔(XML 實例,xsi)應該遵守的名字空間,也就是 XML 實例的缺省名字空間。爲什麼要這樣做我不細講了,這裏的規則就是在 Schema 中自定義的類型(這裏是 attrType)使用時必須加上名字空間前綴,這個前綴對應的名字空間 URI 必須與 targetNamespace 的 URI 相同。

現在我們對於 DTD、Schema、名字空間的作用都有了比較清晰的瞭解。在這一部分需要重點掌握的是名字空間的作用和使用方法。做 DTD、Schema 驗證的具體方法可以看我發在 bbs 上的文章:介紹一下做 Schema 驗證和 DTD 驗證的方法
http://forum.hibernate.org.cn/viewtopic.php?t=859
用 Xerces 來做 DTD 和 Schema 驗證是非常簡單的。想要更詳細地瞭解 DTD 和 Schema 的開發方法可以看《XML Schemas》和《XML 高級編程》這兩本書。
因爲性能上的原因,大部分情況下我們做 XML 開發時是不需要驗證 XML 的有效性的。不過我們將來有可能會開發自己的 XML 詞彙表,所以我們還是有必要學習相關知識的。我們將來主要會採用 Schema,需要重點學習這方面的知識,DTD 僅僅作爲需要了解的知識。還有一個採用 Schema 而不採用 DTD 的重要原因是 DTD 不支持名字空間。由於 DTD 來自於 SGML,SGML 中完全沒有名字空間的概念,因此 DTD 也完全不能識別 XML 中的名字空間。如果在 XML 中使用了包含了前綴的元素名,例如 <book:title>,用 DTD 做有效性驗證時就會出錯,DTD 頑固地認爲你必須在相應 DTD 文件中定義一個 book:title 元素才行(它不會認爲這個 book:title 其實就是一個 title)。而 Schema 完全支持名字空間,正是因爲這個原因,而且考慮到名字空間的重要性,雖然目前 Schema 還存在缺陷,我們還是應該堅持使用 Schema 而不使用 DTD。

在目前階段,只需要掌握好名字空間就可以了。Schema、DTD 等內容可以在需要的時候再去學習。

5、XML 與顯示的結合
第 1 部分說到過,XML 的設計目標就是把內容與顯示格式分離開。其實只有面向文檔的應用纔有顯示的需求,面向數據的應用不需要定義顯示格式。把內容與顯示格式分離不僅有利於面向文檔應用的開發,更有利於面向數據應用的開發。我來舉個面向數據應用的例子,假設你做了一個 Web 搜索引擎(或者叫做網絡爬蟲),如果頁面採用 HTML 來開發,當你的程序讀到這樣的信息:

java代碼: 

 1 <tr>
 2         <td>XML 高級編程</td>
 3         <td>95.00</td>
 4 </tr>


你的程序能辨別出這其實是一本書的名稱和價格嗎?尤其是當這些單純表示格式的 <tr>、<td> 以不規則方式嵌套了很多層的時候,開發出一個支持 HTML 全文檢索的搜索引擎簡直是一場災難。但是如果這些頁面都是採用 XML 來開發的,並且內容與顯示格式完全分離,當你的程度讀到這樣的信息:

java代碼: 

 1 <book>
 2         <title>XML 高級編程</title>
 3         <price>95.00</price>
 4 </book>


就可以非常容易地辨別出這是一本書的名稱和價格,尤其是當這個 XML 頁面使用了通用的詞彙表並且通過了有效性驗證時。所以 XML 就是搜索引擎開發者的福音,XML 還會催生出一大堆面向數據的應用,而這類應用在 XML 出現前是根本無法實現的。

言歸正傳,現在我們來談談面向文檔的應用。那麼顯示格式用什麼來定義呢?有兩種方法,CSS 和 XSLT,XML 文檔要在瀏覽器中顯示必須結合 CSS 或者 XSLT 的樣式單。XML 文檔與 HTML 一樣可以用 CSS 來定義顯示格式(這裏有個例子:http://www.wespoke.com/atom.xml)。
我們先看一下上面這個例子中如何用 CSS 來定義顯示格式:

java代碼: 

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <?xml-stylesheet href="/css/atom.css" type="text/css"?>
 3 <feed>
 4         ...
 5           <entry>
 6                   ...
 7           </entry>
 8         ...
 9 </feed>


其中

java代碼: 

 1 <?xml-stylesheet href="/css/atom.css" type="text/css"?>


是與樣式單相關的處理指令,指出本文檔使用哪一個樣式單來定義顯示格式,如果用 CSS 來定義,type 就是 "text/css",用 XSLT 來定義,type 就是 "text/xsl"。

下面是其對應的 CSS 文件中的一段:

java代碼: 

1 entry {
 2         display: block;
 3           border: 2px solid black;
 4           margin: 1em;
 5           padding: 0.5em;
 6 }


可以看出,這段 CSS 與我們在 HTML 中使用的 CSS 沒有什麼區別。而且通過這段 CSS 可以想象出,瀏覽器在將在 entry 之外顯示 2 個象素寬的邊界。瀏覽器顯示的結果與我們想象的完全相同(1.jpg)。


下面我來講一講 XSLT,因爲在 XML 的世界裏 XSLT 是比 CSS 更加重要的技術。現在最流行的 XML 文檔的顯示方法還是 XSLT。原因與 Schema 一樣,XSLT 採用 XML 格式(CSS 採用自己的語法),可以用相同的 XML 解析器解析,便於程序處理。

XSLT 是參考 SGML 中的 DSSSL(定義 SGML 的顯示格式)而設計的。最初叫做 XSL,但是後來 W3C 發現工作量實在太大就分成了兩個規範:XSLT 和 XSL:FO。XSLT 很快就作爲正式規範推出了,主要是面向轉換類應用的;XSL:FO 主要是面向精確的格式定義(例如 PDF),正式規範才推出不久。我們主要用到 XSLT,因爲 XSLT 目前已經達到了實用的階段並且被廣泛採用。XSLT 其實不完全是爲顯示目的設計的,XSLT 的主要作用是將 XML 由一種格式轉換爲另一種格式,例如由 XML 的一種詞彙錶轉換爲另一種詞彙表,或者由 XML 轉換爲 HTML 或者 XHTML,便於在瀏覽器中顯示。後一種應用(XML->HTML/XHTML)是目前 XSLT 應用最廣的領域,被應用於很多符合 J2EE 標準的表示層框架中。這類框架在服務器端做 XSLT 轉換,將生成的 HTML/XHTML 發給瀏覽器。基於這種技術的框架還可以非常方便地支持各種瘦客戶端,例如 PDA 或具有無線上網功能的 WAP 手機(這時候是 XML->WML,也就是由一種詞彙錶轉換爲另一種詞彙表,WML 本身就是 XML 的一種詞彙表),無非就是另外再寫一套 XSLT 樣式單。在這種應用中,只包含數據的 XML 相當於 MVC 中的 Model,而表示顯示格式的 XSLT 相當於 MVC 中的 View。還有一些需要在服務器定期生成靜態頁面的網站(例如新浪這類新聞網站)也在服務器採用 XML+XSLT 來定期生成靜態頁面(這類進程一般是以後臺方式運行)。

現在 IE 和 Mozilla 兩大瀏覽器都可以很好地支持 XSLT,所以從技術上講可以完全採用 XML+XSLT 來製作所有的頁面。在這裏 XML+XSLT 與我們熟悉的 HTML+CSS 的功能大致相同。這也引起了另外的一種思考,究竟是在服務器端做 XSLT 轉換好還是在瀏覽器端做 XSLT 轉換好?我的考慮是儘管在服務器端做 XSLT 轉換更加靈活,功能更加強大,我卻更願意在瀏覽器端做轉換。因爲 XSLT 轉換是非常耗費資源的操作,如果在服務器端做大量的轉換操作必然會極大地影響服務器的性能。必須要在服務器端做轉換的話一個更好的方案是採用後臺方式定期生成靜態的 HTML 頁面(也就是上面說的一些新聞網站所採取的做法),或者在服務器端通過軟件實現某種 cache。這也符合我們一貫的思路:瀏覽器其實能做很多事情,而且現在主流機型(P4 2G、256M 以上內存)的處理能力已經非常強了,所以在瀏覽器力所能及的情況下應該把儘量多的工作交給瀏覽器去做。

就象剛纔講的 XML+CSS,我們來直觀地看一下 XML+XSLT 是什麼樣子:

XML 文檔 test.xml:

java代碼: 

  <?xml version="1.0" encoding="gbk"?>
  <?xml-stylesheet href="test.xsl" type="text/xsl"?>
  <產品搜尋>
          <摘要>搜尋字串:“滑鼠 鍵盤”,共找到 2 筆</摘要>
          <產品>
              <貨號>12478943</貨號>
              <品名>手不痛健康滑鼠</品名>
              <定價>$234</定價>
              <說明頁 網址="http://foo.bar/mouse/12478943">上市發表會</說明頁>
 10           </產品>
 11           <產品>
 12             <貨號>83424723</貨號>
 13             <品名>打不響靜悄悄鍵盤</品名>
 14             <定價>$567</定價>
 15             <說明頁 網址="http://foo.bar/kbd/83424723">產品特性</說明頁>
 16         </產品>
 17 </產品搜尋>



XSLT 樣式單 test.xsl:

java代碼: 

  <?xml version="1.0" encoding="gbk"?>
  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output encoding="gbk"/>
  
  <xsl:template match="/">
          <html>
            <head>
                    <title>產品搜尋結果</title>
            </head>
 10           <body>
 11             <h1>產品搜尋結果</h1>
 12             <p><b>摘要:</b><xsl:value-of select="*/摘要"/></p>
 13             <xsl:apply-templates select="產品搜尋"/>
 14           </body>
 15           </html>
 16 </xsl:template>
 17 
 18 <xsl:template match="產品搜尋">
 19           <table>
 20             <tr>
 21                       <th>品名</th>
 22                       <th>定價</th>
 23                       <th>說明頁</th>
 24             </tr>
 25                   <xsl:for-each select="產品">
 26             <tr>
 27                       <td><xsl:value-of select="品名"/></td>
 28                       <td><xsl:value-of select="定價"/></td>
 29                       <td><a href="{說明頁/@網址}"><xsl:value-of select="說明頁"/></a></td>
 30             </tr>
 31                   </xsl:for-each>
 32           </table>
 33 </xsl:template>
 34 
 35 </xsl:stylesheet>



這個例子是一個可以在 Mozilla 中正常顯示的 XML 頁面(2.jpg),從這個完整的例子中可以對我們剛纔學到的知識產生很多感性認識。
a、XML 中的元素、屬性名都可以使用中文,只要在 XML 聲明中使用了正確的 encoding(這裏是 gbk)。
b、在 XSLT 樣式單中大量採用 XPath 語法來定位 DOM 中的節點並且對符合條件的節點進行轉換。事實上 XPath 的產生最初就是因爲 XSLT 的需要。
c、在 XSLT 樣式單中同樣可以使用名字空間。
d、XML 經 XSLT 轉換後輸出內容爲標準的 HTML 頁面,可以在瀏覽器中正常顯示。
e、XSLT 轉換是與有效性驗證完全無關的操作,只要是滿足格式正確的要求的 XML 就可以進行轉換。

轉換後生成的 HTML 其實是這樣的:

java代碼: 

  <html>
  <head>
          <title>產品搜尋結果</title>
  </head>
  <body>
          <h1>產品搜尋結果</h1>
          <p><b>摘要:</b>搜尋字串:“滑鼠 鍵盤”,共找到 2 筆</p>
            <table>
              <tr>
 10                       <th>品名</th>
 11                       <th>定價</th>
 12                       <th>說明頁</th>
 13             </tr>
 14             <tr>
 15                       <td>手不痛健康滑鼠</td>
 16                       <td>$234</td>
 17                       <td><a href="http://foo.bar/kbd/83424723">上市發表會</a></td>
 18             </tr>
 19             <tr>
 20                       <td>打不響靜悄悄鍵盤</td>
 21                       <td>$567</td>
 22                       <td><a href="http://foo.bar/mouse/12478943">產品特性</a></td>
 23             </tr>
 24           </table>
 25 </body>
 26 </html>



上面這個例子其實是來自於《無廢話 XML》這本書。這個例子要在 IE 中正常顯示只需要改一點點內容,這個任務留給你們課後去做。
關於 XSLT 首先應該看《無廢話 XML》這本書,這本書裏對 XSLT 的講解是很清楚的。XSLT 我們在目前的開發中也用不到,但是 XSLT 在 XML 中是非常基礎的知識,所以我在這一部分中用了較大的篇幅來講述。

知道了這麼多,你可能會認爲 HTML+CSS 已經是是落後的技術,應該完全被 XML+XSLT 取代。這其實是一個錯誤的觀念,連 W3C 都沒有敢肯定 HTML+CSS 一定會被 XML+XSLT 取代。XML+XSLT 的主要缺點是成本和複雜性。由於缺乏所見即所得的(WYSIWYG)頁面編輯器的支持,對於實現相同顯示效果的複雜頁面,XML+XSLT 的工作量要比 HTML+CSS 大得多。而且頁面製作人員完全不能適應 XML+XSLT 的工作方式(這是程序員的工作方式),強求他們採用 XML+XSLT 是不現實的。目前 Dreamweaver 已經可以非常好地支持 CSS 了。所以在可預測的未來很長一段時間內,HTML+CSS 仍然是 Web 頁面開發的主流技術。當然 HTML 將逐漸被 XHTML 所代替,但是這是另外的問題。XHTML 就是用 XML 來改造 HTML,使 HTML 至少符合 XML 格式正確的要求。符合 XHTML 標準的頁面還有一些其它要求,感興趣的可以看看《XML 高級編程》這本書。

以上這些就是我這次培訓的所有內容。這些都是我認爲的關於 XML 的基礎知識,希望通過這次講解以及課後的學習能夠掌握好。掌握好了這些知識,再去掌握其它與 XML 相關的知識就是輕而易舉的了。

相關資料:
1、《無廢話 XML》
2、《W3C XML 規範》
3、《XML 高級編程》
4、《Java 與 XML》
5、《XML Schemas》


術語列表:
HTML:HyperText Markup Language,超文本標記語言
SGML:Standard Generalized Markup Language,標準通用標記語言。
XML:eXtensible Markup Language,可擴展標記語言。
DTD:Document Type Definition,文檔類型定義。
XML Schema:XML 模式
RELAX NG:REgular LAnguage description for XML Next Generation,下一代的 RELAX。
DSSSL:Document Style Semantics and Specification Language,文檔樣式語義和規範語言
XSLT:eXtensible Stylesheet Language——Transformation,可擴展樣式單語言轉換部分

PI:Processing Instruction,處理指令。
XPath:XML 路徑描述。
namespace:名字空間。

DOM:Document Object Model,文檔對象模型。
SAX:Simple API for XML,XML 簡單 API。
JAXP:Java API for XML Parsing
JDOM:Java Document Object Model
DOM4J:Document Object Model for Java

java代碼: 

 1 <?xml version="1.0" encoding="gbk"?>
 2 <DocRoot xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation="http://www.xxx.com/dagl ./../mlzx/schemas/dz/wjnr.xsd" xmlns="http://www.xxx.com/dagl">
 3         ...
 4 </DocRoot>



我們可以看到在這個 XML 中聲明瞭兩個名字空間。聲明名字空間使用 xmlns:前綴=URI 的形式,其中前綴也可以沒有,用來設置 XML 文檔缺省的名字空間。可以在任何元素上聲明名字空間,聲明後名字空間在該元素管轄範圍(作用域)內起作用。在這個 XML 文檔中使用了 Schema 來做有效性驗證,因此必須聲明 Schema 的名字空間。前綴可以是任意字符串(通常使用 xsi),但是這個名字空間所對應的 URI 是固定的,代表的是一個 Schema 的實例(Schema 與 XML 文檔的關係就象是類和對象的關係一樣)。名字空間聲明後立即可以使用,所以在後面緊接着用這個名字空間前綴 xsi 設置了一個屬性 schemaLocation,這個屬性用來設置 Schema 文件的路徑。xmlns="http://www.xxx.com/dagl" 中沒有前綴設置了文檔的缺省名字空間,也就是說在本文檔中所有沒有前綴的元素、屬性都屬於這個缺省的名字空間。

我們再來看看在 Schema 文件中使用名字空間的情況:

java代碼: 

  <?xml version="1.0" encoding="gbk"?>
  <schema xmlns="http://www.w3.org/2001/XMLSchema"
          xmlns:dagl="http://www.xxx.com/dagl" 
          targetNamespace="http://www.xxx.com/dagl" 
          elementFormDefault="qualified">
  
      <complexType name="attrType">
          <simpleContent>
              <extension base="string">
 10                 <attribute name="code_category" type="string" />
 11                 <attribute name="id" type="string" />
 12             </extension>
 13         </simpleContent>
 14     </complexType>
 15 
 16     <complexType name="dmType">
 17         <sequence>
 18                     ...
 19                 <element name="flh" type="dagl:attrType"/>
 20                     ...
 21         </sequence>     
 22     </complexType>
 23         ...
 24 </schema>


這個摘自剛纔那個 XML 文檔對應的 Schema。我們看到這個 Schema 中除了缺省的名字空間外還聲明瞭一個前綴爲 dagl 的名字空間,而且這個名字空間的 URI 必須與 targetNamespace 的 URI 相同。我把 Schema 規範設置爲缺省名字空間是爲了簡化編寫 Schema 定義,如果不這樣做,那麼每一個 complexType、sequence、element 都需要加上前綴(通常使用 xsd),那樣是很麻煩的。targetNamespace 用來定義相應的 XML 文檔(XML 實例,xsi)應該遵守的名字空間,也就是 XML 實例的缺省名字空間。爲什麼要這樣做我不細講了,這裏的規則就是在 Schema 中自定義的類型(這裏是 attrType)使用時必須加上名字空間前綴,這個前綴對應的名字空間 URI 必須與 targetNamespace 的 URI 相同。

現在我們對於 DTD、Schema、名字空間的作用都有了比較清晰的瞭解。在這一部分需要重點掌握的是名字空間的作用和使用方法。做 DTD、Schema 驗證的具體方法可以看我發在 bbs 上的文章:介紹一下做 Schema 驗證和 DTD 驗證的方法
http://forum.hibernate.org.cn/viewtopic.php?t=859
用 Xerces 來做 DTD 和 Schema 驗證是非常簡單的。想要更詳細地瞭解 DTD 和 Schema 的開發方法可以看《XML Schemas》和《XML 高級編程》這兩本書。
因爲性能上的原因,大部分情況下我們做 XML 開發時是不需要驗證 XML 的有效性的。不過我們將來有可能會開發自己的 XML 詞彙表,所以我們還是有必要學習相關知識的。我們將來主要會採用 Schema,需要重點學習這方面的知識,DTD 僅僅作爲需要了解的知識。還有一個採用 Schema 而不採用 DTD 的重要原因是 DTD 不支持名字空間。由於 DTD 來自於 SGML,SGML 中完全沒有名字空間的概念,因此 DTD 也完全不能識別 XML 中的名字空間。如果在 XML 中使用了包含了前綴的元素名,例如 <book:title>,用 DTD 做有效性驗證時就會出錯,DTD 頑固地認爲你必須在相應 DTD 文件中定義一個 book:title 元素才行(它不會認爲這個 book:title 其實就是一個 title)。而 Schema 完全支持名字空間,正是因爲這個原因,而且考慮到名字空間的重要性,雖然目前 Schema 還存在缺陷,我們還是應該堅持使用 Schema 而不使用 DTD。

在目前階段,只需要掌握好名字空間就可以了。Schema、DTD 等內容可以在需要的時候再去學習。

5、XML 與顯示的結合
第 1 部分說到過,XML 的設計目標就是把內容與顯示格式分離開。其實只有面向文檔的應用纔有顯示的需求,面向數據的應用不需要定義顯示格式。把內容與顯示格式分離不僅有利於面向文檔應用的開發,更有利於面向數據應用的開發。我來舉個面向數據應用的例子,假設你做了一個 Web 搜索引擎(或者叫做網絡爬蟲),如果頁面採用 HTML 來開發,當你的程序讀到這樣的信息:

java代碼: 

 1 <tr>
 2         <td>XML 高級編程</td>
 3         <td>95.00</td>
 4 </tr>


你的程序能辨別出這其實是一本書的名稱和價格嗎?尤其是當這些單純表示格式的 <tr>、<td> 以不規則方式嵌套了很多層的時候,開發出一個支持 HTML 全文檢索的搜索引擎簡直是一場災難。但是如果這些頁面都是採用 XML 來開發的,並且內容與顯示格式完全分離,當你的程度讀到這樣的信息:

java代碼: 

 1 <book>
 2         <title>XML 高級編程</title>
 3         <price>95.00</price>
 4 </book>


就可以非常容易地辨別出這是一本書的名稱和價格,尤其是當這個 XML 頁面使用了通用的詞彙表並且通過了有效性驗證時。所以 XML 就是搜索引擎開發者的福音,XML 還會催生出一大堆面向數據的應用,而這類應用在 XML 出現前是根本無法實現的。

言歸正傳,現在我們來談談面向文檔的應用。那麼顯示格式用什麼來定義呢?有兩種方法,CSS 和 XSLT,XML 文檔要在瀏覽器中顯示必須結合 CSS 或者 XSLT 的樣式單。XML 文檔與 HTML 一樣可以用 CSS 來定義顯示格式(這裏有個例子:http://www.wespoke.com/atom.xml)。
我們先看一下上面這個例子中如何用 CSS 來定義顯示格式:

java代碼: 

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <?xml-stylesheet href="/css/atom.css" type="text/css"?>
 3 <feed>
 4         ...
 5           <entry>
 6                   ...
 7           </entry>
 8         ...
 9 </feed>


其中

java代碼: 

 1 <?xml-stylesheet href="/css/atom.css" type="text/css"?>


是與樣式單相關的處理指令,指出本文檔使用哪一個樣式單來定義顯示格式,如果用 CSS 來定義,type 就是 "text/css",用 XSLT 來定義,type 就是 "text/xsl"。

下面是其對應的 CSS 文件中的一段:

java代碼: 

1 entry {
 2         display: block;
 3           border: 2px solid black;
 4           margin: 1em;
 5           padding: 0.5em;
 6 }


可以看出,這段 CSS 與我們在 HTML 中使用的 CSS 沒有什麼區別。而且通過這段 CSS 可以想象出,瀏覽器在將在 entry 之外顯示 2 個象素寬的邊界。瀏覽器顯示的結果與我們想象的完全相同(1.jpg)。


下面我來講一講 XSLT,因爲在 XML 的世界裏 XSLT 是比 CSS 更加重要的技術。現在最流行的 XML 文檔的顯示方法還是 XSLT。原因與 Schema 一樣,XSLT 採用 XML 格式(CSS 採用自己的語法),可以用相同的 XML 解析器解析,便於程序處理。

XSLT 是參考 SGML 中的 DSSSL(定義 SGML 的顯示格式)而設計的。最初叫做 XSL,但是後來 W3C 發現工作量實在太大就分成了兩個規範:XSLT 和 XSL:FO。XSLT 很快就作爲正式規範推出了,主要是面向轉換類應用的;XSL:FO 主要是面向精確的格式定義(例如 PDF),正式規範才推出不久。我們主要用到 XSLT,因爲 XSLT 目前已經達到了實用的階段並且被廣泛採用。XSLT 其實不完全是爲顯示目的設計的,XSLT 的主要作用是將 XML 由一種格式轉換爲另一種格式,例如由 XML 的一種詞彙錶轉換爲另一種詞彙表,或者由 XML 轉換爲 HTML 或者 XHTML,便於在瀏覽器中顯示。後一種應用(XML->HTML/XHTML)是目前 XSLT 應用最廣的領域,被應用於很多符合 J2EE 標準的表示層框架中。這類框架在服務器端做 XSLT 轉換,將生成的 HTML/XHTML 發給瀏覽器。基於這種技術的框架還可以非常方便地支持各種瘦客戶端,例如 PDA 或具有無線上網功能的 WAP 手機(這時候是 XML->WML,也就是由一種詞彙錶轉換爲另一種詞彙表,WML 本身就是 XML 的一種詞彙表),無非就是另外再寫一套 XSLT 樣式單。在這種應用中,只包含數據的 XML 相當於 MVC 中的 Model,而表示顯示格式的 XSLT 相當於 MVC 中的 View。還有一些需要在服務器定期生成靜態頁面的網站(例如新浪這類新聞網站)也在服務器採用 XML+XSLT 來定期生成靜態頁面(這類進程一般是以後臺方式運行)。

現在 IE 和 Mozilla 兩大瀏覽器都可以很好地支持 XSLT,所以從技術上講可以完全採用 XML+XSLT 來製作所有的頁面。在這裏 XML+XSLT 與我們熟悉的 HTML+CSS 的功能大致相同。這也引起了另外的一種思考,究竟是在服務器端做 XSLT 轉換好還是在瀏覽器端做 XSLT 轉換好?我的考慮是儘管在服務器端做 XSLT 轉換更加靈活,功能更加強大,我卻更願意在瀏覽器端做轉換。因爲 XSLT 轉換是非常耗費資源的操作,如果在服務器端做大量的轉換操作必然會極大地影響服務器的性能。必須要在服務器端做轉換的話一個更好的方案是採用後臺方式定期生成靜態的 HTML 頁面(也就是上面說的一些新聞網站所採取的做法),或者在服務器端通過軟件實現某種 cache。這也符合我們一貫的思路:瀏覽器其實能做很多事情,而且現在主流機型(P4 2G、256M 以上內存)的處理能力已經非常強了,所以在瀏覽器力所能及的情況下應該把儘量多的工作交給瀏覽器去做。

就象剛纔講的 XML+CSS,我們來直觀地看一下 XML+XSLT 是什麼樣子:

XML 文檔 test.xml:

java代碼: 

  <?xml version="1.0" encoding="gbk"?>
  <?xml-stylesheet href="test.xsl" type="text/xsl"?>
  <產品搜尋>
          <摘要>搜尋字串:“滑鼠 鍵盤”,共找到 2 筆</摘要>
          <產品>
              <貨號>12478943</貨號>
              <品名>手不痛健康滑鼠</品名>
              <定價>$234</定價>
              <說明頁 網址="http://foo.bar/mouse/12478943">上市發表會</說明頁>
 10           </產品>
 11           <產品>
 12             <貨號>83424723</貨號>
 13             <品名>打不響靜悄悄鍵盤</品名>
 14             <定價>$567</定價>
 15             <說明頁 網址="http://foo.bar/kbd/83424723">產品特性</說明頁>
 16         </產品>
 17 </產品搜尋>



XSLT 樣式單 test.xsl:

java代碼: 

  <?xml version="1.0" encoding="gbk"?>
  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output encoding="gbk"/>
  
  <xsl:template match="/">
          <html>
            <head>
                    <title>產品搜尋結果</title>
            </head>
 10           <body>
 11             <h1>產品搜尋結果</h1>
 12             <p><b>摘要:</b><xsl:value-of select="*/摘要"/></p>
 13             <xsl:apply-templates select="產品搜尋"/>
 14           </body>
 15           </html>
 16 </xsl:template>
 17 
 18 <xsl:template match="產品搜尋">
 19           <table>
 20             <tr>
 21                       <th>品名</th>
 22                       <th>定價</th>
 23                       <th>說明頁</th>
 24             </tr>
 25                   <xsl:for-each select="產品">
 26             <tr>
 27                       <td><xsl:value-of select="品名"/></td>
 28                       <td><xsl:value-of select="定價"/></td>
 29                       <td><a href="{說明頁/@網址}"><xsl:value-of select="說明頁"/></a></td>
 30             </tr>
 31                   </xsl:for-each>
 32           </table>
 33 </xsl:template>
 34 
 35 </xsl:stylesheet>



這個例子是一個可以在 Mozilla 中正常顯示的 XML 頁面(2.jpg),從這個完整的例子中可以對我們剛纔學到的知識產生很多感性認識。
a、XML 中的元素、屬性名都可以使用中文,只要在 XML 聲明中使用了正確的 encoding(這裏是 gbk)。
b、在 XSLT 樣式單中大量採用 XPath 語法來定位 DOM 中的節點並且對符合條件的節點進行轉換。事實上 XPath 的產生最初就是因爲 XSLT 的需要。
c、在 XSLT 樣式單中同樣可以使用名字空間。
d、XML 經 XSLT 轉換後輸出內容爲標準的 HTML 頁面,可以在瀏覽器中正常顯示。
e、XSLT 轉換是與有效性驗證完全無關的操作,只要是滿足格式正確的要求的 XML 就可以進行轉換。

轉換後生成的 HTML 其實是這樣的:

java代碼: 

  <html>
  <head>
          <title>產品搜尋結果</title>
  </head>
  <body>
          <h1>產品搜尋結果</h1>
          <p><b>摘要:</b>搜尋字串:“滑鼠 鍵盤”,共找到 2 筆</p>
            <table>
              <tr>
 10                       <th>品名</th>
 11                       <th>定價</th>
 12                       <th>說明頁</th>
 13             </tr>
 14             <tr>
 15                       <td>手不痛健康滑鼠</td>
 16                       <td>$234</td>
 17                       <td><a href="http://foo.bar/kbd/83424723">上市發表會</a></td>
 18             </tr>
 19             <tr>
 20                       <td>打不響靜悄悄鍵盤</td>
 21                       <td>$567</td>
 22                       <td><a href="http://foo.bar/mouse/12478943">產品特性</a></td>
 23             </tr>
 24           </table>
 25 </body>
 26 </html>



上面這個例子其實是來自於《無廢話 XML》這本書。這個例子要在 IE 中正常顯示只需要改一點點內容,這個任務留給你們課後去做。
關於 XSLT 首先應該看《無廢話 XML》這本書,這本書裏對 XSLT 的講解是很清楚的。XSLT 我們在目前的開發中也用不到,但是 XSLT 在 XML 中是非常基礎的知識,所以我在這一部分中用了較大的篇幅來講述。

知道了這麼多,你可能會認爲 HTML+CSS 已經是是落後的技術,應該完全被 XML+XSLT 取代。這其實是一個錯誤的觀念,連 W3C 都沒有敢肯定 HTML+CSS 一定會被 XML+XSLT 取代。XML+XSLT 的主要缺點是成本和複雜性。由於缺乏所見即所得的(WYSIWYG)頁面編輯器的支持,對於實現相同顯示效果的複雜頁面,XML+XSLT 的工作量要比 HTML+CSS 大得多。而且頁面製作人員完全不能適應 XML+XSLT 的工作方式(這是程序員的工作方式),強求他們採用 XML+XSLT 是不現實的。目前 Dreamweaver 已經可以非常好地支持 CSS 了。所以在可預測的未來很長一段時間內,HTML+CSS 仍然是 Web 頁面開發的主流技術。當然 HTML 將逐漸被 XHTML 所代替,但是這是另外的問題。XHTML 就是用 XML 來改造 HTML,使 HTML 至少符合 XML 格式正確的要求。符合 XHTML 標準的頁面還有一些其它要求,感興趣的可以看看《XML 高級編程》這本書。

以上這些就是我這次培訓的所有內容。這些都是我認爲的關於 XML 的基礎知識,希望通過這次講解以及課後的學習能夠掌握好。掌握好了這些知識,再去掌握其它與 XML 相關的知識就是輕而易舉的了。

相關資料:
1、《無廢話 XML》
2、《W3C XML 規範》
3、《XML 高級編程》
4、《Java 與 XML》
5、《XML Schemas》


術語列表:
HTML:HyperText Markup Language,超文本標記語言
SGML:Standard Generalized Markup Language,標準通用標記語言。
XML:eXtensible Markup Language,可擴展標記語言。
DTD:Document Type Definition,文檔類型定義。
XML Schema:XML 模式
RELAX NG:REgular LAnguage description for XML Next Generation,下一代的 RELAX。
DSSSL:Document Style Semantics and Specification Language,文檔樣式語義和規範語言
XSLT:eXtensible Stylesheet Language——Transformation,可擴展樣式單語言轉換部分

PI:Processing Instruction,處理指令。
XPath:XML 路徑描述。
namespace:名字空間。

DOM:Document Object Model,文檔對象模型。
SAX:Simple API for XML,XML 簡單 API。
JAXP:Java API for XML Parsing
JDOM:Java Document Object Model
DOM4J:Document Object Model for Java

java代碼: 

 1 List list = document.selectNodes( //foo/bar );
 2 Node node = document.selectSingleNode(//foo/bar/author);
 3 


這與我們前臺寫的 JavaScript 是非常相似的,我們學會 DOM4J 是幾乎不需要花什麼時間。
DOM4J 與 JDOM 一樣,通過 SAX 或 DOM(一般用 SAX)讀入 XML 中的信息在內存中生成自己的數據結構,因此 DOM4J 至少需要一個實現了 SAX 的 XML 解析器,我們可以直接使用 Xerces。
由於 DOM4J 具有易用性、性能、靈活性、功能強大等多方面的優勢,今後我們如果需要在服務器端做 XML 開發,DOM4J 將是我們主要採用的工具。

關於這幾種 API 的詳細內容,請參考《Java 與 XML》和《XML 高級編程》。關於 DOM4J,主要有這些資料:
http://dom4j.sourceforge.net/faq.html
http://www.csdn.net/develop/article/22/22753.shtm

聽了我上面的介紹你們可能會覺得 DOM 是比 SAX 更基礎的 API,因爲它是 W3C 的標準,所有的語言都支持,而 SAX 的使用僅侷限於少數幾種語言。某種程度上你是對的,但是在 Java 的世界裏,SAX 是比 DOM 更加基礎的 API。由於 SAX 處理效率很高,SAX 的應用範圍比 DOM 更廣。例如:我們中間件的低層框架 Avalon(也是 Apache 軟件基金會的產品)處理 XML 配置文件時使用的就是 SAX。另外,因爲 W3C 並沒有規定在內存中如何生成一棵 DOM 樹(W3C 只規定了如何操作這棵 DOM 樹),Xerces 採用高效率的 SAX 來讀入 XML,然後生成 DOM 樹。因此當你在用 Xerces 做 DOM 開發時發現經常需要捕獲 SAXException 就沒什麼可奇怪的了。JDOM 和 DOM4J 通常也是使用 SAX 讀入 XML,然後生成自己的數據結構。對於 JAXP、JDOM 和 DOM4J 來說,DOM 和 SAX 都是基礎的 API。

在我們公司做開發最常接觸的 XML 開發是使用 JavaScript 做 DOM 開發,因爲時間有限,所以我今天只詳細講一下在前臺使用 JavaScript 和 DOM API 做 XML 開發的過程。今天的目的主要是讓大家對於 XML 相關的知識有一個整體的瞭解。

大家知道 JavaScript 是嵌入在瀏覽器中的,創建 DOM 樹不是 JavaScript 的責任,瀏覽器已經創建好了,另外通常 JavaScript 也不能直接讀寫 XML 文件(在權限許可的情況下 JavaScript 可以讀寫本地文件)。JavaScript 處理的 XML 數據有兩個來源,一個是來自於頁面中的 XML 數據島,另外一個是來自於從 XMLHTTP 接口接收的後臺發來的 XML 數據。注意:在瀏覽器中的 DOM 有兩種,HTML DOM 和 XML DOM。如何處理 HTML DOM 在普通的 JavaScript 教材(《JavaScript 權威指南》等等)中已經講得很詳細了,我這裏只詳細講一下如何處理 XML DOM,下面所說的 DOM 都是指 XML DOM。在講 XML DOM 之前我首先要講一下 XPath。

什麼是 XPath?簡單地說,XPath 就是定位 XML 中某些節點(元素、屬性、內容、處理指令、文檔類型定義、註釋)的方法。XPath 的目的是爲 XSLT 和 XPointer 提供一個共同的、整合的語法,用來對應 XML 的各個部分,選擇 XML 中的某個或某些節點。XPath 是在 DOM 樹中查找節點、做 XSLT 轉換、定義文檔內部指針(XPointer)的基礎。有時候也把一個符合 XPath 規範的表達式稱做一個 xpath。我們通常把 XPath 表達式的結果稱爲一個節點集(node set)。節點集能夠被轉換、複製、忽略或執行其它的合法操作。XPath 除了包括定位語法外還包括很多函數定義,這些函數分成 4 類:節點集函數、字符串函數、布爾函數和數值函數。節點集函數,例如 position() 和 count(),通常以節點集作爲輸入(以 XPath 表達式的形式),然後做進一步處理。其它 3 種類型的函數,例如 substring()、not() 和 round() 提供基本的字符串處理、邏輯運算和數值運算的功能。關於 XPath 中各種函數定義的詳細內容可以參考《XML 高級編程》這本書。所有這些表達式語法或函數定義都是 XPath 規範或實現的一部分。

好了,長話短說,我在這裏主要講一下 XPath 如何使用。其實我們需要知道的基本上就是《無廢話 XML》中表 7.1 的內容。
XPath 的定位語法與操作系統目錄結構的語法非常相似。也分成兩種,相對路徑與絕對路徑。相對路徑從當前正在處理的節點開始,絕對路徑從文檔的根節點開始。我來舉些例子:

java代碼: 

  A                                        對應當前節點下所有名爲 A 的子元素。
  *                                        對應當前節點下所有子元素。
  */A                                        對應自當前節點開始,所有名爲 A 的孫元素。
  @A                                        對應一個附屬於當前節點,名爲 A 的屬性。
  @*                                        對應所有附屬於當前節點的屬性。
  text()                                對應當前節點的子元素中的所有文本節點。
  .                                        對應當前節點
  ..                                        對應當前節點的父節點。
  A[1]                                對應當前節點下,第一個名爲 A 的子元素。
 10 A[position()=1]                作用同上。
 11 A/[@B="true"]                對應當前節點下所有名爲 A 的子元素,這個子元素必須含有一個名爲 B 的屬性,其屬性?當匭?爲 "true"。
 12 A|B                                        對應當前節點下,所有名爲 A 或 B 的子元素;| 代表“或”的關係。
 13 .//A                                對應當前節點下,所有名爲 A 的元素;// 符號代表可跨?絞?。
 14 A//B                                對應到所有名爲 B 的元素,它們的上級(可跨?絞叮?必須有一個名爲 A 的元素,而且 A 元素必須是當前節點的子元素。
 15 /A                                        對應根節點下所有名爲 A 的子元素。
 16 //A                                        對應根節點下所有名爲 A 的元素。A 元素可以在任意層次。
 17 



我們在做前臺開發時,有兩個方法會用到 XPath,selectSingleNode() 和 selectNodes()。這兩個方法是 IE 的擴展,不屬於 W3C DOM 規範,但是使用起來非常方便,所以我們在 DOM4J 中也可以看到這兩個方法。

java代碼: 

 1 hwn.__drTags = sr1.selectSingleNode("./tag");
 2 var cxn = xn.selectNodes("./*[not(@m:f) or @m:f!='d']");



上面是從我們的前臺開發框架中 copy 出來的代碼。
selectSingleNode 用於獲得一個節點,如果有多個節點滿足條件,返回的是第一個節點。
selectNodes 用於獲得節點集,返回的結果是包含所有滿足條件節點的數組。

第二條語句的參數看起來有些複雜,它的意思是找到 xn 節點下所有不包含 m:f 屬性或者包含 m:f 屬性,但屬性值不等於 'd' 的所有子元素。


下面我來詳細講解 XML DOM 在 JavaScript 中的實現。
在瀏覽器中,無論 XML 的數據來源如何,最後都會由瀏覽器生成一棵 DOM 樹。這棵 DOM 樹所對應的對象類型爲 XMLDocument,這棵 DOM 樹上的所有節點(包括根節點)都是 XMLNodes 類型的對象。事實上 XMLDocument 也是 XMLNodes 的子類,所以你可以在任何一種 XMLNodes 派生出的對象上調用 selectSingleNode 和 selectNodes。

數據來自 XML 數據島:
例如在頁面中有這樣一個 XML 數據島,
<xml id="book">
...
</xml>

var xd = book.XMLDocument;

通過外部 XML 文件創建新的 DOM 樹:
var xd = new ActiveXObject("Microsoft.XMLDOM");
xd.load(data.xml);

或者將外部文件中的數據加載到 XML 數據島:
var xd = book.XMLDocument;
xd.load(data.xml);

注意:load() 這個方法的參數可以是任意合法的 URL,不一定限制爲文件名。

將數據保存到 XML 文件用
xd.save(data.xml);

通過字符串創建新的 DOM 樹:
var xd = new ActiveXObject("Microsoft.XMLDOM");
xd.loadXML("<"+hd.__hwnodes.style.rootTag+"></"+hd.__hwnodes.style.rootTag+">");


數據來自 XMLHTTP:
var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.open("GET","/hwsvr2/qe",false);
xmlhttp.send(null);
var xd = xmlhttp.responseXML;

得到 XML 文檔的根節點:
var xn = xd.documentElement;


我再來說說在 Mozilla 中創建 XML DOM 樹的方法,將來我們有可能會爲 Mozilla 開發頁面,所以對於如何保持腳本的兼容性有些瞭解是有好處的,這部分內容不是必須掌握的內容。
Mozilla 中並沒有 IE 的 XML 數據島這個概念,不過在 Mozilla 中模擬 XML 數據島是非常容易的,這裏有這方面的資料:
http://www.mozilla.org/xmlextras/xmldataislands/
感興趣的可以看看。

Mozilla 中內建有對 XML DOM 的支持,並沒有使用 ActiveX 之類外掛的方式(被 Mozilla 開發者譏笑爲打補丁的方式)。在 Mozilla 中訪問創建好的 DOM 樹的方法與 IE 中基本上是一樣的,所不同的是創建 DOM 的過程,Mozilla 採用的方法都是符合 W3C 標準的方法:

通過外部 XML 文件創建新的 DOM 樹:
var xd= document.implementation.createDocument("","",null);
xd.load("data.xml");

第一個參數是名字空間的 URL,第二個參數是 DOM 根元素名稱,第三個參數是定義 XML 格式的 DTD。在這裏這 3 個參數都可以不提供。

Mozilla 中沒有 loadXML() 這個簡單的方法,但是可以手工爲 Mozilla 添加這個方法,詳細信息在這裏:
http://webfx.eae.net/dhtml/xmlextras/xmlextras.html

數據來自 XMLHTTP:
var xmlhttp=new XMLHttpRequest();
xmlhttp.open("GET","/hwsvr2/qe",false);
xmlhttp.send(null);
var xd = xmlhttp.responseXML;


得到 XML 文檔的根節點:
var xn = xd.documentElement;

由上面可以看到只要創建了 XML DOM 樹後,訪問方法 IE、Mozilla 是完全一樣的,這部分的差異非常容易通過封裝的方法屏蔽掉。Mozilla 沒有提供 selectSingleNode() 和 selectNodes() 兩個方法,以前我寫過這兩個方法在 Mozilla 上的實現,貼在論壇上,感興趣的可以看看:
http://forum.hibernate.org.cn/viewtopic.php?t=965


下面我來講講訪問 DOM 樹常用的方法。

剛纔我們說到過,DOM 樹的訪問有兩個級別,文檔級別和節點級別。

在文檔級別,XMLDocument 對象上有這些方法:
abort():終止正在進行的異步下載
getElementByTagName():根據標記名稱查找當前節點的子元素。
load():從指定位置下載 XML。
save():將 XML 保存到指定位置。

XMLDocument 對象上有這些屬性:
async:指出 XML 是否可以異步下載。
doctype:返回 XML 的 DTD 節點。
documentElement:返回 XML 的根元素。
parseError:返回包含 parse error 信息的對象。

在節點級別,XMLNodes 對象上有這些方法:
createElement():在當前節點下創建一個子元素。
createTextNode():在當前節點下創建一個內容節點。

appendChild():在當前節點上添加新的子節點。
cloneNode():複製一個節點,返回值爲生成的新節點。
hasChildNodes():當前節點是否爲葉節點。
insertBefore():在某節點前插入新的節點。
removeChild():刪除當前節點的子節點。
replaceChild():替換當前節點的子節點。

XMLNodes 對象上有這些屬性:
childNodes:包含所有的子節點數組。
firstChild:當前節點的第一個子節點
lastChild:當前節點的最後一個子節點
nextSibling:當前節點的下一個兄弟節點
nodeValue:節點值
ownerDocument:當前節點對應的 XML 文檔
parentNode:當前節點的父節點。
parentElement:父元素的句柄。
xml:從當前節點開始子樹所生成的 XML。這個屬性只有 IE 支持。

對於所有的元素節點,可以使用這兩個方法:
setAttribute():設置當前元素的屬性。
getAttribute():獲得當前元素的屬性。
clearAttributes():清除當前元素的所有屬性。

另外還有 selectSingleNode() 和 selectNodes(),這兩個方法其實是最常用的了。由於 XML DOM 中可以使用強大的 XPath 查找你想要查找的任意節點,比 HTML DOM 中僅能用 all()、getElementById()、getElementByTagName() 幾個功能有限的方法方便得多。
只要你理解了 DOM 的概念,並且沒有忘記以前學的數據結構的知識,上面的這些方法理解起來是非常簡單的,我就不細講了,關鍵是要經常使用,熟能生巧。


4、XML 有效性驗證的方法和名字空間
符合第 2 部分講的 4 個條件的 XML 叫做格式正確的(well-formed)XML。還有一種有效的(valid)XML。什麼叫做有效的 XML 呢?
有效的 XML 就是通過某種格式定義來規定這個 XML 中只能有哪些元素、這些元素應該按照什麼順序出現,每個元素有哪些屬性,這些屬性的數據類型、取值範圍等信息。然後這一類的 XML 只要通過驗證符合這個格式定義就認爲是有效的 XML。那麼爲什麼 XML 需要通過驗證,這主要是電子商務的需要。舉個例子,如果你需要通過 Web 方式與客戶進行 B2B 交易,你把電子形式的發票發給客戶,客戶也會把他們的發票發給你,但是兩種發票的格式不同,就好象你在說漢語他在說英語,彼此無法正常交流,所以必須要有一個統一的格式(標準)才能夠開展正常的電子商務活動。XML 就是靠不同類型的格式定義來建造不同的標記語言的,每一種格式定義(標記語言)叫做一種詞彙表(vocabulary)。

XML 的格式定義有很多種方法,包括 DTD、XML Schema、RELAX NG 等等。DTD 是參考 SGML DTD 創造出的 XML 格式定義方法。DTD 的格式定義採用與 XML 不同的語法,這使得很難直接用解析器來解析 DTD,也很難動態(runtime)驗證 XML 的有效性。W3C 後來又創造了 XML Schema。Schema 是一種新型的 XML 格式定義方法,它完全採用 XML 語法,便於解析器處理,而且對於數據格式的定義更加嚴格和精確,所以 Schema 更加適合面向數據的應用。現在的 XML 解析器一般都支持做 DTD 驗證,也有同時支持做 DTD 和 Schema 驗證的,例如我們使用的 Xerces。那麼有了 Schema 是否我們就可以完全拋棄 DTD 呢?答案是否定的,由於 DTD 來自於 SGML,它非常適合面向文檔的應用(SGML 完全是爲文檔處理而設計的)。定義相同的 XML 格式,DTD 定義要比 Schema 簡練的多,Schema 定義則顯得很冗長,所以 DTD 更加適合面向文檔的應用,不過把 Schema 用於面向文檔的應用也不會有多大的問題。因爲 Schema 的格式定義很煩瑣,所有有人開發出了其它的格式定義方法,其中比較有前途的是 RELAX NG。RELAX NG 是一種以 RELAX(由日本人開發)與 TREX(由 XML 界的權威 James Clark 開發)爲基礎的模式語言。它的基本思想與 Schema 相同,也採用 XML 格式,所以程序處理起來也很方便,而且它的語法比 Schema 要簡單的多。但是目前 RELAX NG 還不是 W3C 的標準,所以大多數解析器都不支持(需要使用專門的軟件包)。我的看法是 Schema 可能會在今後參考 RELAX NG 而得到簡化,所以我們還是應該更多地使用 Schema。

現在我來講一下名字空間這個非常重要的概念。名字空間(namespace)在 XML 中的作用其實與 package 在 Java 中的作用非常象。XML 是一種元語言,可以建造出無窮多種標記語言。有些時候需要在同一個 XML 文檔中混用不同類型的標記語言,但是這些不同類型的標記語言中可能有重複的標記,例如:我爲書籍分類建造了一種標記語言,其中有 <title> 這個標記;我又爲影片分類建造了一種標記語言,其中也有 <title> 這個標記。但是在我的 XML 文檔中需要同時包含書籍和影片兩類的數據(假設這個 XML 文檔其實是用戶的一個購物車,他同時買了書和 DVD),我如何區分一個 <title> 究竟是書籍的 title 還是影片的 title 呢?這時候名字空間就可以幫你了。名字空間就是一個元素前綴與 URI 之間的一種映射關係。名字空間是用一個 XML 元素加上一個前綴組成的,比如 <book:title> 和 <picture:title>。這樣 XML 解析器可以在不使用不同的元素名字的情況下,區分上述兩個元素名字。元素前綴可以爲任意字符串,最終一個 XML 文檔中的每個元素前綴要映射到一個唯一的 URI,這個 URI 就是不同的 XML 詞彙表的標識。除了用於元素,名字空間同樣也可以用於屬性(下面我們馬上可以看到)。名字空間經常在 XML 文檔中使用,也可以在 Schema 及 XSLT 樣式單或者 XML 有關的規範中使用。下面我們看一下名字空間的具體使用方法:

java代碼: 

 1 <?xml version="1.0" encoding="gbk"?>
 2 <DocRoot xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation="http://www.xxx.com/dagl ./../mlzx/schemas/dz/wjnr.xsd" xmlns="http://www.xxx.com/dagl">
 3         ...
 4 </DocRoot>



我們可以看到在這個 XML 中聲明瞭兩個名字空間。聲明名字空間使用 xmlns:前綴=URI 的形式,其中前綴也可以沒有,用來設置 XML 文檔缺省的名字空間。可以在任何元素上聲明名字空間,聲明後名字空間在該元素管轄範圍(作用域)內起作用。在這個 XML 文檔中使用了 Schema 來做有效性驗證,因此必須聲明 Schema 的名字空間。前綴可以是任意字符串(通常使用 xsi),但是這個名字空間所對應的 URI 是固定的,代表的是一個 Schema 的實例(Schema 與 XML 文檔的關係就象是類和對象的關係一樣)。名字空間聲明後立即可以使用,所以在後面緊接着用這個名字空間前綴 xsi 設置了一個屬性 schemaLocation,這個屬性用來設置 Schema 文件的路徑。xmlns="http://www.xxx.com/dagl" 中沒有前綴設置了文檔的缺省名字空間,也就是說在本文檔中所有沒有前綴的元素、屬性都屬於這個缺省的名字空間。

我們再來看看在 Schema 文件中使用名字空間的情況:

java代碼: 

  <?xml version="1.0" encoding="gbk"?>
  <schema xmlns="http://www.w3.org/2001/XMLSchema"
          xmlns:dagl="http://www.xxx.com/dagl" 
          targetNamespace="http://www.xxx.com/dagl" 
          elementFormDefault="qualified">
  
      <complexType name="attrType">
          <simpleContent>
              <extension base="string">
 10                 <attribute name="code_category" type="string" />
 11                 <attribute name="id" type="string" />
 12             </extension>
 13         </simpleContent>
 14     </complexType>
 15 
 16     <complexType name="dmType">
 17         <sequence>
 18                     ...
 19                 <element name="flh" type="dagl:attrType"/>
 20                     ...
 21         </sequence>     
 22     </complexType>
 23         ...
 24 </schema>


這個摘自剛纔那個 XML 文檔對應的 Schema。我們看到這個 Schema 中除了缺省的名字空間外還聲明瞭一個前綴爲 dagl 的名字空間,而且這個名字空間的 URI 必須與 targetNamespace 的 URI 相同。我把 Schema 規範設置爲缺省名字空間是爲了簡化編寫 Schema 定義,如果不這樣做,那麼每一個 complexType、sequence、element 都需要加上前綴(通常使用 xsd),那樣是很麻煩的。targetNamespace 用來定義相應的 XML 文檔(XML 實例,xsi)應該遵守的名字空間,也就是 XML 實例的缺省名字空間。爲什麼要這樣做我不細講了,這裏的規則就是在 Schema 中自定義的類型(這裏是 attrType)使用時必須加上名字空間前綴,這個前綴對應的名字空間 URI 必須與 targetNamespace 的 URI 相同。

現在我們對於 DTD、Schema、名字空間的作用都有了比較清晰的瞭解。在這一部分需要重點掌握的是名字空間的作用和使用方法。做 DTD、Schema 驗證的具體方法可以看我發在 bbs 上的文章:介紹一下做 Schema 驗證和 DTD 驗證的方法
http://forum.hibernate.org.cn/viewtopic.php?t=859
用 Xerces 來做 DTD 和 Schema 驗證是非常簡單的。想要更詳細地瞭解 DTD 和 Schema 的開發方法可以看《XML Schemas》和《XML 高級編程》這兩本書。
因爲性能上的原因,大部分情況下我們做 XML 開發時是不需要驗證 XML 的有效性的。不過我們將來有可能會開發自己的 XML 詞彙表,所以我們還是有必要學習相關知識的。我們將來主要會採用 Schema,需要重點學習這方面的知識,DTD 僅僅作爲需要了解的知識。還有一個採用 Schema 而不採用 DTD 的重要原因是 DTD 不支持名字空間。由於 DTD 來自於 SGML,SGML 中完全沒有名字空間的概念,因此 DTD 也完全不能識別 XML 中的名字空間。如果在 XML 中使用了包含了前綴的元素名,例如 <book:title>,用 DTD 做有效性驗證時就會出錯,DTD 頑固地認爲你必須在相應 DTD 文件中定義一個 book:title 元素才行(它不會認爲這個 book:title 其實就是一個 title)。而 Schema 完全支持名字空間,正是因爲這個原因,而且考慮到名字空間的重要性,雖然目前 Schema 還存在缺陷,我們還是應該堅持使用 Schema 而不使用 DTD。

在目前階段,只需要掌握好名字空間就可以了。Schema、DTD 等內容可以在需要的時候再去學習。

5、XML 與顯示的結合
第 1 部分說到過,XML 的設計目標就是把內容與顯示格式分離開。其實只有面向文檔的應用纔有顯示的需求,面向數據的應用不需要定義顯示格式。把內容與顯示格式分離不僅有利於面向文檔應用的開發,更有利於面向數據應用的開發。我來舉個面向數據應用的例子,假設你做了一個 Web 搜索引擎(或者叫做網絡爬蟲),如果頁面採用 HTML 來開發,當你的程序讀到這樣的信息:

java代碼: 

 1 <tr>
 2         <td>XML 高級編程</td>
 3         <td>95.00</td>
 4 </tr>


你的程序能辨別出這其實是一本書的名稱和價格嗎?尤其是當這些單純表示格式的 <tr>、<td> 以不規則方式嵌套了很多層的時候,開發出一個支持 HTML 全文檢索的搜索引擎簡直是一場災難。但是如果這些頁面都是採用 XML 來開發的,並且內容與顯示格式完全分離,當你的程度讀到這樣的信息:

java代碼: 

 1 <book>
 2         <title>XML 高級編程</title>
 3         <price>95.00</price>
 4 </book>


就可以非常容易地辨別出這是一本書的名稱和價格,尤其是當這個 XML 頁面使用了通用的詞彙表並且通過了有效性驗證時。所以 XML 就是搜索引擎開發者的福音,XML 還會催生出一大堆面向數據的應用,而這類應用在 XML 出現前是根本無法實現的。

言歸正傳,現在我們來談談面向文檔的應用。那麼顯示格式用什麼來定義呢?有兩種方法,CSS 和 XSLT,XML 文檔要在瀏覽器中顯示必須結合 CSS 或者 XSLT 的樣式單。XML 文檔與 HTML 一樣可以用 CSS 來定義顯示格式(這裏有個例子:http://www.wespoke.com/atom.xml)。
我們先看一下上面這個例子中如何用 CSS 來定義顯示格式:

java代碼: 

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <?xml-stylesheet href="/css/atom.css" type="text/css"?>
 3 <feed>
 4         ...
 5           <entry>
 6                   ...
 7           </entry>
 8         ...
 9 </feed>


其中

java代碼: 

 1 <?xml-stylesheet href="/css/atom.css" type="text/css"?>


是與樣式單相關的處理指令,指出本文檔使用哪一個樣式單來定義顯示格式,如果用 CSS 來定義,type 就是 "text/css",用 XSLT 來定義,type 就是 "text/xsl"。

下面是其對應的 CSS 文件中的一段:

java代碼: 

1 entry {
 2         display: block;
 3           border: 2px solid black;
 4           margin: 1em;
 5           padding: 0.5em;
 6 }


可以看出,這段 CSS 與我們在 HTML 中使用的 CSS 沒有什麼區別。而且通過這段 CSS 可以想象出,瀏覽器在將在 entry 之外顯示 2 個象素寬的邊界。瀏覽器顯示的結果與我們想象的完全相同(1.jpg)。


下面我來講一講 XSLT,因爲在 XML 的世界裏 XSLT 是比 CSS 更加重要的技術。現在最流行的 XML 文檔的顯示方法還是 XSLT。原因與 Schema 一樣,XSLT 採用 XML 格式(CSS 採用自己的語法),可以用相同的 XML 解析器解析,便於程序處理。

XSLT 是參考 SGML 中的 DSSSL(定義 SGML 的顯示格式)而設計的。最初叫做 XSL,但是後來 W3C 發現工作量實在太大就分成了兩個規範:XSLT 和 XSL:FO。XSLT 很快就作爲正式規範推出了,主要是面向轉換類應用的;XSL:FO 主要是面向精確的格式定義(例如 PDF),正式規範才推出不久。我們主要用到 XSLT,因爲 XSLT 目前已經達到了實用的階段並且被廣泛採用。XSLT 其實不完全是爲顯示目的設計的,XSLT 的主要作用是將 XML 由一種格式轉換爲另一種格式,例如由 XML 的一種詞彙錶轉換爲另一種詞彙表,或者由 XML 轉換爲 HTML 或者 XHTML,便於在瀏覽器中顯示。後一種應用(XML->HTML/XHTML)是目前 XSLT 應用最廣的領域,被應用於很多符合 J2EE 標準的表示層框架中。這類框架在服務器端做 XSLT 轉換,將生成的 HTML/XHTML 發給瀏覽器。基於這種技術的框架還可以非常方便地支持各種瘦客戶端,例如 PDA 或具有無線上網功能的 WAP 手機(這時候是 XML->WML,也就是由一種詞彙錶轉換爲另一種詞彙表,WML 本身就是 XML 的一種詞彙表),無非就是另外再寫一套 XSLT 樣式單。在這種應用中,只包含數據的 XML 相當於 MVC 中的 Model,而表示顯示格式的 XSLT 相當於 MVC 中的 View。還有一些需要在服務器定期生成靜態頁面的網站(例如新浪這類新聞網站)也在服務器採用 XML+XSLT 來定期生成靜態頁面(這類進程一般是以後臺方式運行)。

現在 IE 和 Mozilla 兩大瀏覽器都可以很好地支持 XSLT,所以從技術上講可以完全採用 XML+XSLT 來製作所有的頁面。在這裏 XML+XSLT 與我們熟悉的 HTML+CSS 的功能大致相同。這也引起了另外的一種思考,究竟是在服務器端做 XSLT 轉換好還是在瀏覽器端做 XSLT 轉換好?我的考慮是儘管在服務器端做 XSLT 轉換更加靈活,功能更加強大,我卻更願意在瀏覽器端做轉換。因爲 XSLT 轉換是非常耗費資源的操作,如果在服務器端做大量的轉換操作必然會極大地影響服務器的性能。必須要在服務器端做轉換的話一個更好的方案是採用後臺方式定期生成靜態的 HTML 頁面(也就是上面說的一些新聞網站所採取的做法),或者在服務器端通過軟件實現某種 cache。這也符合我們一貫的思路:瀏覽器其實能做很多事情,而且現在主流機型(P4 2G、256M 以上內存)的處理能力已經非常強了,所以在瀏覽器力所能及的情況下應該把儘量多的工作交給瀏覽器去做。

就象剛纔講的 XML+CSS,我們來直觀地看一下 XML+XSLT 是什麼樣子:

XML 文檔 test.xml:

java代碼: 

  <?xml version="1.0" encoding="gbk"?>
  <?xml-stylesheet href="test.xsl" type="text/xsl"?>
  <產品搜尋>
          <摘要>搜尋字串:“滑鼠 鍵盤”,共找到 2 筆</摘要>
          <產品>
              <貨號>12478943</貨號>
              <品名>手不痛健康滑鼠</品名>
              <定價>$234</定價>
              <說明頁 網址="http://foo.bar/mouse/12478943">上市發表會</說明頁>
 10           </產品>
 11           <產品>
 12             <貨號>83424723</貨號>
 13             <品名>打不響靜悄悄鍵盤</品名>
 14             <定價>$567</定價>
 15             <說明頁 網址="http://foo.bar/kbd/83424723">產品特性</說明頁>
 16         </產品>
 17 </產品搜尋>



XSLT 樣式單 test.xsl:

java代碼: 

  <?xml version="1.0" encoding="gbk"?>
  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output encoding="gbk"/>
  
  <xsl:template match="/">
          <html>
            <head>
                    <title>產品搜尋結果</title>
            </head>
 10           <body>
 11             <h1>產品搜尋結果</h1>
 12             <p><b>摘要:</b><xsl:value-of select="*/摘要"/></p>
 13             <xsl:apply-templates select="產品搜尋"/>
 14           </body>
 15           </html>
 16 </xsl:template>
 17 
 18 <xsl:template match="產品搜尋">
 19           <table>
 20             <tr>
 21                       <th>品名</th>
 22                       <th>定價</th>
 23                       <th>說明頁</th>
 24             </tr>
 25                   <xsl:for-each select="產品">
 26             <tr>
 27                       <td><xsl:value-of select="品名"/></td>
 28                       <td><xsl:value-of select="定價"/></td>
 29                       <td><a href="{說明頁/@網址}"><xsl:value-of select="說明頁"/></a></td>
 30             </tr>
 31                   </xsl:for-each>
 32           </table>
 33 </xsl:template>
 34 
 35 </xsl:stylesheet>



這個例子是一個可以在 Mozilla 中正常顯示的 XML 頁面(2.jpg),從這個完整的例子中可以對我們剛纔學到的知識產生很多感性認識。
a、XML 中的元素、屬性名都可以使用中文,只要在 XML 聲明中使用了正確的 encoding(這裏是 gbk)。
b、在 XSLT 樣式單中大量採用 XPath 語法來定位 DOM 中的節點並且對符合條件的節點進行轉換。事實上 XPath 的產生最初就是因爲 XSLT 的需要。
c、在 XSLT 樣式單中同樣可以使用名字空間。
d、XML 經 XSLT 轉換後輸出內容爲標準的 HTML 頁面,可以在瀏覽器中正常顯示。
e、XSLT 轉換是與有效性驗證完全無關的操作,只要是滿足格式正確的要求的 XML 就可以進行轉換。

轉換後生成的 HTML 其實是這樣的:

java代碼: 

  <html>
  <head>
          <title>產品搜尋結果</title>
  </head>
  <body>
          <h1>產品搜尋結果</h1>
          <p><b>摘要:</b>搜尋字串:“滑鼠 鍵盤”,共找到 2 筆</p>
            <table>
              <tr>
 10                       <th>品名</th>
 11                       <th>定價</th>
 12                       <th>說明頁</th>
 13             </tr>
 14             <tr>
 15                       <td>手不痛健康滑鼠</td>
 16                       <td>$234</td>
 17                       <td><a href="http://foo.bar/kbd/83424723">上市發表會</a></td>
 18             </tr>
 19             <tr>
 20                       <td>打不響靜悄悄鍵盤</td>
 21                       <td>$567</td>
 22                       <td><a href="http://foo.bar/mouse/12478943">產品特性</a></td>
 23             </tr>
 24           </table>
 25 </body>
 26 </html>



上面這個例子其實是來自於《無廢話 XML》這本書。這個例子要在 IE 中正常顯示只需要改一點點內容,這個任務留給你們課後去做。
關於 XSLT 首先應該看《無廢話 XML》這本書,這本書裏對 XSLT 的講解是很清楚的。XSLT 我們在目前的開發中也用不到,但是 XSLT 在 XML 中是非常基礎的知識,所以我在這一部分中用了較大的篇幅來講述。

知道了這麼多,你可能會認爲 HTML+CSS 已經是是落後的技術,應該完全被 XML+XSLT 取代。這其實是一個錯誤的觀念,連 W3C 都沒有敢肯定 HTML+CSS 一定會被 XML+XSLT 取代。XML+XSLT 的主要缺點是成本和複雜性。由於缺乏所見即所得的(WYSIWYG)頁面編輯器的支持,對於實現相同顯示效果的複雜頁面,XML+XSLT 的工作量要比 HTML+CSS 大得多。而且頁面製作人員完全不能適應 XML+XSLT 的工作方式(這是程序員的工作方式),強求他們採用 XML+XSLT 是不現實的。目前 Dreamweaver 已經可以非常好地支持 CSS 了。所以在可預測的未來很長一段時間內,HTML+CSS 仍然是 Web 頁面開發的主流技術。當然 HTML 將逐漸被 XHTML 所代替,但是這是另外的問題。XHTML 就是用 XML 來改造 HTML,使 HTML 至少符合 XML 格式正確的要求。符合 XHTML 標準的頁面還有一些其它要求,感興趣的可以看看《XML 高級編程》這本書。

以上這些就是我這次培訓的所有內容。這些都是我認爲的關於 XML 的基礎知識,希望通過這次講解以及課後的學習能夠掌握好。掌握好了這些知識,再去掌握其它與 XML 相關的知識就是輕而易舉的了。

相關資料:
1、《無廢話 XML》
2、《W3C XML 規範》
3、《XML 高級編程》
4、《Java 與 XML》
5、《XML Schemas》


術語列表:
HTML:HyperText Markup Language,超文本標記語言
SGML:Standard Generalized Markup Language,標準通用標記語言。
XML:eXtensible Markup Language,可擴展標記語言。
DTD:Document Type Definition,文檔類型定義。
XML Schema:XML 模式
RELAX NG:REgular LAnguage description for XML Next Generation,下一代的 RELAX。
DSSSL:Document Style Semantics and Specification Language,文檔樣式語義和規範語言
XSLT:eXtensible Stylesheet Language——Transformation,可擴展樣式單語言轉換部分

PI:Processing Instruction,處理指令。
XPath:XML 路徑描述。
namespace:名字空間。

DOM:Document Object Model,文檔對象模型。
SAX:Simple API for XML,XML 簡單 API。
JAXP:Java API for XML Parsing
JDOM:Java Document Object Model
DOM4J:Document Object Model for Java

java代碼: 

 1 <?xml version="1.0" encoding="gbk"?>
 2 <DocRoot xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation="http://www.xxx.com/dagl ./../mlzx/schemas/dz/wjnr.xsd" xmlns="http://www.xxx.com/dagl">
 3         ...
 4 </DocRoot>



我們可以看到在這個 XML 中聲明瞭兩個名字空間。聲明名字空間使用 xmlns:前綴=URI 的形式,其中前綴也可以沒有,用來設置 XML 文檔缺省的名字空間。可以在任何元素上聲明名字空間,聲明後名字空間在該元素管轄範圍(作用域)內起作用。在這個 XML 文檔中使用了 Schema 來做有效性驗證,因此必須聲明 Schema 的名字空間。前綴可以是任意字符串(通常使用 xsi),但是這個名字空間所對應的 URI 是固定的,代表的是一個 Schema 的實例(Schema 與 XML 文檔的關係就象是類和對象的關係一樣)。名字空間聲明後立即可以使用,所以在後面緊接着用這個名字空間前綴 xsi 設置了一個屬性 schemaLocation,這個屬性用來設置 Schema 文件的路徑。xmlns="http://www.xxx.com/dagl" 中沒有前綴設置了文檔的缺省名字空間,也就是說在本文檔中所有沒有前綴的元素、屬性都屬於這個缺省的名字空間。

我們再來看看在 Schema 文件中使用名字空間的情況:

java代碼: 

  <?xml version="1.0" encoding="gbk"?>
  <schema xmlns="http://www.w3.org/2001/XMLSchema"
          xmlns:dagl="http://www.xxx.com/dagl" 
          targetNamespace="http://www.xxx.com/dagl" 
          elementFormDefault="qualified">
  
      <complexType name="attrType">
          <simpleContent>
              <extension base="string">
 10                 <attribute name="code_category" type="string" />
 11                 <attribute name="id" type="string" />
 12             </extension>
 13         </simpleContent>
 14     </complexType>
 15 
 16     <complexType name="dmType">
 17         <sequence>
 18                     ...
 19                 <element name="flh" type="dagl:attrType"/>
 20                     ...
 21         </sequence>     
 22     </complexType>
 23         ...
 24 </schema>


這個摘自剛纔那個 XML 文檔對應的 Schema。我們看到這個 Schema 中除了缺省的名字空間外還聲明瞭一個前綴爲 dagl 的名字空間,而且這個名字空間的 URI 必須與 targetNamespace 的 URI 相同。我把 Schema 規範設置爲缺省名字空間是爲了簡化編寫 Schema 定義,如果不這樣做,那麼每一個 complexType、sequence、element 都需要加上前綴(通常使用 xsd),那樣是很麻煩的。targetNamespace 用來定義相應的 XML 文檔(XML 實例,xsi)應該遵守的名字空間,也就是 XML 實例的缺省名字空間。爲什麼要這樣做我不細講了,這裏的規則就是在 Schema 中自定義的類型(這裏是 attrType)使用時必須加上名字空間前綴,這個前綴對應的名字空間 URI 必須與 targetNamespace 的 URI 相同。

現在我們對於 DTD、Schema、名字空間的作用都有了比較清晰的瞭解。在這一部分需要重點掌握的是名字空間的作用和使用方法。做 DTD、Schema 驗證的具體方法可以看我發在 bbs 上的文章:介紹一下做 Schema 驗證和 DTD 驗證的方法
http://forum.hibernate.org.cn/viewtopic.php?t=859
用 Xerces 來做 DTD 和 Schema 驗證是非常簡單的。想要更詳細地瞭解 DTD 和 Schema 的開發方法可以看《XML Schemas》和《XML 高級編程》這兩本書。
因爲性能上的原因,大部分情況下我們做 XML 開發時是不需要驗證 XML 的有效性的。不過我們將來有可能會開發自己的 XML 詞彙表,所以我們還是有必要學習相關知識的。我們將來主要會採用 Schema,需要重點學習這方面的知識,DTD 僅僅作爲需要了解的知識。還有一個採用 Schema 而不採用 DTD 的重要原因是 DTD 不支持名字空間。由於 DTD 來自於 SGML,SGML 中完全沒有名字空間的概念,因此 DTD 也完全不能識別 XML 中的名字空間。如果在 XML 中使用了包含了前綴的元素名,例如 <book:title>,用 DTD 做有效性驗證時就會出錯,DTD 頑固地認爲你必須在相應 DTD 文件中定義一個 book:title 元素才行(它不會認爲這個 book:title 其實就是一個 title)。而 Schema 完全支持名字空間,正是因爲這個原因,而且考慮到名字空間的重要性,雖然目前 Schema 還存在缺陷,我們還是應該堅持使用 Schema 而不使用 DTD。

在目前階段,只需要掌握好名字空間就可以了。Schema、DTD 等內容可以在需要的時候再去學習。

5、XML 與顯示的結合
第 1 部分說到過,XML 的設計目標就是把內容與顯示格式分離開。其實只有面向文檔的應用纔有顯示的需求,面向數據的應用不需要定義顯示格式。把內容與顯示格式分離不僅有利於面向文檔應用的開發,更有利於面向數據應用的開發。我來舉個面向數據應用的例子,假設你做了一個 Web 搜索引擎(或者叫做網絡爬蟲),如果頁面採用 HTML 來開發,當你的程序讀到這樣的信息:

java代碼: 

 1 <tr>
 2         <td>XML 高級編程</td>
 3         <td>95.00</td>
 4 </tr>


你的程序能辨別出這其實是一本書的名稱和價格嗎?尤其是當這些單純表示格式的 <tr>、<td> 以不規則方式嵌套了很多層的時候,開發出一個支持 HTML 全文檢索的搜索引擎簡直是一場災難。但是如果這些頁面都是採用 XML 來開發的,並且內容與顯示格式完全分離,當你的程度讀到這樣的信息:

java代碼: 

 1 <book>
 2         <title>XML 高級編程</title>
 3         <price>95.00</price>
 4 </book>


就可以非常容易地辨別出這是一本書的名稱和價格,尤其是當這個 XML 頁面使用了通用的詞彙表並且通過了有效性驗證時。所以 XML 就是搜索引擎開發者的福音,XML 還會催生出一大堆面向數據的應用,而這類應用在 XML 出現前是根本無法實現的。

言歸正傳,現在我們來談談面向文檔的應用。那麼顯示格式用什麼來定義呢?有兩種方法,CSS 和 XSLT,XML 文檔要在瀏覽器中顯示必須結合 CSS 或者 XSLT 的樣式單。XML 文檔與 HTML 一樣可以用 CSS 來定義顯示格式(這裏有個例子:http://www.wespoke.com/atom.xml)。
我們先看一下上面這個例子中如何用 CSS 來定義顯示格式:

java代碼: 

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <?xml-stylesheet href="/css/atom.css" type="text/css"?>
 3 <feed>
 4         ...
 5           <entry>
 6                   ...
 7           </entry>
 8         ...
 9 </feed>


其中

java代碼: 

 1 <?xml-stylesheet href="/css/atom.css" type="text/css"?>


是與樣式單相關的處理指令,指出本文檔使用哪一個樣式單來定義顯示格式,如果用 CSS 來定義,type 就是 "text/css",用 XSLT 來定義,type 就是 "text/xsl"。

下面是其對應的 CSS 文件中的一段:

java代碼: 

1 entry {
 2         display: block;
 3           border: 2px solid black;
 4           margin: 1em;
 5           padding: 0.5em;
 6 }


可以看出,這段 CSS 與我們在 HTML 中使用的 CSS 沒有什麼區別。而且通過這段 CSS 可以想象出,瀏覽器在將在 entry 之外顯示 2 個象素寬的邊界。瀏覽器顯示的結果與我們想象的完全相同(1.jpg)。


下面我來講一講 XSLT,因爲在 XML 的世界裏 XSLT 是比 CSS 更加重要的技術。現在最流行的 XML 文檔的顯示方法還是 XSLT。原因與 Schema 一樣,XSLT 採用 XML 格式(CSS 採用自己的語法),可以用相同的 XML 解析器解析,便於程序處理。

XSLT 是參考 SGML 中的 DSSSL(定義 SGML 的顯示格式)而設計的。最初叫做 XSL,但是後來 W3C 發現工作量實在太大就分成了兩個規範:XSLT 和 XSL:FO。XSLT 很快就作爲正式規範推出了,主要是面向轉換類應用的;XSL:FO 主要是面向精確的格式定義(例如 PDF),正式規範才推出不久。我們主要用到 XSLT,因爲 XSLT 目前已經達到了實用的階段並且被廣泛採用。XSLT 其實不完全是爲顯示目的設計的,XSLT 的主要作用是將 XML 由一種格式轉換爲另一種格式,例如由 XML 的一種詞彙錶轉換爲另一種詞彙表,或者由 XML 轉換爲 HTML 或者 XHTML,便於在瀏覽器中顯示。後一種應用(XML->HTML/XHTML)是目前 XSLT 應用最廣的領域,被應用於很多符合 J2EE 標準的表示層框架中。這類框架在服務器端做 XSLT 轉換,將生成的 HTML/XHTML 發給瀏覽器。基於這種技術的框架還可以非常方便地支持各種瘦客戶端,例如 PDA 或具有無線上網功能的 WAP 手機(這時候是 XML->WML,也就是由一種詞彙錶轉換爲另一種詞彙表,WML 本身就是 XML 的一種詞彙表),無非就是另外再寫一套 XSLT 樣式單。在這種應用中,只包含數據的 XML 相當於 MVC 中的 Model,而表示顯示格式的 XSLT 相當於 MVC 中的 View。還有一些需要在服務器定期生成靜態頁面的網站(例如新浪這類新聞網站)也在服務器採用 XML+XSLT 來定期生成靜態頁面(這類進程一般是以後臺方式運行)。

現在 IE 和 Mozilla 兩大瀏覽器都可以很好地支持 XSLT,所以從技術上講可以完全採用 XML+XSLT 來製作所有的頁面。在這裏 XML+XSLT 與我們熟悉的 HTML+CSS 的功能大致相同。這也引起了另外的一種思考,究竟是在服務器端做 XSLT 轉換好還是在瀏覽器端做 XSLT 轉換好?我的考慮是儘管在服務器端做 XSLT 轉換更加靈活,功能更加強大,我卻更願意在瀏覽器端做轉換。因爲 XSLT 轉換是非常耗費資源的操作,如果在服務器端做大量的轉換操作必然會極大地影響服務器的性能。必須要在服務器端做轉換的話一個更好的方案是採用後臺方式定期生成靜態的 HTML 頁面(也就是上面說的一些新聞網站所採取的做法),或者在服務器端通過軟件實現某種 cache。這也符合我們一貫的思路:瀏覽器其實能做很多事情,而且現在主流機型(P4 2G、256M 以上內存)的處理能力已經非常強了,所以在瀏覽器力所能及的情況下應該把儘量多的工作交給瀏覽器去做。

就象剛纔講的 XML+CSS,我們來直觀地看一下 XML+XSLT 是什麼樣子:

XML 文檔 test.xml:

java代碼: 

  <?xml version="1.0" encoding="gbk"?>
  <?xml-stylesheet href="test.xsl" type="text/xsl"?>
  <產品搜尋>
          <摘要>搜尋字串:“滑鼠 鍵盤”,共找到 2 筆</摘要>
          <產品>
              <貨號>12478943</貨號>
              <品名>手不痛健康滑鼠</品名>
              <定價>$234</定價>
              <說明頁 網址="http://foo.bar/mouse/12478943">上市發表會</說明頁>
 10           </產品>
 11           <產品>
 12             <貨號>83424723</貨號>
 13             <品名>打不響靜悄悄鍵盤</品名>
 14             <定價>$567</定價>
 15             <說明頁 網址="http://foo.bar/kbd/83424723">產品特性</說明頁>
 16         </產品>
 17 </產品搜尋>



XSLT 樣式單 test.xsl:

java代碼: 

  <?xml version="1.0" encoding="gbk"?>
  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output encoding="gbk"/>
  
  <xsl:template match="/">
          <html>
            <head>
                    <title>產品搜尋結果</title>
            </head>
 10           <body>
 11             <h1>產品搜尋結果</h1>
 12             <p><b>摘要:</b><xsl:value-of select="*/摘要"/></p>
 13             <xsl:apply-templates select="產品搜尋"/>
 14           </body>
 15           </html>
 16 </xsl:template>
 17 
 18 <xsl:template match="產品搜尋">
 19           <table>
 20             <tr>
 21                       <th>品名</th>
 22                       <th>定價</th>
 23                       <th>說明頁</th>
 24             </tr>
 25                   <xsl:for-each select="產品">
 26             <tr>
 27                       <td><xsl:value-of select="品名"/></td>
 28                       <td><xsl:value-of select="定價"/></td>
 29                       <td><a href="{說明頁/@網址}"><xsl:value-of select="說明頁"/></a></td>
 30             </tr>
 31                   </xsl:for-each>
 32           </table>
 33 </xsl:template>
 34 
 35 </xsl:stylesheet>



這個例子是一個可以在 Mozilla 中正常顯示的 XML 頁面(2.jpg),從這個完整的例子中可以對我們剛纔學到的知識產生很多感性認識。
a、XML 中的元素、屬性名都可以使用中文,只要在 XML 聲明中使用了正確的 encoding(這裏是 gbk)。
b、在 XSLT 樣式單中大量採用 XPath 語法來定位 DOM 中的節點並且對符合條件的節點進行轉換。事實上 XPath 的產生最初就是因爲 XSLT 的需要。
c、在 XSLT 樣式單中同樣可以使用名字空間。
d、XML 經 XSLT 轉換後輸出內容爲標準的 HTML 頁面,可以在瀏覽器中正常顯示。
e、XSLT 轉換是與有效性驗證完全無關的操作,只要是滿足格式正確的要求的 XML 就可以進行轉換。

轉換後生成的 HTML 其實是這樣的:

java代碼: 

  <html>
  <head>
          <title>產品搜尋結果</title>
  </head>
  <body>
          <h1>產品搜尋結果</h1>
          <p><b>摘要:</b>搜尋字串:“滑鼠 鍵盤”,共找到 2 筆</p>
            <table>
              <tr>
 10                       <th>品名</th>
 11                       <th>定價</th>
 12                       <th>說明頁</th>
 13             </tr>
 14             <tr>
 15                       <td>手不痛健康滑鼠</td>
 16                       <td>$234</td>
 17                       <td><a href="http://foo.bar/kbd/83424723">上市發表會</a></td>
 18             </tr>
 19             <tr>
 20                       <td>打不響靜悄悄鍵盤</td>
 21                       <td>$567</td>
 22                       <td><a href="http://foo.bar/mouse/12478943">產品特性</a></td>
 23             </tr>
 24           </table>
 25 </body>
 26 </html>



上面這個例子其實是來自於《無廢話 XML》這本書。這個例子要在 IE 中正常顯示只需要改一點點內容,這個任務留給你們課後去做。
關於 XSLT 首先應該看《無廢話 XML》這本書,這本書裏對 XSLT 的講解是很清楚的。XSLT 我們在目前的開發中也用不到,但是 XSLT 在 XML 中是非常基礎的知識,所以我在這一部分中用了較大的篇幅來講述。

知道了這麼多,你可能會認爲 HTML+CSS 已經是是落後的技術,應該完全被 XML+XSLT 取代。這其實是一個錯誤的觀念,連 W3C 都沒有敢肯定 HTML+CSS 一定會被 XML+XSLT 取代。XML+XSLT 的主要缺點是成本和複雜性。由於缺乏所見即所得的(WYSIWYG)頁面編輯器的支持,對於實現相同顯示效果的複雜頁面,XML+XSLT 的工作量要比 HTML+CSS 大得多。而且頁面製作人員完全不能適應 XML+XSLT 的工作方式(這是程序員的工作方式),強求他們採用 XML+XSLT 是不現實的。目前 Dreamweaver 已經可以非常好地支持 CSS 了。所以在可預測的未來很長一段時間內,HTML+CSS 仍然是 Web 頁面開發的主流技術。當然 HTML 將逐漸被 XHTML 所代替,但是這是另外的問題。XHTML 就是用 XML 來改造 HTML,使 HTML 至少符合 XML 格式正確的要求。符合 XHTML 標準的頁面還有一些其它要求,感興趣的可以看看《XML 高級編程》這本書。

以上這些就是我這次培訓的所有內容。這些都是我認爲的關於 XML 的基礎知識,希望通過這次講解以及課後的學習能夠掌握好。掌握好了這些知識,再去掌握其它與 XML 相關的知識就是輕而易舉的了。

相關資料:
1、《無廢話 XML》
2、《W3C XML 規範》
3、《XML 高級編程》
4、《Java 與 XML》
5、《XML Schemas》


術語列表:
HTML:HyperText Markup Language,超文本標記語言
SGML:Standard Generalized Markup Language,標準通用標記語言。
XML:eXtensible Markup Language,可擴展標記語言。
DTD:Document Type Definition,文檔類型定義。
XML Schema:XML 模式
RELAX NG:REgular LAnguage description for XML Next Generation,下一代的 RELAX。
DSSSL:Document Style Semantics and Specification Language,文檔樣式語義和規範語言
XSLT:eXtensible Stylesheet Language——Transformation,可擴展樣式單語言轉換部分

PI:Processing Instruction,處理指令。
XPath:XML 路徑描述。
namespace:名字空間。

DOM:Document Object Model,文檔對象模型。
SAX:Simple API for XML,XML 簡單 API。
JAXP:Java API for XML Parsing
JDOM:Java Document Object Model
DOM4J:Document Object Model for Java

發佈了80 篇原創文章 · 獲贊 0 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章