Java XML教程(1-3章)

來源:互聯網
上載者:User
xml|教程 來源:http://d23xapp2.cn.ibm.com/developerWorks/education/xml/xmljava/tutorial/xmljava-1-1.html

第一章 入門介紹

關於本教程  
在本教程中,我們將討論如何使用一個 XML 解析器來:
處理一個 XML 文檔
建立一個 XML 文檔
操作一個 XML 文檔
我們也將討論一些有用而不為眾人所知的 XML 解析器特性。 最重要的,我們所討論的每個工具都可從 IBM 的 alphaWorks 網站 (www.alphaworks.ibm.com) 和其它網站免費獲得。

未討論的:

有些重要的編程概念並未在此介紹:
1 使用可視工具來構建 XML 應用
2 將一個 XML 文檔從一種形式轉換到另一種
3 為終端使用者或其他進程建立介面,及對後端儲存資料的介面
當您構建一個 XML 應用時,所有這些概念都是重要的。我們正在編製新的教程來討論它們,因此請常光顧我們的網址!

XML 應用架構

一個 XML 應用通常是基於一個 XML 解析器而構建的。它為其使用者提供了一個介面,以及對後端儲存資料的一個介面。

本教程關注於編寫使用 XML 解析器來操作 XML 文檔的 Java 代碼。如下邊圖片所示,本教程關注於中間那塊。







第二章 解析器基礎

基礎

一個 XML 解析器是一段可以讀入一個文檔並分析其結構的代碼。在本章節,我們將討論如何使用一個 XML 解析器來讀入一個 XML 文檔。我們也將討論不同類型的解析器以及您在何時使用它們。

本教程後面的章節將討論您從解析器可以獲得什麼以及如何使用這些結果。

如何使用一個解析器

我們將在稍後的章節詳細討論它,但通常而言,您如下使用它:

1 建立一個解析器對象
2 將您的 XML 文檔傳遞給解析器
3 處理結果
構建一個 XML 應用顯然遠遠超出這些,但通常一個 XML 的應用將包含這些流程。

解析器種類

有不同的方法來劃分解析器種類:

驗證或非驗證解析器
支援 Document Object Model (DOM) 的解析器
支援 Simple API for XML (SAX) 的解析器
用特定語言編寫的解析器 (Java, C++, Perl 等)

驗證或非驗證解析器

如我們在第一個教程中所提及的,XML 文檔如果使用一個 DTD 並符合 DTD 中的規則將被稱為有效文檔(valid document)。符合基本標記規則的 XML 文檔被稱為格式正確文檔(well-formed document)。

XML 規範要求所有的解析器當其發現一個文檔不是格式正確時要報錯。驗證(Validation)則是另一個問題了。驗證解析器(Validating parser)在解析 XML 文檔同時進行驗證。非驗證解析器(Non-validating parser) 忽略所有的驗證錯誤。換而言之,如果一個 XML 文檔是格式正確的時,一個非驗證解析器並不關注文檔是否符合其對應 DTD 所指定的規則(如果有的話)。

為何使用非驗證解析器?

速度和效率。要一個 XML 解析器處理 DTD 並確保每個 XML 的元素符合在 DTD 中的規則需要相當大的開銷。如果您確定一個 XML 文檔是有效(可能來自一個資料來源),那就沒有必要在次驗證它了。

同樣,有時您所需要的只是從一個文檔中找出 XML 的標記。一旦您有了這些標記,您可以將資料從中提取出然後加以處理。如果這就是您所需要的,一個非驗證解析器就是正確的選擇。

Document Object Model (DOM)

文件物件模型(Document Object Model)是 World Wide Web Consortium(W3C) 的正式推薦。它定義了一個介面使得程式可以存取和更新 XML 文檔的風格、結構和內容。支援 DOM 的 XML 解析器實現該介面。

該規範的第一版,DOM Level 1,可從 http://www.w3.org/TR/REC-DOM-Level-1 獲得, 如果您願意閱讀規範的話。

DOM 解析器可提供什麼

當您用一個 DOM 解析器來解析一個 XML 文檔時,您將獲得一個包含文檔中所有元素的樹結構。DOM 提供了不同的功能來檢查文檔的內容和結構。

關於標準

現在我們即將討論開發 XML 應用了,我們也要關注 XML 的標準。正式而言,XML 是 MIT(麻省理工) 的商標和 World Wide Web Consortium (W3C)組織的產品。

XML 規範,W3C 的正式推薦,可從 www.w3.org/TR/REC-xml 下載。W3C 網站包含了 XML、DOM 以及一大堆 XML 相關標準的規範。

Simple API for XML (SAX)

SAX API 是另一種處理 XML 文檔內容的方法。一個既成事實的標準,它由 David Megginson 和 XML-Dev 郵件清單其它成員所開發。

