首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

使用 JDom 輕鬆整合 Java 與 XML:核心 API 實戰指南

     編輯:Java 相關知識

概述

JDom 是用 Java 語言讀、寫、操作 XML 的新 API 函式庫。Jason Hunter 與 Brett McLaughlin 公開發布測試版本。在直覺、簡單、高效前提下,API 被最大限度優化。本文介紹如何用 JDom 讀寫現有 XML 文件。

JDom 是開源 API,以直接易懂方式向 Java 程式設計師描述 XML 文件與內容。名稱揭示其為 Java 優化。提供低消耗方法使用 XML 文件。使用者不必掌握太多 XML 知識即可完成想要操作。

JDom 可與現有 XML 技術如 SAX、DOM 相互協作。但非簡單從這些 API 提取。JDom 吸收現有技術優點,建立一套新類別與介面。用 JDom 使用者話說:「這些介面是我從一開始閱讀 org.w3c.dom 就期待的」。JDom 可讀入 SAX 或 DOM 內容,也可輸出 SAX 或 DOM 可接收格式,使 JDom 能與已有 SAX/DOM 建立的系統良好整合。

JDom 設計原則

  1. 簡單易懂:API 設計對 Java 程式設計師簡單易懂。其他 XML 解析 API 設計為語言通用(支援相同 API 在 Java、C++、JavaScript)。JDom 利用 Java 優秀特性:方法多載、回收機制、背景處理等。為簡單易用,函式以程式設計師喜歡形式描繪 XML 文件。例:程式設計師想到的元素文字內容:<element>This is my text content</element>。某些 API 中元素文字內容僅作為子節點,需 element.getFirstChild().getValue() 存取。JDom 提供更簡單方法:String text = element.getText()。依拇指規則,JDom 應用 20% 或更少努力完成 80% 或更多 Java/XML 問題。非指僅支援 80% XML 規範(實際希望 100% 支援),而是說某些東西可加入但非必要,API 應保持簡潔。
  2. 快速輕量:載入與執行文件應快速,記憶體消耗盡量小。JDom 設計遵循此原則。例如起始時不協調操作已比 DOM 快,雖比 SAX 粗糙,但擁有 SAX 沒有的優點。

你需要 JDom 嗎?

已有現有標準,為何發明新的?答案:JDom 解決現有標準解決不了的問題。

  • DOM:完全在記憶體中描述元素樹。大型 API,設計處理幾乎所有 XML 任務。必須有相同 API 支援不同語言。因限制,習慣 Java 特性(方法多載、簡單 set/get)的程式設計師很不習慣。DOM 需大量記憶體與高主頻,難與輕量級 Web 應用共事。
  • SAX:不在記憶體建立元素樹,用事件驅動方式描述(報告每個讀到的開始/結束標記)。輕量級快速讀取 API。但事件處理方式對伺服器端 Java 程式設計師不夠直觀。SAX 不支援修改 XML 文件與隨機讀取。
  • JDom:嘗試結合 DOM 與 SAX 優點。設計為小記憶體上快速執行的輕量級 API。支援隨機讀取整個文件,但驚人之處在於不需將整個文件讀入記憶體。API 支援未來按需讀取資訊的次輕量級操作。並透過標準建構器與 set 方法支援 XML 文件修改。

取得 XML 文件

JDom 用 org.jdom.Document 類別實例描述 XML 文件。Document 類別為輕量級,可包含文件型別、多處理指令物件、根元素與註解物件。可無建構器從草稿建構文件:

Document doc = new Document(new Element("rootElement"));

稍後討論從草稿建構 XML 文件多麼容易。現在從現有檔案、串流、URL 路徑建構文件:

SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(url);

可用 org.jdom.input 套件提供的建構類別從任何資料源建構文件。目前有兩種建構方式:SAXBuilder 與 DOMBuilder。SAXBuilder 用 SAX 解析器從檔案建構文件,偵聽 SAX 事件並從記憶體建立對應文件,速度極快(基本與 SAX 一樣快),推薦方式。DOMBuilder 從現有 org.w3c.dom.Document 物件建立 JDom 文件,允許 JDom 輕鬆與建構 DOM 樹工具實作介面。

JDom 速度有提高潛力透過延遲建構器完成。此建構器檢查 XML 資料源,但請求時才解析。例如:文件屬性不存取時無需解析。建構器仍在發展,可透過 SQL 查詢、LDAP 查詢、其他資料格式建構 JDom 文件。一旦進入記憶體,文件與建造工具無關係。

SAXBuilder 與 DOMBuilder 允許使用者指定是否驗證,以確定哪個解析器執行解析任務:

public SAXBuilder(String parserClass, boolean validation);
public DOMBuilder(String adapterClass, boolean validation);

預設用 Apache 開源 Xerces 解析器且關閉驗證。注意 DOMBuilder 不像解析類別,更像適配類別。因非所有 DOM 解析器相同 API。為讓使用者選擇喜歡解析器,JDom 使用一個對所有 DOM 解析器適用的公共 API 適配類別。支援所有流行 DOM 解析器:Apache Xerces、Crimson、IBM XML4J、Sun Project X、Oracle parsers V1/V2。每個解析器透過正確呼叫其他解析器方法執行標準介面。有點像 JAXP,除支援 JAXP 不支援的新解析器。

