使用 dom4j 解析 Spring `beans.xml` 配置檔,涵蓋 `SAXReader` 讀取、`Element` 遍歷、屬性增刪改、節點新增、格式化寫入檔案的完整實戰代碼。適用於需程式化操作 Spring XML 的場景。
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.4</version>
</dependency>
<!-- 需相容的 JAXP 實現,如 xerces 或 JDK 內建 -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService" class="com.example.UserService">
<property name="userDao" ref="userDao"/>
<property name="cacheEnabled" value="true"/>
</bean>
<bean id="userDao" class="com.example.UserDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
</beans>
import org.dom4j.*;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.List;
public class SpringXmlParser {
public static void main(String[] args) throws Exception {
// 1. 建立 SAXReader
SAXReader reader = new SAXReader();
// 2. 讀取檔案 -> Document
Document document = reader.read(new File("src/main/resources/beans.xml"));
// 3. 取得根元素
Element root = document.getRootElement();
// 4. 遍歷所有 bean 子元素
List beans = root.elements("bean");
for (Element bean : beans) {
String id = bean.attributeValue("id");
String clazz = bean.attributeValue("class");
System.out.println("Bean: id=" + id + ", class=" + clazz);
// 遍歷 property 子元素
for (Element prop : bean.elements("property")) {
String name = prop.attributeValue("name");
String value = prop.attributeValue("value");
String ref = prop.attributeValue("ref");
System.out.println(" Property: name=" + name +
(value != null ? ", value=" + value : "") +
(ref != null ? ", ref=" + ref : ""));
}
}
}
}
public static void printTree(Element node, int indent) {
String prefix = " ".repeat(indent);
System.out.println(prefix + "Element: " + node.getName());
// 列印屬性
for (Attribute attr : node.attributes()) {
System.out.println(prefix + " Attr: " + attr.getName() + " = " + attr.getValue());
}
// 列印文字內容
String text = node.getTextTrim();
if (!text.isEmpty()) {
System.out.println(prefix + " Text: " + text);
}
// 遞迴子元素
for (Element child : node.elements()) {
printTree(child, indent + 1);
}
}
// 呼叫
printTree(document.getRootElement(), 0);
public static void addProperty(Document doc) {
Element root = doc.getRootElement();
// 找到 id="dataSource" 的 bean
Element dsBean = (Element) root.selectSingleNode("//bean[@id='dataSource']");
if (dsBean != null) {
Element prop = dsBean.addElement("property");
prop.addAttribute("name", "maximumPoolSize");
prop.addAttribute("value", "20");
System.out.println("已新增 maximumPoolSize=20");
}
}
public static void addBean(Document doc) {
Element root = doc.getRootElement();
Element bean = root.addElement("bean");
bean.addAttribute("id", "redisTemplate");
bean.addAttribute("class", "org.springframework.data.redis.core.RedisTemplate");
Element prop = bean.addElement("property");
prop.addAttribute("name", "connectionFactory");
prop.addAttribute("ref", "redisConnectionFactory");
System.out.println("已新增 redisTemplate bean");
}
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
public static void writeXml(Document doc, String outPath) throws Exception {
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
format.setIndent(" "); // 兩空格縮排
format.setNewlines(true);
XMLWriter writer = new XMLWriter(
new OutputStreamWriter(new FileOutputStream(outPath), "UTF-8"), format);
writer.write(doc);
writer.flush();
writer.close();
System.out.println("已寫入: " + outPath);
}
// Spring beans 預設命名空間 URI
String nsUri = "https://www.springframework.org/schema/beans";
// 建立 Namespace 物件
Namespace ns = Namespace.get("beans", nsUri);
// 查詢時需帶命名空間
Element root = doc.getRootElement();
List beans = root.elements(new QName("bean", nsUri));
// 或用 XPath
List beans2 = root.selectNodes("//beans:bean",
new org.dom4j.XPathPattern("//beans:bean").getNamespaces());
public class SpringXmlDemo {
public static void main(String[] args) throws Exception {
SAXReader reader = new SAXReader();
Document doc = reader.read(new File("beans.xml"));
// 1. 列印原始結構
printTree(doc.getRootElement(), 0);
// 2. 修改:dataSource 新增屬性
addProperty(doc);
// 3. 新增:redisTemplate bean
addBean(doc);
// 4. 寫入新檔
writeXml(doc, "beans-modified.xml");
}
// ... 上述輔助方法
}
| 問題 | 對策 |
|---|---|
| 中文亂碼 | `OutputFormat.setEncoding("UTF-8")` + `OutputStreamWriter(..., "UTF-8")` |
| 命名空間查不到元素 | 用 `QName(name, namespaceURI)` 或 XPath 註冊前綴 |
| 寫入後 XML 宣告缺失 | `OutputFormat.createPrettyPrint()` 會自動輸出 `` |
| 大檔案記憶體溢位 | 改用 StAX (`XMLStreamReader`) 流式解析 |
| DTD/Schema 驗證失敗 | `reader.setValidation(false)` 或 `reader.setEntityResolver` 忽略外部 DTD |
掌握 `SAXReader.read()` → `Element.elements()/attributeValue()` → `addElement()/addAttribute()` → `XMLWriter.write()` 核心鏈路,即可靈活程式化操作 Spring XML 配置。