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

Java DOM 解析 XML 字符串實戰:提取屬性值與文本內容

     編輯:Java 綜合教學

Java DOM 解析 XML 字符串實戰:提取屬性值與文本內容

DOM (Document Object Model) 將整個 XML 載入記憶體形成樹結構,適合小型文檔的隨機訪問與修改。本文演示如何使用標準 JDK API (`javax.xml.parsers`) 解析 XML 字符串,提取元素屬性與文本內容。

一、示例 XML 數據

String xmlString = ""
    + ""
    + "  yongyoulogin|用友ESB測試人員|創建|失敗|人員已存在,"
    + "  "
    + "    項目一"
    + "    項目二"
    + "  "
    + "";

二、完整解析代碼

import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.StringReader;

public class DomXmlParser {

    public static void main(String[] args) throws Exception {
        String xmlString = "..."; // 如上 XML

        // 1. 建立 DocumentBuilderFactory (線程不安全,建議每次新建或同步使用)
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // 推薦配置:防止 XXE 攻擊、命名空間感知
        factory.setFeature("https://apache.org/xml/features/disallow-doctype-decl", true);
        factory.setFeature("https://xml.org/sax/features/external-general-entities", false);
        factory.setFeature("https://xml.org/sax/features/external-parameter-entities", false);
        factory.setNamespaceAware(true);

        // 2. 獲取 DocumentBuilder
        DocumentBuilder builder = factory.newDocumentBuilder();

        // 3. 解析字符串輸入源
        StringReader reader = new StringReader(xmlString);
        InputSource inputSource = new InputSource(reader);
        Document doc = builder.parse(inputSource);

        // 4. 獲取根元素
        Element root = doc.getDocumentElement(); // 
        System.out.println("根元素: " + root.getTagName());

        // --- 方式一: 遍歷子節點 (適合結構固定) ---
        NodeList children = root.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node node = children.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) node;
                System.out.println("元素: " + element.getTagName());
                
                // 獲取屬性
                if (element.hasAttributes()) {
                    NamedNodeMap attrs = element.getAttributes();
                    for (int j = 0; j < attrs.getLength(); j++) {
                        Node attr = attrs.item(j);
                        System.out.println("  屬性: " + attr.getNodeName() + " = " + attr.getNodeValue());
                    }
                }
                // 獲取文本內容 (包含子元素文本)
                System.out.println("  文本: " + element.getTextContent().trim());
            }
        }

        // --- 方式二: 精確查找 (推薦生產使用) ---
        // 獲取第一個  的 value 屬性
        NodeList msgList = root.getElementsByTagName("message");
        if (msgList.getLength() > 0) {
            Element msgEl = (Element) msgList.item(0);
            String value = msgEl.getAttribute("value"); // 直接獲取屬性,不存在返回空串
            String text = msgEl.getTextContent();       // 獲取標籤內文本
            System.out.println("message[@value=" + value + "] text=" + text);
        }

        // 獲取所有  的 id、status 及文本
        NodeList items = root.getElementsByTagName("item");
        for (int i = 0; i < items.getLength(); i++) {
            Element item = (Element) items.item(i);
            String id = item.getAttribute("id");
            String status = item.getAttribute("status");
            String name = item.getTextContent().trim();
            System.out.printf("Item: id=%s, status=%s, name=%s%n", id, status, name);
        }
    }
}

三、關鍵 API 對比

需求方法說明
獲取元素屬性值`element.getAttribute("name")`屬性不存在返回空字符串 `""`,不拋異常
獲取屬性節點對象`element.getAttributeNode("name")`返回 `Attr` 對象,可進一步操作
獲取所有屬性`element.getAttributes()`返回 `NamedNodeMap`,可迭代
獲取元素文本內容`element.getTextContent()`包含所有子孫文本節點拼接 (DOM Level 3)
獲取首個子文本節點`element.getFirstChild().getNodeValue()`僅直接文本子節點,較脆弱
按標籤名查找`parent.getElementsByTagName("tag")`返回 `NodeList`,含所有後代 (非僅子代)
按 ID 查找 (需 DTD/Schema 定義 ID 型)`doc.getElementById("id")`需文檔聲明 ID 屬性類型,實際少用

四、常見陷阱與最佳實踐

1. 空白文本節點干擾

XML 格式化縮進會產生 `#text` 類型節點 (換行、空格)。遍歷 `getChildNodes()` 時必須判斷 `node.getNodeType() == Node.ELEMENT_NODE`。

2. 命名空間處理

若 XML 含 `xmlns="..."`,需使用命名空間感知方法:

factory.setNamespaceAware(true);
// 查找
NodeList list = root.getElementsByTagNameNS("https://example.com/ns", "tagName");

3. 安全防範 (XXE 攻擊)

解析不可信 XML 時必須關閉外部實體解析:

factory.setFeature("https://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("https://xml.org/sax/features/external-general-entities", false);
factory.setFeature("https://xml.org/sax/features/external-parameter-entities", false);
factory.setFeature("https://apache.org/xml/features/nonvalidating/load-external-dtd", false);
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);

4. 編碼一致性

XML 宣告 `encoding="UTF-8"` 與 Java `String` (UTF-16) 透明轉換,但若從 `InputStream` 讀取,需確保 `InputSource` 設置正確編碼:`inputSource.setEncoding("UTF-8")`。

5. 效能考量

  • DOM 全量載入記憶體,不適用於大文件 (>50MB),改用 SAX 或 StAX 流式解析。
  • `DocumentBuilderFactory` 非線程安全,多線程環境每次新建或使用 `ThreadLocal` 複用。

五、輸出結果示例

根元素: result
元素: message
  屬性: value = 0
  文本: yongyoulogin|用友ESB測試人員|創建|失敗|人員已存在,
元素: data
  屬性: 
  文本: 項目一項目二
message[@value=0] text=yongyoulogin|用友ESB測試人員|創建|失敗|人員已存在,
Item: id=1001, status=active, name=項目一
Item: id=1002, status=inactive, name=項目二

六、總結

DOM 解析 XML 字符串核心步驟:

  1. `DocumentBuilderFactory` → `DocumentBuilder`
  2. `StringReader` → `InputSource` → `parse()` 獲取 `Document`
  3. `getDocumentElement()` 獲取根元素
  4. `getElementsByTagName()` 精確定位元素
  5. `getAttribute()` 取屬性,`getTextContent()` 取文本

配合安全配置與節點類型判斷,即可穩健提取 XML 數據。

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