- Java核心技術·卷Ⅱ:高級特性(原書第10版)
- (美)凱S.霍斯特曼
- 2436字
- 2020-10-30 18:10:48
3.2 解析XML文檔
要處理XML文檔,就要先解析(parse)它。解析器是這樣一個程序:它讀入一個文件,確認這個文件具有正確的格式,然后將其分解成各種元素,使得程序員能夠訪問這些元素。Java庫提供了兩種XML解析器:
·像文檔對象模型(Document Object Model,DOM)解析器這樣的樹型解析器(tree parser),它們將讀入的XML文檔轉換成樹結構。
·像XML簡單API(Simple API for XML,SAX)解析器這樣的流機制解析器(streaming parser),它們在讀入XML文檔時生成相應的事件。
DOM解析器對于實現我們的大多數目的來說都更容易一些,所以我們首先介紹它。如果你要處理很長的文檔,用它生成樹結構將會消耗大量內存,或者如果你只是對于某些元素感興趣,而不關心它們的上下文,那么在這些情況下你應該考慮使用流機制解析器。更多的信息可以查看3.6節。
DOM解析器的接口已經被W3C標準化了。org.w3c.dom包中包含了這些接口類型的定義,比如:Document和Element等。不同的提供者,比如Apache組織和IBM,都編寫了實現這些接口的DOM解析器。Java XML處理API(Java API for XML Processing,JAXP)庫使得我們實際上可以以插件形式使用這些解析器中的任意一個。但是JDK中也包含了從Apache解析器導出的DOM解析器。
要讀入一個XML文檔,首先需要一個DocumentBuilder對象,可以從DocumentBuilder Factory中得到這個對象,例如:

現在,可以從文件中讀入某個文檔:

或者,可以用一個URL:

甚至可以指定一個任意的輸入流:

注意:如果使用輸入流作為輸入源,那么對于那些以該文檔的位置為相對路徑而被引用的文檔,解析器將無法定位,比如在同一個目錄中的DTD。但是,可以通過安裝一個“實體解析器”(entity resolver)來解決這個問題。請查看www.xml.com/pub/a/2004/03/03/catalogs.html或www.ibm.com/developerworks/xml/library/x-mxd3.html,以了解更多信息。
Document對象是XML文檔的樹型結構在內存中的表示方式,它由實現了Node接口及其各種子接口的類的對象構成。圖3-1顯示了各個子接口的層次結構。

圖3-1 Node接口及其子接口
可以通過調用getDocumentElement方法來啟動對文檔內容的分析,它將返回根元素。

例如,如果要處理下面的文檔:

那么,調用getDocumentElement方法可以返回font元素。getTagName方法可以返回元素的標簽名。在前面這個例子中,root.getTagName()返回字符串"font"。
如果要得到該元素的子元素(可能是子元素、文本、注釋或其他節點),請使用getChildNodes方法,這個方法會返回一個類型為NodeList的集合。這個類型在標準的Java集合類創建之前就已經被標準化了,因此它具有一種不同的訪問協議;item方法將得到指定索引值的項;getLength方法則提供了項的總數。因此,我們可以像下面這樣枚舉所有子元素:

分析子元素時要很仔細。例如,假設你正在處理以下文檔:

你預期font有兩個子元素,但是解析器卻報告說有5個:
·<font>和<name>之間的空白字符
·name元素
·</name>和<size>之間的空白字符
·size元素
·</size>和</font>之間的空白字符
圖3-2顯示了其DOM樹。

圖3-2 一棵簡單的DOM樹
如果只希望得到子元素,那么可以忽略空白字符:


現在,只會看到兩個元素,它們的標簽名是name和size。
正如將在下一節中所看到的那樣,如果你的文檔有DTD,那么你就可以做得更好。這時,解析器知道哪些元素沒有文本節點的子元素,而且它會幫你剔除空白字符。
在分析name和size元素時,你肯定想獲取它們包含的文本字符串。這些文本字符串本身都包含在Text類型的子節點中。既然知道了這些Text節點是唯一的子元素,就可以用getFirstChild方法而不用再遍歷另一個NodeList。然后可以用getData方法獲取存儲在Text節點中的字符串。

提示:對getData的返回值調用trim方法是個好主意。如果XML文件的作者將起始和結束的標簽放在不同的行上,例如:

那么,解析器將會把所有的換行符和空格都包含到文本節點中去。調用trim方法可以把位于實際數據前后的空白字符刪掉。
也可以用getLastChild方法得到最后一項子元素,用getNextSibling得到下一個兄弟節點。這樣,另一種遍歷子節點集的方法就是:

