Java XML 處理
Java 提供多種處理 XML 的 API,包括 DOM、SAX、StAX 和 JAXB。
DOM 解析
將整個 XML 載入記憶體,適合小型 XML。
import javax.xml.parsers.*;
import org.w3c.dom.*;
String xml = """
<?xml version="1.0"?>
<users>
<user id="1">
<name>Alice</name>
<age>25</age>
</user>
<user id="2">
<name>Bob</name>
<age>30</age>
</user>
</users>
""";
// 解析
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(xml)));
// 讀取元素
NodeList users = doc.getElementsByTagName("user");
for (int i = 0; i < users.getLength(); i++) {
Element user = (Element) users.item(i);
String id = user.getAttribute("id");
String name = user.getElementsByTagName("name").item(0).getTextContent();
String age = user.getElementsByTagName("age").item(0).getTextContent();
System.out.println(id + ": " + name + ", " + age);
}
DOM 建立 XML
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.newDocument();
// 建立元素
Element root = doc.createElement("users");
doc.appendChild(root);
Element user = doc.createElement("user");
user.setAttribute("id", "1");
root.appendChild(user);
Element name = doc.createElement("name");
name.setTextContent("Alice");
user.appendChild(name);
// 輸出
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(new DOMSource(doc), new StreamResult(System.out));
SAX 解析
事件驅動,適合大型 XML,記憶體效率高。
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import javax.xml.parsers.*;
class UserHandler extends DefaultHandler {
StringBuilder content = new StringBuilder();
String currentElement;
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) {
currentElement = qName;
if ("user".equals(qName)) {
System.out.println("User ID: " + attrs.getValue("id"));
}
}
@Override
public void characters(char[] ch, int start, int length) {
content.append(ch, start, length);
}
@Override
public void endElement(String uri, String localName, String qName) {
if ("name".equals(qName)) {
System.out.println("Name: " + content.toString().trim());
}
content.setLength(0);
}
}
// 使用
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
parser.parse(new InputSource(new StringReader(xml)), new UserHandler());
StAX 解析
串流 API,介於 DOM 和 SAX 之間。
import javax.xml.stream.*;
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(new StringReader(xml));
while (reader.hasNext()) {
int event = reader.next();
switch (event) {
case XMLStreamConstants.START_ELEMENT:
System.out.println("開始: " + reader.getLocalName());
break;
case XMLStreamConstants.CHARACTERS:
String text = reader.getText().trim();
if (!text.isEmpty()) {
System.out.println("內容: " + text);
}
break;
case XMLStreamConstants.END_ELEMENT:
System.out.println("結束: " + reader.getLocalName());
break;
}
}
reader.close();
JAXB(Java 11+ 需額外引入)
將 XML 和 Java 物件互相轉換。
import jakarta.xml.bind.*;
import jakarta.xml.bind.annotation.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
class User {
@XmlAttribute
private int id;
private String name;
private int age;
// getters, setters
}
// 物件轉 XML(序列化)
User user = new User(1, "Alice", 25);
JAXBContext context = JAXBContext.newInstance(User.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(user, System.out);
// XML 轉物件(反序列化)
Unmarshaller unmarshaller = context.createUnmarshaller();
User parsed = (User) unmarshaller.unmarshal(new StringReader(xmlString));
XPath 查詢
import javax.xml.xpath.*;
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
Document doc = ...; // DOM Document
// 查詢單一值
String name = xpath.evaluate("/users/user[@id='1']/name", doc);
// 查詢節點集
XPathExpression expr = xpath.compile("//user");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
方法比較
| 方法 | 記憶體 | 速度 | 隨機存取 | 適用場景 |
|---|---|---|---|---|
| DOM | 高 | 較慢 | 支援 | 小型 XML、需要修改 |
| SAX | 低 | 快 | 不支援 | 大型 XML、只讀 |
| StAX | 低 | 快 | 有限 | 大型 XML、串流 |
| JAXB | 中 | 中 | 支援 | 物件映射 |
重點整理
- DOM:載入整個 XML,適合小型檔案和需要修改的場景
- SAX:事件驅動,記憶體效率高,適合大型檔案
- StAX:拉取式解析,比 SAX 更直觀
- JAXB:物件與 XML 互轉,需要 Java 11+ 額外引入
- XPath:強大的查詢語言