要查看完整的 SAX 標準,參見 www.megginson.com/SAX/。要參加 XML-Dev 郵件清單,發送郵件到 majordomo@ic.ac.uk 其中包含: subscribe xml-dev。

SAX 解析器可提供什麼

當您使用 SAX 解析器來解析 XML 文檔時,解析器在文檔的不同處將產生事件。由您來決定對每個事件如何處理。

SAX 解析器會在以下情況下產生事件:在文檔開始和結束時,在一個元素開始和結束時,或者它在一個元素中找到字元時,以及其它若干點。您可編寫 Java 代碼來處理每個事件,以及如何處理從解析器獲得的資訊。

何時使用 SAX?何時使用 DOM?

我們將在稍後的章節詳細討論這個問題,但通常而言,您在下列時候應該使用一個 DOM 解析器:

您需要十分瞭解文檔的結構
您需要操作文檔中的某些部分(例如,您可能想對某些元素排序)
您需要不止一次使用文檔中的資訊
當您只需要從一個 XML 文檔中提取若干元素時,可使用 SAX 解析器。SAX 解析器在您沒有大多數記憶體時、或者如果您只需要使用文檔中的資訊一次(而不是解析文檔一次,而後要反覆使用它)。

不同語言的 XML 解析器

在 Web 上使用的大多數語言都有其對應的 XML 解析器和庫,包括 Java、C++、Perl 和 Python。下一頁介紹了 IBM 或其它公司提供的解析器的連結。

本教程中絕大多數的樣本是使用 IBM 的 XML4J 解析器。我們所討論的所有代碼使用標準的介面。在本教程的最後章節,我們將向您展現編寫可使用不同解析器的代碼是如何簡單。

Java

IBM 的解析器,XML4J,可從 www.alphaWorks.ibm.com/tech/xml4j 獲得。
James Clark 的解析器,XP,可從 www.jclark.com/xml/xp 獲得。
Sun 的 XML 解析器可從 developer.java.sun.com/developer/products/xml/ (您必需成為 Java Developer Connection 的會員)下載。
DataChannel 的 XJParser 可從 xdev.datachannel.com/downloads/xjparser/ 獲得。


C++

IBM 的 XML4C 解析器可從 www.alphaWorks.ibm.com/tech/xml4c 獲得。
James Clark 的 C++ 解析器,expat,可從 www.jclark.com/xml/expat.html 獲得。


Perl

有多種 Perl 語言的 XML 解析器。要獲得更多資訊,參見 www.perlxml.com/faq/perl-xml-faq.html。


Python

要獲得更多 Python 語言的 XML 解析器,參見 www.python.org/topics/xml/。

總結

任何 XML 應用的核心是一個 XML 解析器。要處理一個 XML 文檔,您的應用將建立一個 parser 對象,將一個 XML document 傳遞給它,然後處理從 parser 對象返回的結果。

我們討論了不同類型的 XML 解析器,以及您為何選取其一。我們用不同方式來對解析器分類:

驗證或非驗證解析器
支援 Document Object Model (DOM) 的解析器
支援 Simple API for XML (SAX) 的解析器
用特定語言編寫的解析器 (Java, C++, Perl 等)
在我們的下一章節,我們將探討 DOM 解析器和如何使用它們。

第三章 DOM (Document Object Model)
Dom, dom, dom, dom, dom,
Doobie, doobie,
Dom, dom, dom, dom, dom...

DOM 是一個操作文檔結構的通用介面。它設計的一個目標是為一個 DOM 相容解析器所編寫的 Java 代碼應該可以使用其它任意 DOM 相容的解析器而不需要修改代碼。(我們稍後將展示這個。)

正如我們前面所提的,一個 DOM 解析器將以樹形式返回您整個文檔的結構。

範例程式碼

在我們繼續以前,請您下載我們的樣本 XML 應用程式。解開此檔案 xmljava.zip,就可以了!(blueski:***或者查看本教程附錄)

DOM 介面

DOM 定義了多個 Java 介面。下列是常用的:

Node: DOM 基本的資料類型。
Element: 您將最主要處理的對象是 Element。
Attr: 代表一個元素的屬性。
Text: 一個 Element 或 Attr 的實際內容。
Document: 代表整個 XML 文檔。一個 Document 對象通常也被稱為一棵 DOM 樹。

常用的 DOM 方法

當您使用 DOM 時,下列是您將常會使用的方法:

Document.getDocumentElement()
返迴文檔的根(root)元素。
Node.getFirstChild() and Node.getLastChild()
返回給定 Node 的第一個子女。
Node.getNextSibling() and Node.getPreviousSibling()
它將刪除 DOM 樹中一切內容,格式化您的硬碟,然後給您地址簿中每個人發送一個謾罵的郵件。(不是真的啦。這些方法返回下一個或前一個給定 Node 的同胞。)
Node.getAttribute(attrName)
對給定的 Node,返回給定名稱的屬性。例如,如果您要獲得名為 id 屬性 的對象,可調用 getAttribute("id")。

我們的第一個 DOM 應用!

介紹了很多概念,讓我們繼續吧。我們的第一個應用簡單地讀入一個 XML 文檔並將其內容輸出到標準輸出。

在一個命令列視窗,運行下面的命令:

java domOne sonnet.xml

這個命令將載入我們的應用然後讓它解析 sonnet.xml 檔案。如果一切運行正常,您將看到 XML 文檔的內容被輸出到標準輸出。
<?xml version="1.0"?>
<sonnet type="Shakespearean">
<author>
<last-name>Shakespeare</last-name>
<first-name>William</first-name>
<nationality>British</nationality>
<year-of-birth>1564</year-of-birth>
<year-of-death>1616</year-of-death>
</author>
<title>Sonnet 130</title>
<lines>
<line>My mistress?eyes are ...

domOne 剖析

domOne 的源碼是非常直了的。我們建立一個新的類 domOne;它有兩個方法,parseAndPrint 以及 printDOMTree。

在 main 方法中,我們處理命令列,建立一個 domOne 對象,然後將檔案名稱傳遞給 domOne 對象。domOne 對象建立一個 parser 對象,解析文檔,然後通過 printDOMTree 方法處理 DOM 樹 (即 Document 對象)。

我們將詳細研究每個步驟。
public class domOne
{
public void parseAndPrint(String uri)
...
public void printDOMTree(Node node)
...
public static void main(String argv[])
...

處理命令列

處理命令列的代碼在左面顯示。我們將檢查使用者是否在命令列上輸入參數。如果沒有,我們列印使用方法並推出;否則,我們假定命令列上第一個參數( Java 語言中的 argv[0] ) 是文檔名。我們忽略使用者可能輸入的其它參數。

我們使用命令列參數來簡化我們的樣本。在大多數情況下,一個 XML 應用可能使用 servlet、Java Bean 和其它類型的組件一起使用;而用命令列參數並不是一個問題。

public static void main(String argv[])
{
if (argv.length == 0)
{
System.out.println("Usage: ... ");
...
System.exit(1);
}

domOne d1 = new domOne();
d1.parseAndPrint(argv[0]);
}
建立一個 domOne 對象

在我們的範例程式碼中,我們建立一個單獨的類 domOne。要解析檔案和列印結果,我們建立一個 domOne 類的執行個體,然後讓我們剛建立的 domOne 對象來解析和列印 XML 文檔。

我們為何這樣處理?由於我們想要使用一個遞迴方法來遍曆 DOM 樹並列印出結果。我們無法用一個如 main 的靜態方法來處理,因此我們建立一個單獨的類來處理它。


public static void main(String argv[])
{
if (argv.length == 0)
{
System.out.println("Usage: ... ");
...
System.exit(1);
}

domOne d1 = new domOne();
d1.parseAndPrint(argv[0]);
}
建立一個 Parser 對象

現在我們已經讓 domOne 的執行個體來解析和處理我們的 XML 文檔,它的第一個處理是建立一個新的 Parser 對象。在此例中,我們將使用一個 DOMParser 對象,一個實現 DOM 介面的 Java 類。在 XML4J 包中還有其它 parser 對象,例如 SAXParser、ValidatingSAXParser 和 NonValidatingDOMParser。

注意我們將這段代碼放在一個 try 模組中。parser 在某些情況下將拋出異常(exception),包括一個無效的 URI、找不到一個 DTD 或者一個 XML 文檔不是有效或格式錯誤。要很好地處理它,我們要捕獲異常(exception)。

try
{
DOMParser parser = new DOMParser();
parser.parse(uri);
doc = parser.getDocument();
}

解析 XML 文檔

解析文檔只是簡單的一行代碼。當解析結束時,我們獲得解析器產生的 Document 對象。

如果 Document 對象不是 null (如果解析過程出錯它將是 null),我們將其傳遞給 printDOMTree 方法。

try
{
DOMParser parser = new DOMParser();
parser.parse(uri);
doc = parser.getDocument();
...
if (doc != null)
printDOMTree(doc);
}

處理 DOM 樹

現在解析已經完成,我們將遍曆 DOM 樹。注意這段代碼是遞迴的。對每個節點,我們處理其本身,然後我們對每個節點的子女遞迴地調用 printDOMTree 方法。遞迴調用如左所示。

要記住當有些 XML 文檔非常大時,它們反而不會有太多層標記。以一個上海市的電話簿為例,可能有幾百萬條記錄,但其標記可能不會超過幾層。考慮到這個原因,遞迴演算法的棧溢出不是一個問題。

public void printDOMTree(Node node)
{
int nodeType = Node.getNodeType();
switch (nodeType)
{
case DOCUMENT_NODE:
printDOMTree(((Document)node).
GetDocumentElement());
...
case ELEMENT_NODE:
...
NodeList children =
node.getChildNodes();
if (children != null)
{
for (int i = 0;
i < children.getLength();
i++)
printDOMTree(children.item(i));
}

很多 Node

如果您查看 sonnet.xml,有二十四個節點。您可能認為這意味著二十四個節點。然而,這不正確。在 sonnet.xml 中一共有 69 個節點;一個文檔節點(document node), 23 個元素節點(element node)以及 45 個文本節點(text node)。我們運行 java domCounter sonnet.xml 就獲得了下邊所示的結果。

domCounter.java

這段代碼解析一個 XML 文檔,然後遍曆 DOM 樹來採集有關該文檔的資料。當資料擷取後將其輸出到標準輸出。


統計 sonnet.xml 的資料:
====================================
Document Nodes: 1
Element Nodes: 23
Entity Reference Nodes: 0
CDATA Sections: 0
Text Nodes: 45
Processing Instructions: 0
----------
Total: 69 Nodes

節點列表示例

對於下邊的片斷,
<sonnet type="Shakespearean">
<author>
<last-name>Shakespeare</last-name>
下列是從解析器返回的節點:

Document 節點


Element 節點對應於 <sonnet> 標記
一個 Text 節點對應於 <sonnet> 節點後的斷行符號符以及 <author> 標記前的兩個空格符
Element 節點對應於 <author> 標記
一個 Text 節點對應於 <author> 節點後的斷行符號符以及 <last-name> 標記前的四個空格符
Element 節點對應於 <last-name> 標記

所有那些文本節點

如果您查看由解析器返回的所有節點列表,您將發現它們大多數是沒用的。在每行開始的空格符組成其中包含可忽略的 Text 節點。

注意如果您將所有的節點放在一行上我們就不會得到這些無用的節點了。我們通過添加分行符和空格符來提高文檔的可讀性。

當您構建一個 XML 文檔時不需要考慮可讀性,就可省略分行符和空格符。這可使得您的文檔更小,處理您的文檔時也不需要構建那些無用的節點。


所有那些文本節點

如果您查看由解析器返回的所有節點列表,您將發現它們大多數是沒用的。在每行開始的空格符組成其中包含可忽略的 Text 節點。

注意如果您將所有的節點放在一行上我們就不會得到這些無用的節點了。我們通過添加分行符和空格符來提高文檔的可讀性。

當您構建一個 XML 文檔時不需要考慮可讀性,就可省略分行符和空格符。這可使得您的文檔更小,處理您的文檔時也不需要構建那些無用的節點。

<sonnet type="Shakespearean">
<author>
<last-name>Shakespeare</last-name>
<first-name>William</first-name>
<nationality>British</nationality>
<year-of-birth>1564</year-of-birth>
<year-of-death>1616</year-of-death>
</author>
<title>Sonnet 130</title>
<lines>
<line>My mistress' eyes are nothing like the sun,</line>

一個 Text 節點對應於 "Shakespeare" 字元
如果您看到標記間所有的空格符,您可發現為何我們有那麼多超出您想像的節點。

瞭解您的 Node

我們最後對處理在 DOM 樹的 Node 要指出的是,我們在處理其之前要檢查每個 Node 的類型。一些方法,例如 getAttributes,對一些特定的節點類型返回 null 值。如果您不檢查節點類型,您將得到不正確的結果(最佳情況)和異常(最差情況)。

在此所介紹的 switch 語句常出現在使用 DOM 解析器的代碼。
switch (nodeType)
{
case Node.DOCUMENT_NODE:
...
case Node.ELEMENT_NODE:
...
case Node.TEXT_NODE:
...
}  


總結

不管您信不信,這就是我們使用 DOM 對象所要瞭解的所有內容。我們的 domOne 程式碼完成了下列工作:

建立一個 Parser 對象
將一個 XML 文檔傳遞給 Parser 來解析
獲得來自於 Parser 的 Document 對象然後加以檢查。
在本教程最後一章,我們將討論如何不需要 XML 原檔案來構建一棵 DOM 樹,並展示如何對一個 XML 文檔中的元素排序。而那些都是基於我們這裡所討論的概念之上。

在我們繼續那些更進階的應用前,我們將詳細探討 SAX API。我們同樣將使用類似的樣本,展現 SAX 和 DOM 的不同處。


相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。