如果要枚舉節點的屬性,可以調用getAttributes方法。它返回一個NamedNodeMap對象,其中包含了描述屬性的Node對象。可以用和遍歷NodeList一樣的方式在NamedNodeMap中遍歷各子節點。然后,調用getNodeName和getNodeValue方法可以得到屬性名和屬性值。

或者,如果知道屬性名,則可以直接獲取相應的屬性值:

現在你已經知道怎么分析DOM樹了。程序清單3-1中的程序將這些技術都運用了一遍。你可以使用File->Open菜單選項來讀入一個XML文件。DocumentBuilder對象會解析這個XML文件,并產生一個Document對象。該程序會將Document對象顯示為一個JTree(參見圖3-3)。

圖3-3 一摞XML文檔的解析樹
該樹形結構清楚地顯示了子元素是怎樣被包含空白字符和注釋的文本包圍起來的。為了更清楚起見,這個程序將換行和回車字符顯示為\n和\r。(否則,它們將顯示為空框,這是Swing對字符串中不能繪制的字符顯示的默認符號)。
在第10章你將會學習到該程序中用來顯示樹形結構和屬性表的技術。DOMTreeModel類實現了TreeModel接口。getRoot方法會返回文檔的根元素,getChild方法可以得到子元素的節點列表,返回被請求的索引值對應的項。表的單元格渲染器顯示了以下內容:
·對元素,顯示的是元素標簽名和由所有的屬性構成的一張表。
·對字符數據,顯示的是接口(Text、Comment、CDATASection),后面跟著數據,其中換行和回車字符被\n和\r取代。
·對其他所有的節點類型,顯示的是類名,后面跟著toString的結果。
程序清單3-1 dom/Treeviewer.java






javax.xml.parsers.DocumentBuilderFactory 1.4
·static DocumentBuilderFactory newInstance()
返回DocumentBuilderFactory類的一個實例。
·DocumentBuilder newDocumentBuilder()
返回DocumentBuilder類的一個實例。
javax.xml.parsers.DocumentBuilder 1.4
·Document parse(File f)
·Document parse(String url)
·Document parse(InputStream in)
解析來自給定文件、URL或輸入流的XML文檔,返回解析后的文檔。
org.w3c.dom.Document 1.4
·Element getDocumentElement()
返回文檔的根元素。
org.w3c.dom.Element 1.4
·String getTagName()
返回元素的名字。
·String getAttribute(String name)
返回給定名字的屬性值,沒有該屬性時返回空字符串。
org.w3c.dom.Node 1.4
·NodeList getChildNodes()
返回包含該節點所有子元素的節點列表。
·Node getFirstChild()
·Node getLastChild()
獲取該節點的第一個或最后一個子節點,在該節點沒有子節點時返回null。
·Node getNextSibling()
·Node getPreviousSibling()
獲取該節點的下一個或上一個兄弟節點,在該節點沒有兄弟節點時返回null。
·Node getParentNode()
獲取該節點的父節點,在該節點是文檔節點時返回null。
·NamedNodeMap getAttributes()
返回含有描述該節點所有屬性的Attr節點的映射表。
·String getNodeName()
返回該節點的名字。當該節點是Attr節點時,該名字就是屬性名。
·String getNodeValue()
返回該節點的值。當該節點是Attr節點時,該值就是屬性值。
org.w3c.dom.CharacterData 1.4
·String getData()
返回存儲在節點中的文本。
org.w3c.dom.NodeList 1.4
·int getLength()
返回列表中的節點數。
·Node item(int index)
返回給定索引值處的節點。索引值范圍在0到getLength()-1之間。
org.w3c.dom.NamedNodeMap 1.4
·int getLength()
返回該節點映射表中的節點數。
·Node item(int index)
返回給定索引值處的節點。索引值范圍在0到getLength()-1之間。
- Java 開發從入門到精通(第2版)
- Java面向對象思想與程序設計
- Boost C++ Application Development Cookbook(Second Edition)
- Python Deep Learning
- Drupal 8 Configuration Management
- RISC-V體系結構編程與實踐(第2版)
- Android Wear Projects
- 一塊面包板玩轉Arduino編程
- Shopify Application Development
- XML程序設計(第二版)
- Office VBA開發經典:中級進階卷
- 三步學Python
- 瘋狂Java講義精粹
- D Cookbook
- Full Stack Development with JHipster