輸出 XML 文件

可用幾種標準輸出工具輸出 XML 文件。org.jdom.output.XMLOutputter 或許最常用,將 XML 文件寫入特定 OutputStream。SAXOutputter 產生基於 JDom XML 文件的 SAX 事件,可送給等待 SAX 事件的應用程式。DOMOutputter 產生 DOM 文件,可送給接收 DOM 文件的應用程式。輸出程式碼:

XMLOutputter outputter = new XMLOutputter();
outputter.output(doc, System.out);

XMLOutputter 用參數定制輸出格式。第一參數為行縮排格式;第二參數為是否換行。機器對機器為速度考慮可放棄縮排與換行:

XMLOutputter outputter = new XMLOutputter("", false);
outputter.output(doc, System.out);

(註:支援中文帶換行縮排格式:XMLOutputter outp = new XMLOutputter("", true, "GB2312"); outp.setTextTrim(true);)

完整範例:讀入 XML 並輸出

import java.io.*;
import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;

public class PrettyPrinter {
    public static void main(String[] args) {
        String filename = args[0];
        try {
            SAXBuilder builder = new SAXBuilder();
            Document doc = builder.build(new File(filename));
            XMLOutputter fmt = new XMLOutputter();
            fmt.output(doc, System.out);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

讀取文件型別

許多 XML 文件有文件型別宣告,JDom 用 DocType 類別描述。文件型別宣告範例:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

DOCTYPE 後第一個詞揭示文件強制型別名稱,PUBLIC 後為公共屬性,最後為系統屬性。透過 getDocType() 取得,DocType 提供取得宣告的方法:

DocType docType = doc.getDocType();
System.out.println("Element: " + docType.getElementName());
System.out.println("Public ID: " + docType.getPublicID());
System.out.println("System ID: " + docType.getSystemID());

讀取文件資料

每個 XML 文件必須有根元素,是存取所有內部資訊起點。例:<web-app id="demo"> 為根元素。根元素實例直接取得:

Element webapp = doc.getRootElement();

可存取元素屬性(如 id)、內容與子元素。

存取子元素

XML 文件為樹狀結構,任何元素可包含任意數量子元素。例:<web-app> 有 <description> 與 <distributable> 子元素。取得子元素方法:

List getChildren();           // 回傳所有子元素
List getChildren(String name); // 依名稱回傳所有子元素
Element getChild(String name); // 依名稱回傳第一個子元素

示例:

// 取得所有直接子元素為 Element 物件的 List
List allChildren = element.getChildren();
out.println("First kid: " + ((Element)allChildren.get(0)).getName());
// 取得指定名稱所有直接子元素
List namedChildren = element.getChildren("name");
// 取得指定名稱第一個子元素
Element kid = element.getChild("name");

文件結構預知時,getChild() 容易快速取得巢狀元素。例:

<?xml version="1.0"?>
<linux:config>
  <gui>
    <window-manager>
      <name>Enlightenment</name>
      <version>0.16.2</version>
    </window-manager>
    <!-- etc -->
  </gui>
</linux:config>

直接取得 window manager 名稱:

String windowManager = rootElement.getChild("gui")
    .getChild("window-manager")
    .getChild("name")
    .getText();

文件不可用時小心 NullPointerException。未來 JDom 可能支援 XPath 實現簡單文件導航。子元素可透過 getParent() 取得父元素。

取得文件屬性

屬性是元素擁有的另一組資訊。HTML 程式設計師熟悉。例:<table width="100%" border="0"> 有 width 與 border 屬性。直接取得:

String width = table.getAttributeValue("width");

也可用屬性實例重新取得,支援進階概念如命名空間屬性:

Attribute widthAttrib = table.getAttribute("width");
String width = widthAttrib.getValue();

為方便可取得屬性原始資料型別:

int width = table.getAttribute("border").getIntValue();

可轉換至任何基本型別。屬性無法轉換時拋出 DataConversionException。屬性不存在 getAttribute() 回傳 null。

提取文件內容

element.getText() 提取文字內容極簡單,適用標準文件:<name>Enlightenment</name>。但文件有時包含註解、文字內容與子元素,甚至處理指令:

<table>
  <!-- Some comment -->
  Some text
  <tr>Some child</tr>
  <?pi Some processing instruction?>
</table>

標準方式取得文字內容與子元素:

String text = table.getText(); // "Some text"
Element tr = table.getChild("tr"); // <tr> child

使標準使用簡單。需取得文件所有內容順序時(如輸出),用特殊方法 getMixedContent()。回傳 List,內容可能包含註解、字串、元素、處理指令實例。Java 程式設計師可用 instanceof 取得內容。列印文件內容摘要:

List mixedContent = table.getMixedContent();
Iterator i = mixedContent.iterator();
while (i.hasNext()) {
    Object o = i.next();
    if (o instanceof Comment) {
        out.println("Comment: " + o);
    } else if (o instanceof String) {
        out.println("String: " + o);
    } else if (o instanceof ProcessingInstruction) {
        out.println("PI: " + ((ProcessingInstruction)o).getTarget());
    } else if (o instanceof Element) {
        out.println("Element: " + ((Element)o).getName());
    }
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved