XML/單一實體
學習目標
編輯完成本章內容的學習,對於一個實體您將能夠
- 創建一個XML數據schema
- 創建一個XML文檔
- 創建一個XML樣式表
- 編寫一段java程序來解析一個XML文檔並列出其中的內容
概述
編輯- 許多計算機系統中都會包含有格式不一數據。在這樣的系統之間進行數據格式的轉換將會耗費大量的時間。XML是一種通用的數據存儲格
式,而與之相配套的大量工具和技術能夠使得不兼容的系統之間特定XML應用的交換變得十分簡捷。由於XML的開放性和通用性,可以預見 的是隨著時間的發展,越來越多的組織和個人包括程式設計師和數據用戶都將會選擇XML。這將使得XML最終成為對於特定數據交換的最可行的 技術。
- XML不僅僅是被用來進行信息的交換,其也能用於網頁的發布。XML的語法非常嚴謹,從而使得網頁瀏覽器變得體積更小、速度更快成為可
能,同時其也能很好地應用於個人數字助理(DA)和手機上。而在另一方面,為讀取HTML格式網頁而設計的瀏覽器,往往必須設計大量的 代碼來解決由於HTML缺乏對於數據格式的嚴格定義而造成的不便。
- 適用於以XML方式進行編碼的數據類型應該具有以下特點:域長度是未知的和不可預見的,這裡域的內容大多數為純文本。
- XML schema 允許以標準化結構進行信息交換。 Schema定義了一些自定義的標記,這些標記包含有許多用以描述標記所標識內容的屬
性。這樣,XML文檔中被標記的數據中所包含的信息便可以通過一種名叫「解析器」的應用程式進行提取,更進一步,利用XML樣式表便可以轉 換為Web網頁格式。
- 創建schema的第一步便是定義描述數據交換中所涉及事實的數據模型。當具有高置信度的模型一旦被創建,數據模型便可以轉換成為
schema。在本章內容中,我們將從一個簡單的例子開始,在其後的章節中將會陸續介紹XML其他更加複雜的屬性。
- 如下圖所示,我們將會從一個單一的實體CITY開始。由於本章討論的是將單一的實體CITY映射到XML schema的問題,我們需要定義一個
包含CITY的實體TOURGUIDE。我們可以將TOURGUIDE想像成為一個包含有許多城市的實體,並且TOURGUIDE將不包含任何屬性或是標 簽。TOURGUIDE將僅僅是一個城市相關數據的集合。
XML schema
編輯XML schema 描述了XML文檔的結構和內容,其定義了:
- 出現在一個文檔中的所有元素的名稱和內容;
- 文檔的結構;
- 所有的子元素;
- 子元素的數目;
- 元素出現的頻率;
- 元素出現的順序;
- 元素的數據類型.
- XML schema的一個突出的優點是它定義了數據類型,使得對於符合該Schema的文檔的內容描述和數據正確性的校驗變得更加容易。這樣
一來,文檔中可能包含的錯誤就能夠在進行數據交換之前被檢測出。
- XML schema語言被稱為XML schema 定義(XSD)。因為XML schema也是用XML編寫的,所以它是可擴展的,而且XML文檔的編輯器
可同樣用於XML schema的編輯。
- 通用XML schema數據類型
XML schema有許多預定義的數據類型。最為通用的有:
- 字符串型——元素中包含有一串字符
- 十進制型——元素中包含有十進制小數
- 整型——元素中包含有整數
- 布爾型——元素中包含有真/假或1/0
- 日期型——元素中包含有日期
- 時間型——元素中包含有時間
- uri引用型——元素中包含有URL(統一資源定位符)
- 完整的預定義資料結構列表請參http://www.w3.org/TR/xmlschema-2/#built-in-datatypes
- schema元素的定義有兩種類型:簡單或複雜。一個「簡單類型」將只包含「文本」而不會有其他元素或屬性。在這裡,「文本」是一個概括的表示,其含義是預定義的數據類型或來源於用戶自定義的類型定義。一個「複雜類型」包含有其他的元素或屬性。無論簡單還是複雜的類型都可以進行命名,以便能夠在schema的其他部分進行重用;如果不對該類型命名,則該類型只有在給出定義的元素下才能被使用。
<xsd:element name="city" type="cityDetails">
<xsd:complexType name="cityDetails">
<xsd:sequence>
<xsd:element name="cityName" type="xsd:string"/>
<xsd:element name="adminUnit" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
圖2-1 命名的複雜類型
<xsd:element name="tourGuide">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="city" type="cityDetails"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
圖2-2 未命名的複雜類型
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified">
<!-- Tour Guide -->
<xsd:element name="tourGuide">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="city" type="cityDetails" minOccurs = "1" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<!-- City -->
<xsd:complexType name="cityDetails">
<xsd:sequence>
<xsd:element name="cityName" type="xsd:string"/>
<xsd:element name="adminUnit" type="xsd:string"/>
<xsd:element name="country" type="xsd:string"/>
<xsd:element name="population" type="xsd:integer"/>
<xsd:element name="area" type="xsd:integer"/>
<xsd:element name="elevation" type="xsd:integer"/>
<xsd:element name="longitude" type="xsd:decimal"/>
<xsd:element name="latitude" type="xsd:decimal"/>
<xsd:element name="description" type="xsd:string"/>
<xsd:element name="history" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
表2-1 City實體的XML schema – city.xsd
讓我們檢查一下上面的XML schema
- 所有的XML文檔都以XML聲明開始{1}。
- XSD schema 命名空間namespace 聲明 {2}. 命名空間將會在《數據schema》[[Data schemas
(XML) | Data schemas]] 章節中深入地討論。
- 注釋被包含在標籤「<!--「和「-->」 之間{3}.
- tourGuide元素被定義為一個複雜類型{4-10},也就是說其中包含嵌入的元素。
- 一個元素最少出現次數通過minOccurs(默認值為1)進行定義,最大出現次數沒有限制maxOccurs=「無窮大」{7}
- City被聲明為已命名的複雜類型{7}。
- <xsd:complexType 標誌了一個複雜類型聲明的開始{12},」cityDetails」 標識了這個複雜類型。但是這不是該
複雜類型的名稱。這種複雜類型定義可以用來對於多個元素進行聲明。
- Schema元素sequence {13} 定義了子元素出現的次序。
- <xsd:element 標誌了一個簡單類型聲明的開始{14}。」cityName」 是這個被聲明的元素的名稱(在XML文檔中通常
以<cityName>的形式出現)」xsd:string」 是這個元素的數據類型。
- 結束標誌{24-26}。注意:結束標誌不能相互交疊。
- 注意: 緯度和經度是十進制數據類型。從通常形式(例如50º 17' 35")到十進制形式的轉換可通過公式度+分/60+秒/3600。
- 對於任何XML文檔,包括XML schema和XML 樣式表文檔,都可以進行檢查以判定它們是否「結構良好」(良構)。正如第一
章所描述的,一個符合XML語法規則的XML文檔就是良構的文檔,即有且只有唯一的一個根元素,任何開始標籤必須有一個結 束標籤與之對應。我們可使用XML編輯軟體來進行結構良好性檢驗,例如NetBeans。
- 一旦檢查到錯誤,這些錯誤將會按順序顯示在結果窗口中。雙擊任何一個錯誤報告,便可以轉到XML文檔中該錯誤出現的位置。
可以使用NetBeans創建上述XML schema:
- 點擊File -> New -> XML -> XML Schema。
- 將文件保存為「city」(將自動添加後綴.xsd)。
- 複製並粘貼上述schema到文件city.xsd中並保存。
檢查XML文檔是否為良構的:
- 右鍵單擊文檔節點,選擇Check XML document 或按Alt+F9。
如果XML schema city.xsd是良構的,輸出窗口將如下所示:
小結:XML schema 顯示了XML文檔的元素和結構
XML文檔
編輯- XML文檔是包含有XML代碼和句法的文件。所有的XML文檔必須包含有唯一一對標識"根"元素的標籤。所有其他元素都必須包
含在這個根元素中。元素可以擁有子元素。相對應的,任意子元素都有一個「父」元素。所有的元素都必須正確地嵌套在它們的父元素中,也就是子元素的結束標籤一定要在父元素結束標籤前給出。這樣便形成了一個樹狀的結構。XML文檔以.xml為後 綴。
XML元素命名規定
- XML元素的名稱必須以字母或帶下劃線的字符開頭。而且也不能以字符串「xml」開頭,「xml」是XML定義保留的字符串。
名稱的其他部分可以是字母、數字或其他字符但中間不能存在空格。理論上講可以給元素定義任意名稱,但是為了增強元素名的描述性,名稱最好能夠反映該元素的所表示的內容。
- XML文檔通常會有一個相對應的資料庫,在該資料庫中欄位與XML文檔中的元素相對應。一個很好的方式是使用資料庫中的命
名規則來進行XML文檔元素的命名。
- 「:」儘量不要用在元素的名稱之中。因為其是被保留用來進行命名空間的定義(這一部分將會在下一章中詳細介紹)
<?xml version="1.0" encoding="UTF-8"?>
<tourGuide
xmlns:xsi='http://www.w3.org/1/XMLSchema-instance'
xsi:noNamespaceSchemaLocation='city.xsd'>
<city>
<cityName>Belmopan</cityName>
<adminUnit>Cayo</adminUnit>
<country>Belize</country>
<population>
/population>
<area>
5
</area>
<elevation></elevation>
<longitude>
/longitude>
<latitude>
/latitude>
<description>Belmopan is the capital of Belize</description>
<history>Belmopan was established following the devastation of the former capitol,
Belize City, by Hurricane Hattie in 5. High ground and open space influenced the
choice and ground-breaking began in 6. By 0 most government offices and
operations had already moved to the new location.</history>
</city>
<city>
<cityName>Kuala Lumpur</cityName>
<adminUnit>Selangor</adminUnit>
<country>Malaysia</country>
<population>0</population>
<area>
</area>
<elevation></elevation>
<longitude>
./longitude>
<latitude>
3./latitude>
<description>Kuala Lumpur is the capital of Malaysia and the largest city in the nation</description>
<history>The city was founded in 7 by Chinese tin miners and superseded Klang. In
0 the British government transferred their headquarters from Klang to Kuala Lumpur,
and in 6 it became the capital of Malaysia. </history>
</city>
</tourGuide>
表2-2 City 實體的XML文檔 – city.xml
表2-2中列出了用來描述擁有一個city實體的tourGuide的XML文檔。需要注意以下幾點:
- 每一個XML文檔的第一行都以XML聲明開始{1}。
- 隨後的的聲明標明了該文檔的根元素(tourGuide)以及schema文件(city.xsd),該聲明使用xsi=schemaLocation {2-4}。
- 對於第一個城市{5-19}和第二個城市{20-33}的定義。
- 根元素的結束標籤{34}。
- 由XML schema約束的XML文檔可以進行有效性驗證。一個「有效」的XML文檔是一個「結構良好」的XML文檔,也就是說其也遵循了XMLschema中的規則。但是,需要注意的是即使文檔是結構良好的,其仍有可能是無效的。例如,如下的XML文檔片斷:
<city> <cityName>Boston</cityName> <country>United States</country> <adminUnit>Massachusetts</adminUnit> ...... </city>
- 我們可以看到,元素並沒有按照Schema中規定的正確順序出現。依據其聲明的schema,該XML文檔可以(使用檢驗程序)進行有效性檢驗——檢驗程序將會發現上面提到的順序混亂的錯誤。
使用NetBeans創建上述的XML文檔:
- 點擊File -> New -> XML -> XML Document。
- 將文件保存為「city」。
- 選擇XML Schema-Constrained Document 作為文檔的類型。
- 定義schema位置以及跟元素的名稱(tourGuide)。
- 複製並粘貼上述代碼並保存。
- 進行良構性檢驗(ALT+F9)
進行有效性檢驗:
- 右鍵單擊文檔節點選擇Validate XML。
如果XML文件city.xml,遵循了XMLschema city.xsd的定義,則輸出窗口將顯示如下信息:
- 在NetBeans中打開文檔city.xml
小結:XML文檔是一個包含有XML代碼和句法的文件,是一個由元素及子元素良好組織而形成的實體。 |
XML 樣式表
編輯- 可擴展樣式表語言(XSL)為XML文檔的轉換以及以特定格式顯示內容提供了一種手段。由於XML文檔並沒有提供瀏覽器能夠理解的標籤,比如HTML標籤,沒有包含了表達信息的樣式表的輔助,瀏覽器便無法顯示出XML文檔中的數據。通過將數據與表示邏輯相分離,XSL允許用戶根據其不同的需要和偏好瀏覽同樣的數據。
- XSL轉換語言(XSLT)被用來進行XML文檔的轉換,例如將XML文檔轉換為用於瀏覽器瀏覽的HTML文件。XSLT樣式表包含有一組格式說明,這些格式說明規定了XML文檔內容在瀏覽器中的顯示方式,這一點與HTML的級聯樣式表(CSS)十分相似。使用不同的樣式表對於同樣的數據可以產生不同的視圖。而且樣式表不是僅僅用於瀏覽器顯示文檔內容,例如,樣式表也可以用於XML文件的轉換。
- 在文件轉換過程中,XSLT對XML文件進行分析,並將其轉化為一個節點樹,即XML文檔的一種層次化的表示。樹中的每一個節點代表了一個XML文檔片斷,例如一個元素、屬性或其他的文本內容。XSL樣式表包含有預定義的「模板」,這些模板定義了對於節點的操作。XSLT會通過匹配屬性將XML元素與模板聯繫起來,並且將其轉換成結果文檔。
1. <?xml version="1.0" encoding="UTF-8"?> 2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 3. <xsl:output method="html"/> 4. <xsl:template match="/"> 5. <HTML> 6. <HEAD> 7. <TITLE>Tour Guide</TITLE> 8. </HEAD> 9. <BODY> 10. <H2>Cities</H2> 11. <xsl:apply-templates select="tourGuide"/> 12. </BODY> 13. </HTML> 14. </xsl:template> 15. <xsl:template match="tourGuide"> 16. <xsl:for-each select="city"> 17. <xsl:text>City: </xsl:text> 18. <xsl:value-of select="cityName"/> 19. <BR/> 20. <xsl:text>Population: </xsl:text> 21. <xsl:value-of select="population"/> 22. <BR/> 23. <xsl:text>Country: </xsl:text> 24. <xsl:value-of select="country"/> 25. <BR/> 26. <BR/> 27. </xsl:for-each> 28. </xsl:template> 29. </xsl:stylesheet> |
表2-3 City實體的XML樣式表 – city.xsl
讓我們分析一下上面的樣式表:
- 由於XSLT使用XML語言編寫的,它們總是以標準的XML聲明加上XML句法規格開頭。
- 標籤<xsl:stylesheet> 標明了樣式表定義的開始,並且聲明了版本號以及W3C的正式命名空間{2,3}。
- 元素<xsl:template>定義了一個模板定義的開始,並且包含了對於匹配節點的操作規則的定義。匹配規則被用來將XML元素與樣式表進
行匹配。在上面的樣式表中即為XML原文檔的根(/)或整個分支{4}。XSL查找匹配的根然後輸出HTML文件。
- 模板元素內容包含在HTML數據輸出流中,這樣瀏覽器便可以進行相應的解釋{5-18}。
- XSL<xsl:for-each>元素被用來對於一個特定節點集(此例中為元素city)中的所有節點進行遍歷,並將其加入到輸出文件中{28}。
- <xsl:value-of>元素從被選節點/XML元素(cityName)中提取屬性值,並將其加入到輸出數據流中。{18,21,24}
city.xsl樣式表的輸出結果如表2-3所示:
Cities
City: Belmopan
Population: 11100
Country: Belize
City: Kuala Lumpur
Population: 1448600
使用NetBeans創建XML樣式表的步驟如下:
- 點擊File -> New -> XML -> XSL Stylesheet
- 將文件保存為「city」
- 複製並粘貼上述代碼到NetBeans編輯器,並保存。
- 對於樣式表進行格式良構性檢查。(ALT+F9)
- 注意:作為示例的city系列文件(city.xsd, city.xml and city.xsl)也可以通過文本編輯器創建,並且結果能夠利用合適的瀏覽器例如Mozilla 1.6進行顯示。但是應該將所有的文件保存在同一個目錄下並且在city.xml第一行中加入如下的代碼:
<?xml-stylesheet href="city.xsl" type="text/xsl"?>
該行代碼便將XSL樣式表與包含有城市數據的XML文件建立起關聯。
小結:XSL是一種用來將信息轉換成可表示形式的工具,而且同時還保持數據的含義。 |
XML在 Thomas Cook中的應用
編輯
XML使得同樣的工作能夠在3天之內得到完成。這使得Thomas Cook所有的當前或潛在客戶以及分布在世界各地的代理商能夠獲取實時的旅遊信息。而以前他們至少需要等待6周的時間。
XML格式的宣傳網頁以及旅遊指南和在線雜誌。
提高,而這為ThomasCook提供了微弱的競爭優勢。
|
解析XML文檔
編輯- 我們已經學習了如何表示數據,接下來我們需要的就是處理該數據。這項工作能夠利用一種叫做XML解析器的軟體來實現,XML解析器能夠讀取XML文檔並且對照XML schema進行有效性檢驗。XML解析器使得人們對於XML文檔的內容和結構可以有更
好的了解。它支持XSLT標準,能夠將數據細分並傳遞給其他的應用程式或轉換成其他格式,例如HTML。
解析器類型:
DOM (Document Object Model 文檔目標模型) – 此類解析器將整個XML文檔讀入內存,依據XML文檔創建目標樹結構然後等待用戶的指令。這種方式將受到內存容量的限制因為XML文檔大小有可能超出內存的容量。
SAX, the Simple API for XML 簡單XML應用程式接口, 它是一個基於事件的解析器。此類解析器逐行讀取XML文檔,並在發現任一目標元素時產生一個事件。例如,每個XML根標籤都會伴隨一個「start element」事件。SAX解析器在任 一時刻只會為客戶程序處理文檔的一個或幾個片斷。當發現所需元素時,它便會從文檔中返回數據。對於大型XML文檔來說,SAX提供了在小內存占用量條件下更快和更高效解析XML數據的方法。
- 我們需要針對應用的特點選擇DOM(基於樹)或SAX(基於事件)解析方式。但是,從本書的寫作初衷出發,我們使用一種開放源碼的基於DOM的解析器——Xerces Java。Xerces Java能夠利用DOM方便地讀取文檔數據並進行諸如添加、刪除節點的
操作。Xerces Java由apache.org發起並開發。
- 下面是用來進行解析的XML文檔代碼。解析的結果是根據文檔得到的DOM樹。該java程序由Hendrik Fischer編寫。
(NOTE from Klaas van Gelder (klaasvg@fastmail.fm): the class TypeTranslator does not exist in one of the imported packages, so the code does not compile...)
package Parser_Software; //import class libraries needed for the parsing //*NOTE: already included in latest Java SDK 1.4.x import javax.xml.parsers.*; import org.xml.sax.*; import org.w3c.dom.*; import java.io.*; //import class for Input/Output import java.util.Vector; //insert statement cache public class MySimpleDOMParser { //global reference to our DOM object static Document doc; //parse given XML file when creating MyParser object public MySimpleDOMParser(String filename) { //create file object that holds the XML file File file = new File(filename); try { /* THREE steps are needed to create a parser and save the * document data into a DOM object * 1. create factory object providing the parser */ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //2. create parser object building the DOM object DocumentBuilder parser = factory.newDocumentBuilder(); /* 3. use parse method to create DOM object from the given file * store the resulting DOM object into the "doc" variable */ doc = parser.parse(file); /* +++NOW YOU CAN CALL ANY METHOD TO WORK WITH THIS DATA+++ * example - printNodes: prints out all nodes in the DOM tree * - insertStatements: creates strings holding the insert * statement If the document isn't well-formed, an exception has * already been thrown and this has been skipped. */ System.out.println(file + " is well-formed."); /* The parsing will only succeed if the XML file was well-formed, * in anyother case it will throw an exception that is caught * by the following catch blocks */ } catch (SAXException e) { System.out.println(file + " is not well-formed."); } catch (IOException e) { //usually happens if the file was not found System.out.println("Due to an IOException, " + "the parser could not check " + file); } catch (FactoryConfigurationError e) { System.out.println("Could not locate a factory class"); } catch (ParserConfigurationException e) { //the JAXP class library was not loaded correctly System.out.println("Could not locate a JAXP parser"); } } //print out the nodes starting at a given node (usually the root node) public static void printNode(Node n) { //gather information about the current node name String name = n.getNodeName(); String type = TypeTranslator.getTypeName(n); String uri = n.getNamespaceURI(); String value = n.getNodeValue(); //put results into a string buffer StringBuffer output = new StringBuffer(); output.append("Node : " + name + "\n"); output.append("Type : " + type + "\n"); if (uri != null) output.append("NameSpace : " + uri + "\n"); if (value != null) output.append("Value : " + value + "\n"); //display the result to the user System.out.println(output.toString()); //get a list of the current node's children in the DOM tree NodeList children = n.getChildNodes(); //for every child node do the same - recursive call for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); printNode(child); } }//End of printNode() public static void main(String[] args) { //call this application with the command //line arguments "file.xml file.xsd" MySimpleDOMParser p = new MySimpleDOMParser(args[0]); //get a list of all element nodes "city" NodeList n = doc.getElementsByTagName("city"); printNode(doc); }//End of main() }//End of MySimpleDOMParser class |
使用NetBeans創建並運行XML解析器:
首先,必須創建一個存放java文件的包。
- 點擊File -> New -> Java Package。
- 保存為「'Parser_Software」
然後創建java文件:
- 點擊File -> New -> Java Classes -> Java Class。
- 在java文件包中保存為「MySimpleDOMParser」——創建命名的解析器。
- 複製並粘貼上面的代碼。
- 點擊Build -> Set Arguments...
- 輸入XML文檔的準確路徑。例如,c:\XML_Chapter\Chapter_2_Single_entity\city.xml
- 點擊Build -> Execute,執行操作
解析器輸出結果:
編輯
|
小結:解析器程序使得用戶可以方便地訪問XML文檔的內容和結構,並且允許用戶對於解析器本身進行處理和修正。 |
總結
編輯- XML(可擴展標記語言)是一種在文本文件中以結構化方式描述數據的方法。它主要用於信息的交換。XML是基於網絡的、可擴展的、獨立於平台的語言,它是構建所有XML文檔的基礎。
- XML schema 描述了XML文檔的內容和結構。XML文檔包含了數據,而XML樣式表定義用於XML文檔表示的格式說明。一個結構良好的XML文檔完全遵循了XML句法,而如果文檔同時遵循了相應的XMLschema,那麼它就是有效的。
- 基於DOM的解析器在內存中為待解析的XML文檔建立了一個樹結構,而SAX則是逐步讀取文檔數據並在發現標籤、文本或注釋時報告用戶。
練習
編輯1. 一個博物館的問題。
- a. 創建一個用來描述博物館實體的XML schema,該實體擁有以下屬性:博物館名稱、建館日期、地址、網址。並進行良構性和有效性驗證。
- b. 利用剛才創建的schema創建XML文檔,使其包含有兩個博物館的數據。並進行良構性和有效性驗證。
- c. 編寫XML樣式表來顯示博物館的名稱、建館日期和網址。並進行良構性和有效性驗證。
- d. 編寫一段java程序來對XML文檔進行解析並列出每個博物館的名稱和地址。
2. XML數據流程圖模型。
建立包含以下組件的數據流程圖並解釋其如何工作:
- XSL樣式表
- XML文檔
- XML schema
- XSL(T)處理器
- 不同的輸出結果
練習2的參考答案: