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

JDOM 2.x 實戰:XML 文件讀寫與操作完整指南

     編輯:Java 相關知識

前言:為什麼選擇 JDOM?

在 Java 處理 XML 的四大主流方案(DOM、SAX、StAX、JDOM)中,JDOM 以「純 Java 設計、API 直觀、記憶體效率優於 DOM」著稱。JDOM 2.x 全面支援 Java 8+、Namespace、XPath、XSLT、Schema 驗證,是伺服器端配置檔解析、資料交換的優秀選擇。本文以實務範例示範完整讀寫流程。

一、專案依賴設定

Maven



    org.jdom
    jdom2
    2.0.6.1 



    jaxen
    jaxen
    1.2.0

Gradle (Kotlin DSL)


implementation("org.jdom:jdom2:2.0.6.1")
implementation("jaxen:jaxen:1.2.0")

二、範例 XML 結構

檔案:books.xml




    
        Effective Java
        Joshua Bloch
        2018
        45.99
        9780134685991
    
    
        Clean Architecture
        Robert C. Martin
        2017
        38.50
        9780134494166
    

三、XML 讀取與查詢操作

1. 基礎解析:SAXBuilder


import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.jdom2.filter.Filters;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
import java.io.File;
import java.util.List;

public class JdomReadDemo {
    public static void main(String[] args) throws Exception {
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(new File("books.xml"));
        Element root = doc.getRootElement();
        
        // 取得所有 book 元素
        List books = root.getChildren("book");
        for (Element book : books) {
            String id = book.getAttributeValue("id");
            String category = book.getAttributeValue("category");
            String title = book.getChild("title").getText();
            String author = book.getChildText("author");
            double price = Double.parseDouble(book.getChildText("price"));
            
            System.out.printf("ID: %s | 類別: %s | 書名: %s | 作者: %s | 價格: %.2f%n",
                id, category, title, author, price);
        }
    }
}

2. 進階查詢:XPath 表達式(需 jaxen 相依)


public class JdomXPathDemo {
    public static void main(String[] args) throws Exception {
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(new File("books.xml"));
        
        XPathFactory xpf = XPathFactory.instance();
        
        // 查詢所有 programming 類別的書名
        XPathExpression expr = xpf.compile(
            "//book[@category='programming']/title", Filters.element());
        List titles = expr.evaluate(doc);
        System.out.println("Programming 類別書名:");
        titles.forEach(e -> System.out.println("  - " + e.getText()));
        
        // 查詢價格大於 40 的書籍(需自訂邏輯或 XSLT)
        // JDOM 本身不支援 XPath 2.0 數值比較,建議用 Java Stream 過濾
        List expensiveBooks = root.getChildren("book").stream()
            .filter(b -> Double.parseDouble(b.getChildText("price")) > 40)
            .toList();
        System.out.println("\n價格 > 40 的書籍:");
        expensiveBooks.forEach(b -> System.out.println("  - " + b.getChildText("title")));
    }
}

3. 命名空間處理


import org.jdom2.Namespace;

public class JdomNamespaceDemo {
    public static void main(String[] args) throws Exception {
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(new File("books.xml"));
        Element root = doc.getRootElement();
        
        // 定義命名空間
        Namespace bkNs = Namespace.getNamespace("bk", "https://example.com/bookstore");
        
        // 使用命名空間查詢子元素
        for (Element book : root.getChildren("book")) {
            Element title = book.getChild("title", bkNs); // 關鍵:指定 Namespace
            String lang = title.getAttributeValue("lang", Namespace.NO_NAMESPACE);
            System.out.println("書名: " + title.getText() + " (語言: " + lang + ")");
        }
    }
}

四、XML 建立與寫入操作

1. 程式化建立 Document


import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.Namespace;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import java.io.FileWriter;

public class JdomWriteDemo {
    public static void main(String[] args) throws Exception {
        // 定義命名空間
        Namespace bkNs = Namespace.getNamespace("bk", "https://example.com/bookstore");
        
        // 建立根元素
        Element root = new Element("bookstore", bkNs);
        root.addNamespaceDeclaration(bkNs); // 宣告 xmlns:bk
        Document doc = new Document(root);
        
        // 新增第一本書
        Element book1 = new Element("book");
        book1.setAttribute("id", "bk003");
        book1.setAttribute("category", "microservices");
        
        Element title1 = new Element("title", bkNs);
        title1.setAttribute("lang", "en");
        title1.setText("Building Microservices");
        book1.addContent(title1);
        
        book1.addContent(new Element("author").setText("Sam Newman"));
        book1.addContent(new Element("year").setText("2021"));
        
        Element price1 = new Element("price");
        price1.setAttribute("currency", "USD");
        price1.setText("42.00");
        book1.addContent(price1);
        
        Element isbn1 = new Element("isbn");
        isbn1.setAttribute("type", "ISBN-13");
        isbn1.setText("9781492034025");
        book1.addContent(isbn1);
        
        root.addContent(book1);
        
        // 輸出格式化 XML
        Format format = Format.getPrettyFormat()
            .setEncoding("UTF-8")
            .setIndent("    ") // 4 空格縮排
            .setLineSeparator("\n");
        
        XMLOutputter outputter = new XMLOutputter(format);
        try (FileWriter writer = new FileWriter("books_new.xml")) {
            outputter.output(doc, writer);
        }
        System.out.println("XML 檔案寫入完成:books_new.xml");
    }
}

2. 修改現有 XML 並回寫


public class JdomModifyDemo {
    public static void main(String[] args) throws Exception {
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(new File("books.xml"));
        Element root = doc.getRootElement();
        
        // 找到特定書籍並更新價格
        for (Element book : root.getChildren("book")) {
            if ("bk001".equals(book.getAttributeValue("id"))) {
                Element price = book.getChild("price");
                double oldPrice = Double.parseDouble(price.getText());
                double newPrice = oldPrice * 0.9; // 9 折
                price.setText(String.format("%.2f", newPrice));
                price.setAttribute("currency", "USD");
                System.out.println("更新價格: " + oldPrice + " -> " + newPrice);
                break;
            }
        }
        
        // 寫回原檔(建議先備份)
        XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
        try (FileWriter writer = new FileWriter("books.xml")) {
            outputter.output(doc, writer);
        }
    }
}

五、Schema 驗證(XSD)


import org.jdom2.input.sax.XMLReaders;
import org.xml.sax.SAXException;

public class JdomValidationDemo {
    public static void main(String[] args) {
        try {
            // 建立支援 Schema 驗證的 Builder
            SAXBuilder builder = new SAXBuilder(XMLReaders.XSDVALIDATING);
            builder.setProperty("https://java.sun.com/xml/jaxp/properties/schemaLanguage",
                "https://www.w3.org/2001/XMLSchema");
            builder.setProperty("https://java.sun.com/xml/jaxp/properties/schemaSource",
                new File("bookstore.xsd"));
            
            Document doc = builder.build(new File("books.xml"));
            System.out.println("✓ XML 通過 Schema 驗證");
        } catch (SAXException e) {
            System.err.println("✗ Schema 驗證失敗: " + e.getMessage());
        } catch (Exception e) {
            System.err.println("解析錯誤: " + e.getMessage());
        }
    }
}

六、效能與記憶體考量

解析器記憶體模型適用場景速度
DOM / JDOM樹狀結構全載入記憶體中小型 XML、需隨機存取、修改中等
SAX事件驅動、不建樹大型 XML、單向讀取、記憶體受限快
StAX拉取式、游標控制大型 XML、需部分跳過、雙向控制快
JDOM + SAXBuilder建樹但可配合 Filter大多數企業應用最佳平衡點中等

大檔案處理建議

  • 使用 SAXBuilder 搭配 ElementFilter 只建立需要的子樹
  • 或改用 StAX (javax.xml.stream) 手動處理流式讀寫
  • 避免一次性載入超過可用 Heap 50% 的 XML

七、常見坑與最佳實務

  1. 編碼一致性:讀寫皆明確指定 UTF-8,避免平台預設編碼差異
  2. 命名空間正確性:建立元素時同步宣告 Namespace,查詢時必須指定
  3. 特殊字元逸出:JDOM 自動處理 `< > & " '`,勿手動字串拼接 XML
  4. 輸出格式化:生產環境可用 Format.getCompactFormat() 減小體積
  5. 執行緒安全:Document 非執行緒安全,多執行緒環境需同步或複製

總結

JDOM 2.x 提供了符合 Java 慣用語的 XML 操作 API,在可讀性、功能完整度與效能間取得良好平衡。掌握 SAXBuilder 解析、XPath 查詢、Namespace 處理、XMLOutputter 序列化四大核心操作,即可應對絕大多數企業級 XML 整合場景。對於超大型 XML 或極致效能需求,可考慮 StAX 或 SAX 作為補充方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved