# XML 學習筆記
整理:Jims of [肥肥世家](http://www.ringkee.com)
[jims.yang@gmail.com](mailto:jims.yang@gmail.com)
Copyright ? 2004 本文遵從GNU 的自由文檔許可證(Free Document License)的條款,歡迎轉載、修改、散布。
發布時間:2004年12月03日
最近更新:2006年02月17日,新增CSS內容
**Abstract**
XML技術是Internet技術的又一次革命。本筆記記錄標記語言的歷史和發展,還有我的學習歷程。
**Table of Contents**
+ [1\. XML簡介](#id2875121)
+ [2\. XML語法](#id2810081)
+ [2.1\. 基本語法規則](#id2810137)
+ [2.2\. 良構XML文檔和有效XML文檔](#id2810559)
+ [2.3\. XML文檔的組成](#id2810333)
+ [2.4\. XML文檔樹](#id2810496)
+ [3\. DTD](#id2810509)
+ [3.1\. 文檔類型聲明](#id2861409)
+ [3.2\. 元素聲明](#id2861485)
+ [3.3\. 屬性聲明](#id2861808)
+ [3.3.1\. 屬性類型](#id2861852)
+ [3.3.2\. 屬性缺省值](#id2808545)
+ [3.4\. 實體](#id2808624)
+ [4\. XML名稱空間](#id2808845)
+ [5\. XHTML](#id2809084)
+ [6\. 樣式表](#id2875593)
+ [6.1\. CSS2](#id2875778)
+ [6.2\. XSLT](#id2876470)
+ [6.3\. XPath](#id2876923)
+ [6.3.1\. 匹配模式](#id2877015)
+ [6.3.2\. XPath軸](#id2877227)
+ [6.3.3\. 謂詞](#id2877462)
+ [6.3.4\. XPath表達式](#id2877773)
+ [6.3.5\. XPath函數](#id2877892)
+ [6.4\. XLink](#id2877959)
+ [7\. 分析XML](#id2878164)
+ [7.1\. 分析器工具](#id2878286)
+ [7.2\. Unicode](#id2878314)
+ [A. 附錄](#id2878622)
+ [A.1\. 標記語言的歷史](#id2878629)
+ [A.2\. XML相關技術名詞解釋](#id2878688)
+ [A.3\. XML應用](#id2878814)
## Chapter 1\. XML簡介
XML(eXtensible Markup Language,可擴展標記語言)是SGML的一個子集,但比SGML簡單,用以創建可相互轉換的結構化文本文檔和數據文檔。下面說明一下與XML相關的一些概念。
* SGML(Standard Generalized Markup Language,標準通用標記語言),由于IBM公司的三位先驅者Charles GoldFarb、Edward Mosher和Raymond Lorie創立,主要作為大型文檔的編制工具。DTD(Document Type Definition,文檔類型定義)是SGML文檔的核心,它定義了SGML文檔必須遵循的一組語法規則。由于它很復雜,所以只是在一些大公司或大項目中使用。直到HTML面世,它還是默默無聞。
* HTML(Hypertext Markup Language,超文本標記語言),它是在SGML框架中通過DTD定義的標記語言,是SGML的一種應用。它由于結構簡單,容易學習而迅速普及,每個人都能很快地建立自已的頁面,HTML造就了現時Internet上無數的信息資源。HTML標記只描述文檔的外觀,而不描述文檔的內容本身--里面有什么。HTML是不明白網頁內容的,這樣就造成了內容搜索的差異和不確定性。另一個問題是,HTML不是可擴展的,這意味著沒有一種方便的途徑來擴展標記。每一個新標記的引入都會造成系統的不一致性和對標準的修訂。這就是為什么現在我們用不同的瀏覽器瀏覽同一個網站時表現效果會有差異。
* XHTML(eXtensible Hypertext Markup Language,可擴展超文本標記語言),它是按XML規則編寫的HTML,由于有統一的規則約束,所以它不會出現如HTML一樣的不規范、不一致性問題。
* XML(eXtensible Markup Language,可擴展標記語言),繼承了SGML的優點,但又沒有了SGML的復雜性。XML專門為WEB應用而設計,和HTML不同,它是一種元標記語言(meta-markup language),也就是說它沒有一套能夠適用于各個領域中所有用戶的固守的標簽和元素,相反,它允許開發者根據自已的需要定義自已的元素,XML中的X(eXtensible)就是說明了這一點。它的特點有:
* XML使用Unicode字符集,可生成英文、中文、希臘文或梵文等多種語言。
* 可將多個來源(包括其他XML文檔和二進制文件)匯合進一個XML文檔。
* 可利用DTD或Schema(模式)管理一致性問題。DTD主要用于文檔型文檔,Schema主要用數據型文檔。
* 具有很好的擴展性,可定義自已的元素和屬性。
* 通過XML可從關系數據庫管理系統中提取數據到結構化文檔。它還被設計成可對各種數據對象進行操作。
* 在一個設計良好的XML應用中,XML標記不涉及文檔如何顯示,只表示文檔的結構。
> XML被設計用來存儲、支持和交換數據,而不是用來顯示數據的。通常,XML被用于數據交換,而不是數據存儲。
* 元數據,定義數據的數據。
* 標記語言是一種定義文檔的格式語言。SGML、XML、XHML、HTML都屬標記語言。
XML文檔是什么?它有時是一個文件,有時是關系數據庫中的一條記錄,有時是由Object Request Broker(對象請求代理程序)傳送的一個對象,有時是到達網絡接口的一個字節流。XML文檔可使不同系統、不同平臺的數據實現統一接口,這就是XML真正的威力所在。下面列舉幾個使用XML的領域:
* 文檔設計和管理,可利用XML維護公司的文檔資料。
* Web開發,利用XHTML和XSLT實現的Web頁面擴展性更好,更容易維護。
* 數據庫應用和程序開發,可從數據庫中提取數據并生成XML文檔,實現信息的跨平臺、跨系統溝通。
* 定義其它語言,WML和WAP就是用通過XML建立的。
XML不是什么?
* XML只是一種標記語言,不是一種編程語言。不存在一種編譯器,把XML文檔轉化成可執行二進制代碼。
* XML不是一種網絡傳輸協議,但通過網絡協議傳輸的數據格式則可以是XML格式的。
* XML不是數據庫,不能替代Oracle或MySQL這類的關系數據庫管理系統。
## Chapter 2\. XML語法
創建一個簡單的index.xml文檔:
```
< xml version="1.0" >
< xml-stylesheet type="text/xsl" href="basic.xsl" >
<basic>Hello World</basic>
```
下面創建一個名為basic.xsl的XML樣式表(XSL),以便在瀏覽器中顯示XML文檔內容:
```
< xml version="1.0" >
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
<title>a basic stylesheet</title>
</head>
<body>
<xsl:value-of select="/" />
</body>
</html>
</xsl:template>
</xsl:stylesheet>
```
接著在瀏覽器中打開index.xml文檔,則可顯示“Hello World”。上面兩個文檔都是合法的XML文件,具體的語法規則下面會詳細介紹,上例可先給大家一個感性的認識。
合法的XML文檔可有種意思,一個是良構文檔(well-format),即符合XML規則書寫的文檔;另一種是有效文檔,是已驗證符合一個DTD的文檔。
## 2.1\. 基本語法規則
* XML是區分大小寫的;
* 所有元素的起始和結束標注必須成對出現,且要正確嵌套;
* 如果使XML說明,則它必須是XML文檔的第一行:
```
< xml version="1.0" >
```
* 元素屬性必須用引號引起來,單、雙引號都可以,但必須成對出現。如:
```
<basic attr="1.0">
<basic attr='1.0'>
```
* XML命名規則:
* XML名以下劃線或字母開始;
* XML名可包含字母、數字、句點、下劃線和冒號;
* XML名不能包含空格;
* XML名不能以數字開始,但可包含數字;
* XML名區分大小寫。
* 保留標記字符,如果要在XML中顯示<或&之類的標記,就要使用字符的實體形式,XML中有五種預先定義了的實體:
```
< 表示<字符
> 表示>字符
& 表示&字符
' 表示'字符
" 表示"字符
```
我們也可用ENTITY自定義實體:
```
<!ENTITY linux "linux is a very good system">
這樣我們可用&linux;來調用。
```
* XML文檔內容中的空格是有意義的,在轉換后會保留。
* 空元素以<開始并以/>結束,如<br/>。
## 2.2\. 良構XML文檔和有效XML文檔
符合XML語法規則的XML文檔稱為良構文檔,這些規則如下:
* 應當只有一個父標志,由父標志派生所有其它子標志,在一個文檔中不能存在多個父標志。
* 嵌套元素應按正確的順序開始和結束。
* 子標志應在父標志完成前關閉。
* 屬性值應放在雙引號中。
通過某個DTD或Schema驗證的文檔稱為有效XML文檔。
## 2.3\. XML文檔的組成
* XML聲明:
* version,定義XML規范的版本號,到現在為止,只有一個版本號1.0。
* encoding,指定文檔的編碼系統。
* standalone,定義文檔是獨立的還是需要裝入其他元素才能正確分析。如果XML文檔沒有外部實體或DTD,則可以設置為no,否則設置為yes。可用該值提高性能:如果為no,則可提高處理速度;如果設置為yes,則首先要分析文檔,確定需要其他哪些文件,然后才能完全分析文檔。
* 根元素,每篇XML文檔都需要有且只能有一個根元素。由元素是文檔的第一個元素,包含其它所有元素。下例的portal就是根元素,如:
```
<portal>
<name>jims</name>
<email></email>
...
</portal>
```
* 屬性,每個元素都可以設置一個或多個屬性,如:
```
<portal>
<name id='1',sex="male">Jims</name>
</portal>
```
元素和屬性都可以表示信息,什么時候使用元素,什么時候使用屬性呢?屬性信息表現能力有限,它只能表示字符串。所以當需靈活表示信息時應該使用元素。一般把信息主體放到元素中,屬性只放一些注釋或額外的信息。
* CDATA部份,它用<![CDATA[和]]>表示,它們之間的數據作為原始字符顯示,唯一不能出現的標志是]]>。
* 注釋,注釋是很重要,不論是在編寫程序和文檔時,所以XML也提供了注釋功能,以<!--開頭-->結尾的一對區間為注釋。在以-->結束之前,不能出現“--”號,“---”更不允許。
* 處理指令,處理指令以< 開頭以 >結尾。如PHP處理指令可寫成,< php ... >。處理指令是標記,而不是元素。因此,與注釋一樣,處理指令可出現在XML文檔的標簽外的任何位置,包括根元素之前或之后。最常見的處理指令是,xml-stylesheet樣式表指令,它會告訴瀏覽器在顯示文檔時應用什么樣式表。如:
```
< xml-stylesheet href="sample.css" type="text/css" >
<portal>
<name>...</name>
...
</portal>
```
## 2.4\. XML文檔樹
XML文檔是一種結構化的文檔,可用樹的形式表示出來。樹是一種由節點和分支組成的簡單結構,兩個節點間由分支連接。上端的節點稱為父節點,下端的節點稱為子節點。一個節點如果沒有父節點,則稱為樹的根節點(根),每個樹必須有且只能有一個根節點。一個節點如果沒有子節點,則稱為樹的葉節點。只有一個節點的樹也是允許的。
## Chapter 3\. DTD
由于XML可自定義標簽,所以每個人定義的標簽集都會不同,如果沒有一套標準來規定標簽的定義原則,則應用程序就不能對XML文檔進行處理。解決該問題的方案采用DTD,DTD(Document Type Definition,文檔類型定義),用于定義XML文檔的編寫規則。如哪些元素可出現在文檔中,及元素的內容和屬性的要求等。應用程序會利用這個DTD對文檔進行檢驗,符合DTD約束規則的XML文檔稱之為有效文檔,可以進行下一步處理,否則會報錯,應用程序可捕獲該錯誤進行相應的異常處理。檢驗過程是可選,這要視具體應用而定。
## 3.1\. 文檔類型聲明
要使用DTD進行有效性檢驗,就要使用文檔類型定義聲明指定DTD。如:
```
< xml version="1.0" standalone="no" >
<!DOCTYPE portal SYSTEM "http://www.w3c.com/dtd/portal.dtd">
<portal>
<name>Jims</name>
<email>Jims@163.com</email>
<email>Jims@21cn.com</email>
</portal>
```
文檔類型聲明位于XML聲明之后,根元素之前。如果dtd文檔位于本機,可用路徑名直接指出dtd文檔的位置。portal.dtd的內容如下:
```
<!ELEMENT portal (name,email*)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT email (#PCDATA)>
```
上面的內容也可直接寫到XML文檔內,這種dtd聲明方式叫內部dtd子集,如:
```
< xml version="1.0" standalone="no" >
<!DOCTYPE portal [
<!ELEMENT portal (name,email*)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT email (#PCDATA)>
]>
<portal>
<name>Jims</name>
<email>Jims@163.com</email>
<email>Jims@21cn.com</email>
</portal>
```
如果dtd位于XML文檔外,則叫外部dtd子集。我們可以結合內外dtd,共同組成一個dtd來為XML文檔作驗證。如:
```
<!DOCTYPE portal SYSTEM "external.dtd" [
<!ELEMENT portal (name,email*)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT email (#PCDATA)>
]>
```
注意,使用內外dtd時,這兩個dtd要互相兼容,不能有沖突。
## 3.2\. 元素聲明
上節文檔類型聲明中的每一項都是元素聲明,定義了每個元素的約束。元素聲明的格式為:
```
<!ELEMENT element_name (content_model)>
```
有效文檔中使用的每個元素都必須在文檔的DTD中用元素聲明進行聲明。element_name可是任何合法的XML名稱,content_model(內容模型)指定元素可以或必須包含的子元素以及子元素的順序。下面具體介紹內容模型的內容。
* #PCDATA,規定元素只包含已析的字符數據。下面聲明指出一個name元素可以包含文本,但不能劃分為獨立的area_code、number和extension元素:
```
<!ELEMENT name (#PCDATA)>
```
* 子元素,可指明元素的子元素。下面聲明表示name元素必須包含且只包含一個desc元素。
```
<!ELEMENT name (desc)>
```
也可用逗號為分隔符,指明多個子元素。并且子元素出現的次序必須按定義時的順序。如:
```
<!ELEMENT name (id,desc)>
```
name元素的id子元素必須在desc子元素前面,否則驗證會出錯,該文檔不是一個有效的XML文檔。
```
下面這個文檔是有效的
<name>
<id>1</id>
<desc>dtd test</desc>
</name>
下面這個文檔是無效的,順序顛倒了
<name>
<desc>dtd test</desc>
<id>1</id>
</name>
下面的文檔也是無效的,有多余的元素
<name>
<id>1</id>
<desc>dtd test</desc>
<date>2005/01/31</date>
</name>
```
* 子元素的個數,我們可通過正則表達式來規定子元素的個數。
* ,允許零個或一個該元素
* \*,允許零個或多個該元素
* +,允許一個或多個該元素
下面我們可利用這些符號規定id子元素必須出現,且只能出現一次,而desc子元素可選。
```
<!ELEMENT name (id,desc*)>
```
根據上面的聲明,下面的name元素都是有效的。
```
<name>
<id>1</id>
<desc>dtd test</desc>
</name>
<name>
<id>2</id>
</name>
<name>
<id>3</id>
<desc>dtd test</desc>
<desc>another test</desc>
</name>
```
* 可選項(|),選項是一個參數列表,每個參數間用“|”分隔,代表能且只能選一個子元素。
```
<!ELEMENT choice (good | bad)>
```
上例的choice元素可選一個good子元素,或bad子元素,且只能從選一個。可選的參數列可以多項,不限于兩項。如:
```
<!ELEMENT choice (one | two | three | four)>
```
* 小括號,可用小括號把選項括起來,以表達更豐富的意思,如我們想表示choice元素必須包含一個good子元素,并且必須包含ok子元素或bad子元素的一個。
```
<!ELEMENT choice (good,(ok|bad))>
```
* 混合內容,在一些文檔中,一個元素可能既包含子元素,也包含字符串,這些內容叫混合內容。可用以下方式表示:
```
<!EMEMENT description (#PCDATA | term)* )>
```
該聲明表示description元素可包含已析的字符串和term子元素,且允許出現零次或多次,如:
```
<description>
this is a <term>dtd</term> test.
</description>
```
#PCDATA必須在第一位,可選的子元素可任意多項。
* 空元素,某些元素不用包含任何內容,稱之為空元素。寫成以/>結束的獨立標簽。
```
<!ELEMENT image EMPTY>
```
示例:
```
<image src="http://www.xml.com/dtd.jpg" />
```
* ANY,允許元素內包含任意內容。該選項在dtd測試時很有用,在生產系統中盡量不要使用。
```
<!ELEMENT page ANY>
```
## 3.3\. 屬性聲明
一個有效的XML文檔,必須對元素的屬性進行聲明。使用ATTLIST聲明來完成,一個ATTLIST可以為一個元素類型聲明多個屬性。
```
<!ATTLIST image src CDATA #REQUIRED>
```
上例聲明image元素必須有一個src屬性,該屬性的值是字符數據。可用ATTLIST聲明為一個元素聲明多個屬性,如:
```
<!ATTLIST image src CDATA #REQUIRED
width CDATA #REQUIRED
height CDATA #REQUIRED
alt CDATA #IMPLIED
>
```
上述聲明指出src、width、height屬性是必須的,alt屬性是可選的。
### 3.3.1\. 屬性類型
* CDATA類型屬性值可包含任意文本字符串。DTD不能指定屬性為一個整數或一個日期,Schema能提供更為強大的數據類型。
* NMTOKEN類型屬性值是一個XML名稱記號。XML名稱記號與XML名稱類似,但XML名稱記號允許所有的字符作為名稱的開始字符,而XML名稱的第一個字母必須是字母、表意字符和下劃線。因此10,.bashrc是合法的XML名稱標記,但不是合法的XML名稱。每個XML名稱都是一個XML名稱標記,然而XML名稱標記不全是XML名稱。如果屬性包含1990,2005之類的整數,則應該指定其類型為NMTOKEN。如:
```
<!ELEMENT person birthday NMTOKEN #REQUIRED>
```
* NMTOKENS類型屬性包含一個或多個用空白分隔的XML名稱記號。如:
```
<person dates="02-01-2005 03-01-2005 05-01-2005">person</person>
```
對應的聲明應為:
```
<!ATTLIST person dates NMTOKENS #REQUIRED>
```
另一方面,對01/02/2005這樣的形式不能使用該聲明,因為其中的正斜杠不是合法的名稱字符。
* 枚舉聲明,枚舉不用關鍵字。直接列舉所有的值,中間用豎線分隔。如:
```
<!ATTLIST date month(January | February | March | April | May | June | July | August | September | October | November | December) #REQUIRED>
```
針對上述聲明,date元素的month屬性可選十二個月份的中一個。
* ID類型的屬性必須包含一個XML名稱,而且該名稱在文檔中是獨一無二的。ID屬性可為元素分配一個唯一的標識符。
```
<!ATTLIST name card_id ID #REQUIRED>
```
由于數字不是合法的XML名稱,所以ID編號不能以數字開頭,解決辦法是在前面加下劃線或字母。
* IDREF類型的屬性指向文檔中某元素的ID類型的屬性。因此,它必須是一個XML名稱,它的作用是當簡單的包含關系不能滿足要求時在元素間建立多對多關系。如:
```
<project project_id="p1">
<goal>deploy linux</goal>
<team_member person_card_id="c123">
</project>
<person card_id="c123">
<name>linuxsir</name>
<assignment project_project_id="p1">
</person>
```
project元素的project_id屬性和person元素的card_id屬性應該是ID類型。team_member元素的person_card_id屬性和assignment元素的project_project_id屬性是IDREF類型。對應的聲明如下:
```
<!ATTLIST person card_id ID #REQUIRED>
<!ATTLIST project project_id ID #REQUIRED>
<!ATTLIST team_member person_card_id IDREF #REQUIRED>
<!ATTLIST assignment project_project_id IDREF #REQUIRED>
```
* IDREFS類型的屬性包含一個XML名稱列表。名稱間用空白間隔,且每個名稱都是文檔中某個元素的ID。當某個元素需要引用多個其他元素時使用該元素。如:
```
<!ATTLIST person card_id ID #REQUIRED
assignment IDREFS #REQUIRED>
<!ATTLIST project project_id ID #REQUIRED
team IDREFS #REQUIRED>
```
對應的文檔可寫成:
```
<project project_id="p1" team="c123">
<gold>deploy linux</gold>
</project>
<person card_id="c123" assignment="p1">
<name>Linuxsir</name>
</person>
```
* ENTITY類型的屬性包含在DTD的其它位置聲明的未析實體的名稱中。如movie元素可能有一個標識激活時播放mpeg或rm文件的實體屬性:
```
<!ATTLIST movie src ENTITY #REQUIRED>
```
如果DTD聲明了一個名為play的未析實體,則此movie元素可用于在XML文檔中嵌入視頻文件:
```
<movie src="play" />
```
* ENTITIES類型的屬性包含在DTD的其它位置聲明的多個未析實體名稱,其間用空白隔開。
```
<!ATTLIST slide_show slides ENTITIES #REQUIRED>
```
如果DTD聲明了未析實體slide1、slide2、slide3、...,則可使用slide_show元素在XML文檔中嵌入幻燈片。
```
<slide_show slides="slide1 slide2 slide3" />
```
* NOTATION類型的屬性包含在文檔的DTD中聲明的某個記法的名稱。該屬性類型較少用。理論上,可以使用該屬性使某些特殊元素與類型相關聯,下例聲明為不同的圖像類型定義了4個記法,然后規定每個image元素都必須從中選擇一種type屬性。
```
<!NOTATION gif SYSTEM "image/gif">
<!NOTATION tiff SYSTEM "image/tiff">
<!NOTATION jpeg SYSTEM "image/jpeg">
<!NOTATION png SYSTEM "image/png">
<!ATTLIST image type NOTATION (gif | tiff | jpeg | png) #REQUIRED>
```
每個image元素的type屬性的值可以為gif,tiff,jpeg和png四個值中的一個。該屬性比枚舉類型稍具優勢,因為記法的實際MIME媒體類型在理論上是可用的。由于斜杠在XML名稱中不是一個合法字符,所以枚舉類型不能指定image/png或image/jpeg作為允許值。
### 3.3.2\. 屬性缺省值
每個ATTLIST聲明除了要提供一種數據類型外,還要聲明屬性的缺省行為。
* #IMPLIED,屬性可選。
* #REQUIRED,屬性必須有。
* #FIXED,屬性是常量,不能更改。
```
<!ATTLIST person name CDATA #FIXED "linuxsir"
```
* Literal,作為一個引用字符串的實際缺省值。
```
<!ATTLIST person name NMTOKEN "linuxsir"
```
如果沒有顯示指明person元素的name屬性,則該值為linuxsir。
## 3.4\. 實體
* 用ENTITY聲明定義實體。如:
```
<!ENTITY linux "linux is a very good system">
用&linux;可引用該字符串
```
* 可定義一個外部實體,引用外部XML文檔
```
<!ENTITY linux SYSTEM "/home/linux/test.xml">
使用&linux;可引用/home/linux/test.xml文檔
```
外部實體沒有XML聲明,但可以有文本聲明,兩者很類似,主要區別是文本聲明必須有編碼聲明,而版本信息則是可選的。
```
< xml version="1.0" encoding="gb2312" > 是一個合法的文本聲明
< xml encoding="gb2312" > 也是一個合法的文本聲明
```
* 不是所有的數據都是XML。如jpeg照片,mpeg電影等。XML建議使用外部未析實體作為在文檔中嵌入這些內容的機制。DTD為包含非XML數據的實體指定一個名稱和URI。
```
<!ENTITY movie SYSTEM "/home/linux/test.avi" NDATA avi>
```
由于數據不是XML格式,所以使用NDATA聲明指定數據類型。avi是在NOTATION中定義的MIME媒體類型。在XML中嵌入未析實體很復雜且不規范,盡量不要使用。
* 參數實體可定義一組通用的實體,在文檔中可通過該參數實體來引用實體。參數實體的定義與通用實體定義類似,只是中間多了一個%,引用時也是用%代碼&。
```
<!ENTITY % person "name,address,postcode">
引用方法
%person;
這樣會用name,address,postcode代替參數實體%person;
```
* 通常DTD都比較大,DocBook的DTD長達11000多行,如果把它存放在單一文件中,管理和維護起來都非常困難。我們可以使用外部DTD子集,把一個大的DTD按功能分成不同的功能塊,存放在不同的文件中。再通過外部參數實體聲明引入當前DTD中,如:
```
定義參數實體引用外部names.dtd
<!ENTITY % names SYSTEM "names.dtd">
調用外部DTD子集
%names;
```
* 使用IGNORE關鍵字可注釋聲明,如:
```
<![IGNORE[
<!ELEMENT note (#PCDATA)>
]]>
```
當然了,使用<!-- 注釋 -->的方式也是一樣的。
* INCLUDE關鍵字表示DTD中的確在使用給定的聲明,如:
```
<![INCLUDE[
<!ELEMENT note (#PCDATA)>
]]>
```
單從該聲明來看,有沒有使用INCLUDE效果都一樣,但如果組合INCLUDE和IGNORE,可實現DTD功能的選擇。我們可定義一個參數實體:
```
<!ENTITY % note_allowed "INCLUDE" >
```
然后使用參數實體引用而不使用關鍵字:
```
<![%note_allowed;[
<!ELEMENT note (#PCDATA)>
]]>
```
按上述操作,元素聲明是有效的,但我們也可以把參數實體%note_allowed重新定義為IGNORE,這樣,該元素聲明就無效了。
## Chapter 4\. XML名稱空間
* XML名稱空間表示XML名稱的使用范圍,因為XML可自定義元素標簽,所以有不同XML應用間XML名稱重名的機會是很大的。如果沒有一種方法來區分不應用的名稱,就會造成混亂。XML名稱空間就是為了解決這個問題而設計的。通過XML名稱空間,我們可以區分來自不同的XML應用的具有相同名稱的元素和屬性。可以將來自單一XML應用的相關元素和屬性集合在一起,方便軟件識別和處理。
* 名稱空間由前綴和本地部分組成,中間用冒號分隔。前綴標識元素或屬性的所在名稱空間,本地部分標識名稱空間中的某個元素或屬性。整個名稱也稱為限定名稱(qualified name)。前綴可以用除XML(大小寫任意組合)三個字母外的任何合法的XML名稱字符組成。每個限定名稱中的前綴都必須與唯一的一個URI關聯。帶有相同URI關聯的前綴的名稱屬于同一名稱空間。
```
<rdf:RDF xmlns:rdf="http://www.w3.org/TR/REC-rdf-syntax#">
<rdf:Description about="http://www.example.com/test.xml">
<title>example</title>
<author>linuxsir</author>
...
</rdf:Description>
</rdf:RDF>
```
上例rdf:RDF元素的xmlns:rdf屬性將前綴rdf綁定到名稱空間 http://www.w3.org/TR/REC-rdf-syntax# 。屬性xmlns:rdf為rdf:RDF元素及其子元素聲明了前綴rdf。RDF處理器將把rdf:RDF和rdf:Description作為RDF元素,因為兩個元素都具有與RDF規范定義的某個URI相綁定的前綴。處理器不會認為title,author等元素為RDF元素,因為它沒有綁定到相同URI的rdf前綴。
前綴一般在使用該前綴的最上層元素中定義。在下層元素中也可定義不同的前綴:
```
<rdf:RDF xmlns:rdf="http://www.w3.org/TR/REC-rdf-syntax#">
<rdf:Description xmlns:dc="http://www.w3.org/dc/"
about="http://www.example.com/test.xml">
<dc:title>example</dc:title>
<dc:author>linuxsir</dc:author>
...
</rdf:Description>
</rdf:RDF>
```
不帶前綴的屬性,如about,不屬于任何的名稱空間。如xlink:type和xlink:href屬性屬于xlink名稱空間,當然,前提是你要先把xlink綁定到一個URI。URI不必須是一定存在的http鏈接,它只是一種表示的方法,以區分不同的名稱空間。
* 通過將無前綴的xmlns屬性附加到根元素中,可以指定不帶前綴的元素及所有不帶前綴的子元素屬于某個名稱空間。
```
<svg xmlns="http://www.w3.org/2000/svg">
<ellipse rx="110" ry="130" />
<rect x="4cm" y="1cm" />
</svg>
```
這里,雖然所有元素都沒有前綴,但它都同屬一個名稱空間。但屬性屬不同名稱空間,因為默認名稱空間只應用于元素。默認名稱空間在子元素中也用相同的方法重新設置。
* 如果名稱空間只用來識別來自某種XML應用的元素和屬性,而不是用來區分具有相同名稱的不同元素,則可在DTD的元素中定義一個固定的xmlns屬性,而不需要文檔中定義。定義方法如下:
```
<!ATTLIST svg xmlns CDATA #FIXED "http://www.w3.org/svg/">
```
* 在定義DTD時,需要使用名稱空間前綴的在定義時也要把前綴寫到DTD定義里,如:
```
<!ELEMENT xlink:name (#PCDATA)>
```
* 使用參數實體引用來定義名稱空間前綴可方便DTD文檔的維護,如:
```
<!ENTITY % prefix "xlink">
<!ENTITY % colon ":">
```
接著,利用該參數實體名稱定義更多的參數實體引用,如:
```
<!ENTITY % xlink-title "%prefix;%colon;title">
<!ENTITY % xlink-author "%prefix;%colon;author">
```
這樣,如果需更改前綴,只需修改一個地方就可以了,不用整篇文檔修改。
```
<!ELEMENT %xlink-title; (#PCDATA)>
<!ELEMENT %xlink-author; (#PCDATA)>
```
> 不能在ATTLIST和ELEMENT聲明中直接使用%prefix;和%colon;,因為在另一個實體的外部使用這些參數實體時,XML解析器會在實體替換文本的兩邊添加額外的空格。
## Chapter 5\. XHTML
XHTML是W3C推薦的一種標準,它定義了一種與XML兼容的HTML版本。XHTML文檔是一個有效的XML文檔,所以編寫格式比HTML嚴格。如果需從HTML文檔轉換成XHTML文檔,需作以下更改:
* 在XHTML中不允許省略結束標簽,所以需補齊缺少的標簽。
* 元素需按正確的順序嵌套。
* 所有元素和屬性的名稱都采用小寫。
* 屬性值需添加引號,如<p align="center">。
* 所有屬性都需有屬性值。
* 采用&和<等的實體形式表示這些字符。
* 確保文檔有單一根元素,最好用html。
* 像<hr>這樣的空元素要改成<hr/>或<hr><hr/>。
* 注釋應由<! 注釋 >的形式改成<!-- 注釋 -->。
* 文檔編碼應采用UTF-8或UTF-16,或者添加XML聲明指定文檔的編碼方式。
* 需去掉非標準的元素。如:marguee。
* 添加一個DOCTYPE聲明,用PUBLIC來指向XHTML的三種DTD中的一種。分別是Strict、Transitional和Frameset,一般使用Strict。
* Strict(嚴格型),W3C推薦的XHTML形式。不包括一些非標準的元素和屬性,如applet和center等。聲明方式如下:
```
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
```
* Transitional(過渡型),一種不太嚴格的XHTML格式,可使用一些非標準的元素和屬性,如applet和bgcolor等。聲明方式如下:
```
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
```
* Frameset(框架型),與過渡型DTD類似,允許使用與框架相關的元素,如frameset和iframe。聲明方式如下:
```
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
```
* 文檔的根元素必須具有xmlns屬性,標識缺省的名稱空間提 http://www.w3.org/1999/xhtml 。
下面是一個標準的XHTML文檔的示例:
```
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns:"http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-type" content="text/html; charset=gb2312">
<title>xhtml example</title>
</head>
<body>
...
</body>
</html>
```
由HTML轉到XHTML是一種枯燥而乏味的工作,現在有一種叫tidy的開源工具可幫我們完成大部份的工作,它是一個C程序,使用方法如下:
```
% tidy --output-xhtml yes test.html test.xml
```
XHTML 1.1把XHTML的三種DTD分成獨立模塊。我們可根據實際情況包含或省去某些模塊。這些模塊是:
* Structure Module(結構模塊)--->%xhtml-struct.module;,包含HTML文檔主要的元素,如:html、head、title和body。
* Text Module(文本模塊)--->%xhtml-text.module;,包含文本的基本元素和其內聯元素,如:h1、h2、...、strong、span等。
* Hypertext Module(超鏈接模塊)--->%xhtml-hypertext.module;,包含用于鏈接的元素,如:a元素。
* List Module(列表模塊)--->%xhtml-list.module;,包含用于列表的元素,如:dl、dt、dd、ul、ol和li。
* Applet Module(applet模塊)--->%xhtml-applet.module;,Java所需要元素,如:applet和param。
* Presentation Module(表示模塊)--->%xhtml-pres.module;,面向表示的標記:b、big、hr、I、small、sub、sup和tt。
* Edit Module(編輯模塊)--->%xhtml-edit.module;,用于修正的元素,如:del和ins。
* Bidirectional Text Module(文本方向模塊)--->%xhtml-bdo.module;,用于指定文本閱讀的方向,如bdo元素。
* Basic Forms Module(基本表單模塊)--->%xhtml-basic-form.module;,用于HTML 3.2的表單元素,如:form、input、select、option和textarea。
* Forms Module(表單模塊)--->%xhtml-form.module;,用于HTML 4.0的表單元素,如:form、input、select、option、textarea、button、fieldset、label、legend和optgroup。
* Basic Tables Module(基本表格模塊)--->%xhtml-basic-table.module;,基本的表格元素,如:table、caption、th、tr和td。
* Table Module(表格模塊)--->%xhtml-table.module;,安全功能的表格支持,如:table、caption、th、tr、td、col、colgroup、tbody、thead和tfoot。
* Image Module(圖像模塊)--->%xhtml-image.module;,包含img元素。
* Client-side Image Map Module(客戶端圖像映像模塊)--->%xhtml-csismap.module;,包含map和area元素以及支持客戶端圖像映像所需要的元素的屬性。
* Server-side-Image Map Module(服務器端圖像映像模塊)--->%xhtml-ssismap.module;,該模塊沒有添加新元素,但對img元素添加了一個ismap屬性。
* Object Module(對象模塊)--->%xhtml-object.module;,用于在網頁中嵌入可執行內容,如:java程序。
* Param Module(參數模塊)--->%xhtml-param.module;,網頁中可執行內容中傳遞參數的param元素。
* Frames Module(框架模塊)--->%xhtml-frames.module;,包含實現框架所需的元素,如:frame、frameset和noframes。
* Iframe Module(內聯框架模塊)--->%xhtml-iframe.module;,包含內聯框架的iframe元素。
* Intrinsic Events(固有事件模塊)--->%xhtml-events.module;,支持如onSubmit和onFocus等腳本的屬性。
* Meta-information Module(元信息模塊)--->%xhtml-meta.module;,包含meta元素。
* Scripting Module(腳本模塊)--->%xhtml-script.module;,支持JavaScript等腳本。
* Stylesheet Module(樣式表模塊)--->%xhtml-style.module;,用于定義CSS的style元素。
* Link Module(鏈接模塊)--->%xhtml-link.module;,指定外部文件,如樣式表、庫等關系的link元素。
* Base Modue(基模塊)--->%xhtml-base.module;,包含base元素,指定解析相對URL所參照的基URL。
* Target Module(目標模塊)--->%xhtml-target.module;,用于指定目標框架或框架中某個窗口的target屬性。
* Style Attribute Module(樣式屬性模塊)--->%xhtml-inlstyle.module;,將CSS樣式應用于文檔中單個元素的style屬性。
* Name Identification Module(名稱標識模塊)--->%xhtml-nameident.module;,name屬性是id屬性的早期版本,現在不推薦使用。
* Legacy Module(傳統模塊)--->%xhtml-legacy.module;,不推薦使用的元素和屬性,如:basefont、center、fonts、strike和u元素。
* Ruby Module(Ruby模塊)--->%xhtml-ruby.module;,東亞文本中用于將少量文本放于正文文本旁邊的ruby、rbc、rtc、rb、rt和rp元素,一般用來指示發音。
## Chapter 6\. 樣式表
樣式表可幫我們解釋XML文檔中各元素的具體意思,所以通過樣式表可直接在瀏覽器上顯示XML文檔。目前主要的樣式表語言有:
* CSS1(Cascading Stylesheets Level 1,層疊式樣式表1)
* CSS2(Cascading Stylesheets Level 2,層疊式樣式表2)
* XSLT(XSL Transformations 1.0 XSL 轉換 1.0)
在XML文檔在序言部分通過xml-stylesheet處理指令可指定關聯的樣式表。xml-stylesheet指令必須有一個href屬性和type屬性。href指向樣式表的URL,type指定樣式表的MIME類型:對CSS為text/css,對于XSLT為text/xml或application/xml。下面是一個簡單的使用樣式表的XML文檔:
```
< xml version="1.0" >
< xml-stylesheet href="test.css" type="text/css" >
...
```
除以上兩個必須的屬性外,還有4種可選屬性:
* media,標識該樣式應用于什么媒體,如報紙(paper)、計算機監視器(screen)、電視(tv)或所有(all)。
* charset,指明樣式表采用字符集編碼方式,如:utf-8。
* alternate,指明是否有可選的樣式表,默認為no,表明是主樣式表,如果為yes,則是備用樣式表。
* title,在有alternate的前提下,title用于指定不同樣式表的標題。如:
```
< xml-stylesheet href="big.css" type="text/css" alternate="yes" title="Large fonts" >
< xml-stylesheet href="small.css" type="text/css" alternate="yes" title="Small fonts" >
< xml-stylesheet href="medium.css type="text/css" title="Normal fonts" > #默認的主樣式表
```
樣式表現在已成為Web應用中的一個關鍵技術,它的作用主要體現在以下三個方面:
* 設計一個樣式表可以應用于多個文檔。樣式表可以存在于XML文檔外,XML文檔可通過鏈接使用樣式表。這意味著如果你有幾千個文檔,都可以鏈接到同一個樣式表中,改變一個樣式表等于改變幾千個文檔的顯示效果。
* 實現內容和表現的分離,增強文檔的一致性和可維護性。通過單一的樣式表,實現所有文檔顯示的一致。如果顯示樣式有變動,我們只需維護有限的幾個樣式表就可以了。
* 實現一個文檔,多個樣式。通過樣式表,可把一篇文檔以HTML形式、PDF形式或文本形式顯示出來。
## 6.1\. CSS2
CSS2是層疊樣式表,它是一種排版技術,能讓元素按特定的樣式顯示,如字體大小,顏色、布局等。在網頁中有三種使用方法:
* 用<style>標記聲明,如
```
<style>
div {font-size: 12pt;}
div {color: blue;}
</style>
```
* 在元素中用style屬性指定,如:
```
<div style="font-size: 12pt;color: blue">CSS測試</div>
```
* 用LINK標記鏈接一個外部CSS文件,如:
```
<link rel="stylesheet" type="text/css" href="mycss.css">
```
按作用域來分,有三類的樣式表,分別是網頁解釋器樣式表、作者樣式表和瀏覽者樣式表。網頁解釋器樣式表也叫默認的樣式表,當沒有另外的樣式表加載時使用。作者樣式表就是網頁設計師設計的樣式表。瀏覽者樣式表是瀏覽網頁的用戶在瀏覽器上另外設置的樣式表。
CSS的基本數據類型
* integer,表示整數,可取正負值。如:12,-24。
* number,表示數字,可取正負值和小數。如:12.1,-14.3。
* lenght,表示距離長度,可取正負值和小數,后跟一個單位,如:12em,12cm。單位又分相對單位和絕對單位,相對單位有:em,ex,px。絕對單位有:in(英寸),cm(公分),mm(公厘),pt(等于1/72英寸),pc(等于12pt)。
* percentage,表示百分比值,可取正負和小數。如:20%,-40%。
* uri,表示網絡資源。如: http://www.ringkee.com 。
inherit參數值
```
<style>
body {width: 600px;}
.div1 {width: 120%;}
.div2 {width: inherit;}
說明:
div1的寬度是600px*120%
div2的寬度繼承父元素body的參數,是600px
```
選擇符的作用是指定哪些元素使用哪些樣式。選擇符可以分為簡單選擇符和復合選擇符兩類,簡單選擇符是類型選擇符、通用選擇符加上零個或多個屬性選擇符、ID選擇符、偽類等組成。復合選擇符是用">"和"+"號結合多個簡單選擇符組成。">"和"+"號兩邊要加上空格。下面介紹各種選擇符:
* 通用選擇符,用"*"號表示,可用于所有標記。如:
```
<style>
* {font-size: 14pt;}
*.EM {color: red;}
</style>
<div>應用字體樣式</div>
<em class="EM">應用紅色樣式</em>
```
* 類型選擇符,與標記名一樣,只作用已該標記上。如:
```
<style>
div {font-size: 14pt;}
</style>
<div>應用樣式</div>
```
* 子代選擇符,HTML標記是可嵌套的,子代選擇符可把樣式表應用于子嵌套的子標記上,如:
```
<style>
div p b {font-size: 14pt;}
</style>
<div>
<p>沒有應用樣式</p>
<p><b>應用樣式</b></p>
</div>
```
* 子選擇符,與子代選擇符類似,但它只調用第一層子元素。如:
```
<style>
div > b {color: red;}
div p > em {color: green;}
</style>
<div><b>當b標記是div標記的子標記時應用紅色樣式</b></div>
<div><p><em>當em是p的子標記且p是div的子標記時應用綠色樣式</em></p></div>
```
* 鄰近選擇符,當兩個元素位于同一層且在位置是前后關系時,可以使用鄰近選擇符。兩個選擇符用"+"號分開,如果A位于B之前,則B可應用樣式。如:
```
<style>
div + p {color: red;}
</style>
<div>沒有應用樣式</div>
<p>應用紅色樣式。</p>
```
* 屬性選擇符,HTML標記有屬性,我們可為特定的屬性指定樣式。有四種寫法,分別是:
* [屬性],樣式只應用于指定的屬性。
* [屬性=值],樣式只應用于指定的屬性與值都相同的情況
* [屬性~=值],樣式只應用于指定的屬性且屬性值包含指定值的情況,屬性值是用空格分隔的字符串。
* [屬性|=值],樣式只應用于指定的屬性且屬性值是的第一個字符串是指定值的情況,屬性值是用"-"分隔的字符串。
```
<style>
[href] {color: red;}
A[href="http://www.ringkee.com"] {color: green;}
table[summary~="table"] {color: black;}
table[summary|="this-is-a-table"] {color: blue;}
</style>
<a href="http://www.python.org">應用紅色樣式</a>
<a href="http://www.ringkee.com">應用綠色樣式</a>
<table summary~="This is a table>
<tr>
<td>應用黑色樣式</td>
</tr>
</table>
<table summary|="This-is-a-table>
<tr>
<td>應用藍色樣式</td>
</tr>
</table>
```
* 類選擇符,與屬性選擇符類似,但它只指對class屬性應用樣式。類選擇符用"."語法,如.value與[class~=value]是一樣的。
```
<style>
.myid {color: red;}
</style>
<div class="myid">應用紅色樣式</div>
```
* ID選擇符,與屬性選擇符類似,但它只指對ID屬性,用"#"語法。
```
<style>
#myid {color: red;}
</style>
<div id="myid">應用紅色樣式</div>
```
* :first-child偽類,當標記是另一個標記的第一個子標記時,應用樣式。
```
<style>
p:first-child {color: red;}
</style>
<p>p是body的第一個子標記,應用紅色樣式</p>
<div>測試</div>
<p>p標記是body的第三個子標記,不應用紅色樣式</p>
```
* :link和:visited偽類只作用于a標記,在指定href屬性的前提下,:link表示a標記還沒被點擊時的樣式,:visited表示被當點后的樣式。
```
<style>
a:link {color: blue;}
a:visited {color: red;}
</style>
<a href="http://www.ringkee.com">鏈接沒點擊前是藍色的,點擊后是紅色的</a>
```
* :hover,:active和:fouce偽類也只能作用于a標記,且也要指定href屬性。:hover指定當用戶把鼠標移到a標記上并且指針變成手型時應用的樣式。:active指定點擊a鏈接并放開鼠標時所顯示的樣式。:fouce指定用戶點擊a標記瞬間,即鏈接成為焦點時所顯示的樣式。:hover要放在:link和:visited之后,否則:hover的樣式會覆蓋:link和:visited的樣式。
```
<style>
a:link {color: blue;}
a:visited {color: red;}
a:haover {color: green;}
a:focus {color: black;}
a:active {color: white;}
</style>
<a href="http://www.ringkee.com">應用樣式</a>
```
* :left及:right偽類只作用于頁面內容。當頁面在左邊時應用:left指定的樣式,當頁面在右邊時應用:right指定的樣式。
* :first-line只對div和p標記不效,樣式只應用于這兩個標記內的第一行內容。
```
<style>
:first-line {color: red;}
</style>
<div width:50px;>
該元素內的第一行內容應用紅色樣式。
</div>
```
* :first-letter偽類也只能作用于div和p標記,與:first-line不同的是它只作用于標記內的第一個字符。如果我們想要每一行的開頭字符大一點就可使用該偽類。
```
<style>
:first-letter {font-size: 40pt;}
</style>
<p>這行文字開頭第一個字符的大小是40pt</p>
```
* :before和:after偽類可在內容的前面或后面增加特定的內容或指定樣式。
```
<style>
p:before {content: "("; color: red;}
p:after {content: ")"; color: green;}
</style>
<p>這行文字前后會增加一對括號,前括號為紅色</p>
<p>這行文字前后會增加一對括號,后括號為綠色</p>
```
* 層疊選擇符是指當有多個選擇符的樣式都應用于同一個標記時的選擇規則。該規則利用一個三位數來確定,數字最大的就可選中。這三位數的確定規則的這樣的,如果選擇符中有ID選擇符,則百位數加1,否則為0。如果有屬性選擇符、類選擇符或偽類選擇符,則十位數加1,否則為0。如果有類型選擇符,則個位數加1,否則為0。如果選擇符是#div div,這三位數則是101。讓我們分析一下,#div是ID選擇符,所以在百位數上加1,div是類型選擇符,所以個位數上加1變成101。"*"表示0,優先級最低。
樣式表的主要功能是指定同一個文件在不同媒體上按不同的樣式顯示。通過在種方式可指定不同媒體
* @media方式
```
<style>
@media screen {div{color:red;}}
@media print {div{color:green;}}
</style>
<div>不同媒體顯示不同顏色</div>
```
* @import是另一種指定不同媒體的方式,它可引入外部的css文檔。它的語法格式是:
```
<style>
@import url("simple.css") screen;
</style>
```
* 在HTML4.0中,可以用LINK標記的media屬性為不同媒體類型指定樣式表。
```
<LINK rel="stylesheet" href="import.css" type="text/css" media="print">
```
!important規則會改變應用樣式的優先級,有!important參數樣式的優先級最高,會優先顯示。
```
<style>
h1 {color:red;}
h1 {color:green !important;}
</style>
<h1>字體為綠色</h1>
```
## 6.2\. XSLT
XSLT是XSL的一部份,它是XML的一種應用,指定將一篇XML文檔轉換成另一種XML文檔的規則。XSLT文檔即是一篇XML文檔,也是一個樣式表,里面包含一系列的模板。XSLT處理器對輸入XML文檔中的元素和樣式表中的模板進行比較,如果匹配,則將該模板的內容寫入一個輸出樹中。完成處理后,將輸出樹串行化成一篇XML文檔或其它格式的文檔,如HTML或者rtf。
XSLT幾個關鍵術語
* 源樹,原始文檔中的元素和元素內容的樹。
* 結果樹,轉換之后中文檔中的元素和元素內容的樹。
* 模板規則,XSLT樣式表的基礎,分為模式和模板兩部份。整個xsl:template元素。
* 模式,表示源樹中的元素與模式規則匹配的條件集合。xsl:template中的match的值。
* 模板,表示當應用模板規則時,結果樹中要實例化的部份。xsl:template元素中的內容。
XSLT定義了35個元素,分為三類:
兩個根元素
* xsl:stylesheet根元素,XSLT也是一個XML文檔,該文檔的根元素就是xsl:stylesheet。XSLT元素都屬于名稱空間`xmlns:xsl="http://www.w3.org/1999/XSL/Transform"`,所以所有的XSLT元素都有xsl前綴。一個最小化XSLT文檔:
```
< xml version="1.0" >
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
</xsl:stylesheet>
```
* xsl:transform元素,作用同上。
13個頂級元素,可直接作為根元素的子元素,包括:
* xsl:apply-imports
* xsl:attribute-set
* xsl:decimal-format
* xsl:import
* xsl:include
* xsl:key
* xsl:namespace-alias
* xsl:output
* xsl:param
* xsl:preserve-space
* xsl:strip-space
* xsl:template模板元素,用于匹配XML文檔中的元素。如:<xsl:template match="person">,匹配XML文檔中的person元素。
* xsl:variable
20個指令元素
* xsl:apply-imports
* xsl:apply-template應用模板元素,用于顯示指定的元素值(內容)。如:<xsl:apply-template select="name">,顯示name元素的值。
* xsl:attribute
* xsl:call-template
* xsl:choose
* xsl:comment
* xsl:copy
* xsl:copy-of
* xsl:element
* xsl:fallback
* xsl:for-each
* xsl:if
* xsl:message
* xsl:number
* xsl:otherwise
* xsl:processing-instruction
* xsl:text
* xsl:value-of選擇元素,用于計算元素的值(內容)。如:<xsl:value-of select="name">,獲得XML文檔中name元素的值(內容)。
* xsl:variable
* xsl:when
XSLT函數
## 6.3\. XPath
XPath是一種用來從文檔樹中選擇節點和節點集的語言。從XPath的角度來看,共有七種節點:
* 根節點
* 元素節點
* 屬性節點
* 文本節點
* 注釋節點
* 處理指令節點
* 名稱空間節點
CDATA部份,實體引用和文檔類型聲明不包括在內,XPath在所有這些項都并入文檔之后才起作用。根節點和根元素是不同的兩個概念,根節點包含整篇文檔,包括根元素。
### 6.3.1\. 匹配模式
匹配模板的通用模式
**Table 6.1\.**
| 模式 | 描述 |
| --- | --- |
| match="E" | 匹配元素E |
| match="*" | 匹配任意元素 |
| match="E|F" | 匹配元素E和F |
| match="E/F" | 匹配以E為父元素的元素F |
| match="E//F" | 匹配以E為根元素的元素F |
| match="/" | 匹配根節點 |
| match="text()" | 匹配文本節點 |
| match="comment()" | 匹配注釋節點 |
| match="processing-instruction()" | 匹配處理指令 |
| match="node()" | 匹配除屬性節點和根節點外的節點 |
| match="id(test)" | 匹配具有唯一ID test的元素 |
| match="E[@CLASS="foo"] | 匹配元素E,其類屬性為foo |
| match="E[F]" | 匹配元素包含有F元素的E元素 |
### 6.3.2\. XPath軸
XPath提供了選擇節點的機制,兩個較有用的是軸選擇和謂語選擇,軸指定上下文節點和要選擇的節點的關系。共有十三種軸,最常用的有四種,分別是子軸(child)、屬性軸(attribute)、自已(self)、雙親(parent)。
**Table 6.2\. XPath軸描述**
| 軸 | 描述 |
| --- | --- |
| child | 包含當前節點的兒子 |
| descendent | 包含當前節點的后代,后代不包含屬性(attribute)或名稱域(namespace)節點 |
| parent | 包含當前節點的父親 |
| ancestor | 包含當前節點的祖先,祖先總是包含根節點 |
| following-sibling | 包含當前節點隨后的所有節點樹,但不包含attribute或namespace節點 |
| preceding-sibling | 包含當前節點之前的所有節點樹,但不包含attribute或namespace節點 |
| following | 包含當前節點隨后的所有節點,following軸排除了當前節點的后代和attribute或namespace節點 |
| preceding | 包含當前節點之前的所有節點,following軸排除了當前節點的后代和attribute或namespace節點 |
| attribute | 包含當前節點的所有屬性 |
| namespace | 包含當前節點的所有namespace節點 |
| self | 只包含當前節點 |
| descendent-or-self | 包含當前節點和當前節點的后代 |
| ancestor-or-self | 包含當前節點和當前節點的祖先 |
### 6.3.3\. 謂詞
XPath表達式可以匹配多個節點,如需對匹配的節點進行進一步的篩選,可以使用謂詞。
**Table 6.3\. 選擇節點常用謂詞**
| 謂詞 | 描述 |
| --- | --- |
| select="E" | 選擇是當前節點的孩子的E元素 |
| select="" | 選擇當前節點的孩子的所有元素 |
| select="text()" | 選擇當前節點的文本節點孩子 |
| select="@name" | 選擇當前節點的name屬性 |
| select="@*" | 選擇當前節點的所有屬性 |
| select="E[1]" | 選擇當前節點的孩子的第一個E元素 |
| select="E[last()]" | 選擇當前節點的孩子的最后一個E元素 |
| select="*/E" | 選擇當前節點的孫了的所有E元素 |
| select="E//F" | 選擇從當前節點的孩子的E元素派生而來的元素F |
| select="//" | 選擇根元素 |
| select="//E" | 選擇從根節點派生而來的E元素 |
| select="//E/F" | 選擇所有是從根節點派生而來的E元素的孩子的F元素 |
| select="." | 選擇當前節點 |
| select=".//E" | 選擇從當前節點派生而來的所有E元素 |
| select=".." | 選擇當前節點的父節點 |
| select="../@name" | 選擇當前節點的父節點的name屬性 |
| select="E[@name='foo']" | 選擇所有是當前節點的孩子,并且其name屬性具有foo值的E屬性,除等號外,還可用<,>,<=,>=和!= |
| select="E[@foo and @bar]" | 選擇所有包含foo和bar屬性的E元素 |
home/person/@id這種定位路徑的寫法叫簡寫定位路徑,該寫法簡潔,容易理解,是XSLT匹配模式中最常用的寫法。還有一種稱為非簡寫定位路徑的寫法,它把節點測試和軸結合在一起,如child::home/child::person/attribute::id。該寫法在實際使用中不常用,但它具有非常重要的性能因此有必要了解。
### 6.3.4\. XPath表達式
位置路徑是XPath的一個最常用的表達式,用以標識XML文檔的節點集。除此之上,XPath表達式還可返回數字、布爾和字符串。非節點集的XPath表達式不能用于xsl:template元素的match屬性中。它們用于xsl:value-of元素的select屬性值或用于位置路徑的謂詞中。
每個XPath位置路徑可分為一步名多步,每步以“/”號分隔,如:
```
room[\@name=$root]/date[year=$year and month=$month]/meeting
```
上下文節點即當前正在處理的節點,也就是位置路徑定位的當前節點。上下文在XPath表達式計算前被創建,由XSLT處理器創建。處理每一步后,上下文都會改變。
位置路徑中的步可分為三部份:軸(axis)、節點測試(note test)和謂詞(predicate),它的寫法如下:
```
axis::note-test[predicate]
```
軸和節點測試之間用“::”分開,每個謂詞由括號[]括起來。
要設計好一個位置路徑,需確保在每一步選擇最少的節點,使用最嚴格的軸,用最嚴格的節點測試。避免使用謂詞,因為由軸和節點測試選擇的節點集的每個節點都會用作謂詞的上下文節點。對于位置路徑的三步,最節省的是節點測試。
XPath中的所有數字都是8個字節的IEEE754浮點雙精度類型,與java的double類型相同。可表示正無窮大、負無窮大和NaN(零除零)值。支持五種運算符,分別是加(+)、減(-)、乘(*)、除(div)、取余(mod)。
XPath中的字符串是Unicode字符,用單引號或雙引號定界。可以使用=和!=對字符進行比較,也可用<,>,<=,>關系運算符,但比較的兩個字符必須是數字,否則比較結果沒有意義。
XPath中的布爾值常用于位置路徑的謂詞中,如/person[name="debian"]。布爾值還常用于xsl:if和xsl:when元素的test屬性中。如:
```
<xsl:template match="home">
<xsl:if test = ".='debian' or .='redhat'">
<xsl:value-of select = "." />
</xsl:if>
</xsl:template>
```
### 6.3.5\. XPath函數
XPath還提供很多函數,用于表達式和謂詞。XPath函數的返回值有四種類型,分別是:
* 布爾值,如:true()返回ture(真),false()返回false(假),not()對布爾值取反。
* 數字,如:number()把任意類型轉化數字,celing()返回大于或等于參數的最小整數。
* 節點集,如:position()返回當有節點在上下節點列表中的位置,count()可統計節點數。
* 字符串,如:string()轉化任意類型為字符串,string-length()返回字符串長度。
## 6.4\. XLink
XLink是一種基于屬性的語法,用來在XML文檔中添加鏈接。XLink鏈接可以是單向的,如HTML中的A元素,它也可以是雙向的,在兩個方向上鏈接兩篇文檔,因此能夠從A到B或從B到A。每個XLink元素必須具有一個xlink:type屬性,指出連接類型。屬性xlink:href指向所鏈接的資源URI。下面是一個簡單鏈接的示例:
```
<test xmlns:xlink = "http://www.w3.org/1999/xlink"
xlink:type = "simple"
xlink:href = "http://www.ringkee.com/xml.html">
<author>Jims</author>
<date>2005/02/18</date>
</test>
```
xlink:type屬性類型共有六種,分別是:simple,extended,locator,arc,title,resource。
xlink:show屬性可告訴瀏覽器或應用程序在激活鏈接時應該做什么,它有五種可能的動作,分別是:
* new,在新窗口中顯示鏈接內容。
* replace,在當前窗口顯示鏈接內容。
* embed,在當前鏈接元素的位置嵌入內容。
* other,動作不確定,由應用程序指定。
* none,無動作。
xlink:actuate屬性可告訴瀏覽器何時顯示鏈接,它有四種可能值:
* onLoad,一旦發現鏈接,馬上顯示。
* onRequest,當用戶提出請求時才顯示。
* other,由文檔中的其它標記,而不是xlink,來決定何時顯示。
* none,不指定。
一個和HTML中的A元素作用一樣的示例:
```
<test xmlns:xlink = "http://www.w3.org/1999/xlink"
xlink:type = "simple"
xlink:href = "http://www.ringkee.com/xml.html"
xlink:actuate = "onRequest"
xlink:show = "replace" >
<author>Jims</author>
<date>2005/02/18</date>
</test>
```
一個在頁面嵌入圖像的示例:
```
<image xlink:type = "simple"
xlink:actuate = "onLoad"
xlink:show = "embed"
xlink:href="http://www.ringkee.com/flower.png"
width = "320" height = "240" />
```
xlink:actuate和xlink:show是可選的。
xlink:title和xlink:role屬性可指定資源之間的描述,xlink:title包含少量描述遠程資源的文本,xlink:role包含URI,指向資源的較長描述。
## Chapter 7\. 分析XML
分析XML文檔可通過程序來做,分析器有兩大類,一種是事件驅動的,一種是基于樹模型的。
* 使用事件驅動的分析器時,每遇到一個元素就會觸發一個事件,由事件處理器進行處理。事件分析器按順序讀取XML文檔,而不把整個文檔讀入內存,所以處理速度很快。但缺點是由于要從頭到尾讀取XML文檔,因此無法在XML文檔中移動位置。事件驅動分析器適合處理其它地方使用的XML數據,如轉換成HTML文檔或從文件中讀取數據并插入數據庫中。它的優點有:
* 文件搜索,從XML文檔中搜索需要的標志或數據;
* 格式轉換,如轉換成HTML。任何需將原始XML轉換成另一種格式的工作都最好使用事件驅動分析器來完成,因為它可動態將信息轉換成新格式。
* 少量修改,你可用事件驅動分析器讀取和重新生成XML。在分析過程中,可以改變少量的單語、字符數據內容或重新構造XML。事件驅動分析器特別適合整理和重新格式化XML文檔。
* 簡單驗證,由于整個文檔不在內存中,所以無法進行完整驗證,但可檢查拼寫錯誤和一般良構XML文檔之類的簡單問題;
* 建立內部結構,可以使用事件驅動分析器建立XML文檔的復雜內部表示,如基于樹的接口使用的樹式結構。
> 事件驅動分析器不能在XML文檔間交叉引用文檔內容,但它使用簡單,速度快。
* 基于樹的分析器把整個XML文檔讀入內存,并生成樹狀結構。分析器可隨機訪問樹中的任意節點,并能修改樹結構和內容。
## 7.1\. 分析器工具
現有的分析器種類有上百種,但常用的是兩個標準的工具庫,一個是XML簡單API(SAX,Simple API for XML)和文檔對象模型(DOC,Document Object Model)。SAX是事件驅動分析器的標準,而DOM是基于樹的分析器標準。另外,Expat雖然不是標準,但它是腳本語言中處理XML時最常用的分析器。Expat由James Clark編寫,是事件驅動分析器。
## 7.2\. Unicode
計算機并不能正真理解文本內容,它無法識別諸如a,b,c這類的字母,更不用說中文了。計算機所能理解的只有數字,如60,80等。字符集(character set)規定了字母到數字的映射關系,如65代表大寫字母A。65稱為碼點(code point),字符編碼(character encoding)決定碼點如何用字節表示。是用多了節還是單字節,高字節位表示什么,低字節位表示什么。
不同國家使用不同的語言,不同程序使用不同的編碼規范,在進行世界范圍內的數據交換就要統一表示數據的字符編碼規范。傳統的ASCII字符集只定義了127個字符,其中前31個是控制符。127位之后的字符隨平臺不同而不同。大多數平臺只能表示前127位,單字節(8位),使得字符集中最多只能提供256個字符。這些標準字符稱為羅馬或拉丁字符集,用ASCII來表示中文、日文是遠遠不夠的。
為了解決字符集問題,出現了Unicode字符集。它可用多字節格式編碼字符,目前標準允許2字節字符,支持65536個不同字符。標準的Unicode字符集為Latin-1(或ISO-8859-1)。有關Unicode的介紹可訪問Unicode的官方網站:<http://www.unicode.org>。
Unicode字符集為字符分配碼點,即編號。這些編號可以用多種模式編碼,如UCS-2、UCS-4、UTF-8、UTF-16。
* UCS-2,也叫ISO-10646-UCS-2。每個字符用一個0~65535之間的兩個字節的無符號整數表示。如A的Unicode碼點為65,用兩個字節00和41(十六進制)表示。B的Unicode碼點為66,用兩個字節00和42表示。UCS-2有兩種形式:高字節(#x0041)在前和低字節(#x4100)在前。為區發高低位不同表示形式,采用UCS-2編碼文檔通常以Unicode字符#xFEFF(零寬度無間斷空格)開頭,一般稱為字節順序標記(byte order mark)。這個字符是不可見的。如果兩個字節交換位置,得到的字符#xFFFE實際是不存在的。因此中通過查看UCS-2文檔的前兩個字符是#xFEFF還是#xFFFE,就可確定該文檔是否是高字節在前。UCS-2的缺點:如果文本字符主要是拉丁文,由于采用兩個字節,字符集編碼是單字節字符編碼的兩倍;UCS-2不能與ASCII向前或向后兼容,用于單字節字符集的工具常常不適用于處理UCS-2編碼文件。
* UTF-8是一種可這長度的Unicode編碼。0~127為ASCII碼字符集,與ASCII編碼完全兼容,每個字符采用一個字節編碼。UTF-8用兩個字節表示128~2047,該范圍覆蓋了最常見的非表意字母。其余的字符,主要來自漢語、日語和韓語,每個都用3個字節表示。如果Unicode的碼點超過65535個字符,那么這些字符就會用4個字節編碼。對于以拉丁文為主的文件,使用UTF-8比UCS-2可減少一半的文件大小。對于漢語、日語和韓語的文件,其大小會增加百分之五十。對于其它語言,文件大小相差不大。UTF-8是最常用的Unicode編碼方式。
在Unicode流行以前,出現了一系列處理特定語言的單字節字符集,ISO將14種這樣的字符集標準化成ISO 8859標準,分別是ISO-8859-1~14。ISO-8859-15是ISO-8859-1的修訂版本。這些字符集統稱ISO字符集。
Cp1252是依賴于Windows平臺的一種編碼,是Windows的缺省字符集。該種編碼不支持跨平臺特性,盡量不要使用。
MacRoman是Mac OS使用的一種非標準、單字節編碼。在非Mac平臺下使用也會有問題,盡量不要使用。
在XML文檔中,如果需輸入編輯器不支持的字符,我們可用字符引用的方式,以十進制或十六進制給出它所代表的Unicode字符編號,如њ(十進制)或者њ(十六進制)。字符引用可用于元素內容、屬性和注釋,不能用于元素名和屬性名、處理指令或XML關鍵字。如果有一些字符需經常使用,則我們可為這些字符定義實體,這樣,在文檔中就可方便地引用該實體了。專門定義字符實體的DTD我們可獨立出來,形成以.ent為后綴的外部DTD。在需要時使用外部參數實體引用將這些定義引入文檔的DTD中。
XHTML 1.0 DTD包含有三個有用的字符引用實體可在文檔中使用。
* Latin-1字符,http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent
ISO-8859-1中自160以上的非ASCII碼字符。
* 特殊字符,http://www.w3.org/TR/xhtml/DTD/xhtml-special.ent
ISO-8859-2中不在Latin-1中的字母。
* 標點符號,http://www.w3.org/TR/xhtml-symbol.ent
希臘字母表(不包含帶重音的字符)和各種標點符號、數學運算符及其他數學中常用的符號。
在XML文檔中可以使用xml:lang屬性規定元素內容采用的語言。這樣就可在一篇文檔中同時使用多種語言,這是XML跨平臺和跨語言的重要特性之一。如:xml:lang="CN-CHN"。語言代碼是一個兩個字母的語言代碼,語言代碼后還可跟一個子代碼,語言代碼可在這里找到[http://ftp.ics.uci.edu/pub/ietf/http/related/iso3166.txt](http://ftp.ics.uci.edu/pub/ietf/http/related/iso3166.txt)。下面是xml:lang屬性聲明的示例:
```
<!ELEMENT test (#PCDATA)>
<!ATTLIST test xml:lang NMTOKEN #IMPLIED>
```
由于所有語言代碼都是有效的XML名稱標記,所以使用NMTOKEN類型。
## Appendix A. 附錄
## A.1\. 標記語言的歷史
* 1974年,IBM的Charles F.Goldfarb、Ed Mosher和Ray Lorie發明了一種最終發展成為標準的通用標記語言(SGML,Standardized General Markup Language)。1986年,SGML被ISO采用為8879號標準。
* 1991年,Tim Berners-Lee利用SGML提供的基本機制定義了超文本標記語言(HTML,Hypertext Markup Language),把Internet帶進了一個多姿多彩的世界。HTML是SGML最成功的一種應用。
* 1998年2月10日,W3C的XML 1.0標準正式發布,為異構平臺的數據交換提供了一個可行的標準。
## A.2\. XML相關技術名詞解釋
* XLink,一種基于屬性的用于XML和非XML文檔之間超鏈接的語法,可以提供與HTML相似的簡單、單向的鏈接,多文檔之間的多向鏈接,以及沒有寫入權限的文檔間的鏈接。
* XSLT(XSL Transformation,XSL轉換),一種XML文檔,用于描述具有相同或不同XML詞匯表的兩個文檔之間的轉換。
* XSL-FO(XSL Formatting Object,XSL格式化對象),一種用于描述打印和網頁布局的XML應用。
* Dsssl(Document Style Sheet and Semantics Language,文檔樣式表和語義語言),用于描述XML打印和在Web上的樣式,源自SGML。
* XPointer,標識XML文檔中由URI指定的特殊部分,通常與XLink結合使用。
* XPath,用于標識XML文檔中的路徑。
* Namespace,區分來自不同的XML語匯表但名稱相同的元素和屬性的一種方式。
* SAX,Simple API for XML,一種事件驅動的XML文檔處理器。
* DOM,Document Object Model,一種面向樹的API,它把XML文檔解釋成具有多屬性和嵌套的對象樹。
## A.3\. XML應用
XML可自定義標簽,為了增強互操作,個人或組織可約定只使用某種標簽。這些標簽集被稱為XML應用。XML應用不是使用XML的軟件應用程序,如IE或Word,而是XML在矢量圖形或數學公式這些特殊領域的一種應用。
* SVG,可縮放矢量圖形(Scalable Vector Graphic),是W3C推薦的XML中矢量圖的編碼標準。
* MathML,數學標記語言(Mathematical Markup Language),用于表示數據公式。
* CML,化學標記語言(Chemical Markup Language),描述化學、物理學、分子生物學和其它分子科學。
* RDF,資源描述框架(Resource Description Framework),用于描述資源,特別是圖書館分類卡上的元數據。
* CDF,通道定義格式(Channel Definition Format),微軟公司定義的一種非標準XML應用,用來向IE發布可離線瀏覽的網頁。