我将为你介绍几种主流的方法,从最简单到最健壮,并提供详细的代码示例。

核心思路
无论使用哪种方法,基本流程都一样:
- 准备 XML 字符串: 将你的 XML 内容放在一个
String变量中。 - 创建输入源: 因为解析器通常不直接从
String读取,而是从InputStream或InputSource读取,所以需要将String转换为InputSource。 - 选择解析器: 根据你的需求选择解析器(DOM, SAX, StAX)。
- DOM (Document Object Model): 将整个 XML 文档读入内存,解析成一个树形结构,优点是操作方便,可以随意遍历和修改;缺点是内存消耗大,不适合处理大型 XML 文件。
- SAX (Simple API for XML): 事件驱动的解析器,它不会将整个文档加载到内存,而是当解析器遇到 XML 元素(如开始标签、结束标签、文本内容)时,触发相应的事件(回调方法),优点是内存占用小,速度快;缺点是只能顺序读取,不能回头,操作复杂。
- StAX (Streaming API for XML): 提供了类似 SAX 的事件驱动机制,但它允许你“拉取”(pull)事件,而不是由解析器“推送”(push),代码更直观,性能也高,是介于 DOM 和 SAX 之间的一个很好的折中方案。
- 执行解析: 调用解析器开始解析过程。
- 处理结果: 从解析器获取结果并处理。
使用 DOM 解析器 (最常用,最简单)
DOM 适合小型 XML 文件,因为它提供了最直观的树形结构来访问数据。
添加依赖 (Maven)
虽然 Java 标准库包含 javax.xml,但为了更好的类型安全(如 DocumentBuilderFactory 的配置),推荐使用 jakarta.xml,这是 Java EE 的继任者。
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
<!-- 实现依赖,Glassfish -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>4.0.3</version>
</dependency>
如果你使用的是旧版 Java (Java 8 或更早),则使用 javax.xml。

代码示例
假设我们有以下 XML 字符串:
<bookstore>
<book category="FICTION">
<title lang="en">The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<year>1925</year>
<price>10.99</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J.K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
Java 代码:
import jakarta.xml.parsers.DocumentBuilder;
import jakarta.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import java.io.StringReader;
public class DomParserFromString {
public static void main(String[] args) {
String xmlString = """
<bookstore>
<book category="FICTION">
<title lang="en">The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<year>1925</year>
<price>10.99</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J.K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
""";
try {
// 1. 创建 DocumentBuilderFactory 和 DocumentBuilder
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
// 2. 将 String 转换为 InputSource
InputSource is = new InputSource(new StringReader(xmlString));
// 3. 解析 XML 字符串,得到 Document 对象
Document document = builder.parse(is);
// 4. 获取所有 book 节点
NodeList nodeList = document.getElementsByTagName("book");
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
// 获取属性
String category = element.getAttribute("category");
System.out.println("Book Category: " + category);
// 获取子元素文本内容
String title = element.getElementsByTagName("title").item(0).getTextContent();
String author = element.getElementsByTagName("author").item(0).getTextContent();
String year = element.getElementsByTagName("year").item(0).getTextContent();
String price = element.getElementsByTagName("price").item(0).getTextContent();
System.out.println(" Title: " + title);
System.out.println(" Author: " + author);
System.out.println(" Year: " + year);
System.out.println(" Price: " + price);
System.out.println("-----------------------------");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用 SAX 解析器 (内存高效)
SAX 解析器通过回调方法来处理 XML,你需要实现 org.xml.sax.helpers.DefaultHandler。
代码示例
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import jakarta.xml.parsers.SAXParser;
import jakarta.xml.parsers.SAXParserFactory;
import java.io.StringReader;
public class SaxParserFromString {
public static void main(String[] args) {
String xmlString = """
<bookstore>
<book category="FICTION">
<title lang="en">The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<year>1925</year>
<price>10.99</price>
</book>
</bookstore>
""";
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
// 创建一个自定义的 Handler
DefaultHandler handler = new DefaultHandler() {
boolean inBook = false;
boolean inTitle = false;
boolean inAuthor = false;
boolean inYear = false;
boolean inPrice = false;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) {
if (qName.equalsIgnoreCase("book")) {
inBook = true;
System.out.println("Found a book. Category: " + attributes.getValue("category"));
}
if (inBook && qName.equalsIgnoreCase("title")) {
inTitle = true;
}
if (inBook && qName.equalsIgnoreCase("author")) {
inAuthor = true;
}
if (inBook && qName.equalsIgnoreCase("year")) {
inYear = true;
}
if (inBook && qName.equalsIgnoreCase("price")) {
inPrice = true;
}
}
@Override
public void characters(char[] ch, int start, int length) {
if (inTitle) {
System.out.println(" Title: " + new String(ch, start, length));
inTitle = false;
}
if (inAuthor) {
System.out.println(" Author: " + new String(ch, start, length));
inAuthor = false;
}
if (inYear) {
System.out.println(" Year: " + new String(ch, start, length));
inYear = false;
}
if (inPrice) {
System.out.println(" Price: " + new String(ch, start, length));
inPrice = false;
}
}
@Override
public void endElement(String uri, String localName, String qName) {
if (qName.equalsIgnoreCase("book")) {
inBook = false;
}
}
};
// 解析
InputSource is = new InputSource(new StringReader(xmlString));
saxParser.parse(is, handler);
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用 StAX 解析器 (现代且高效)
StAX 结合了 DOM 的易用性和 SAX 的高效性,你创建一个 XMLStreamReader,然后在一个循环中逐个“拉取”事件。

代码示例
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.StringReader;
public class StaxParserFromString {
public static void main(String[] args) {
String xmlString = """
<bookstore>
<book category="FICTION">
<title lang="en">The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<year>1925</year>
<price>10.99</price>
</book>
</bookstore>
""";
try {
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(new StringReader(xmlString));
String currentElement = null;
String category = null;
while (reader.hasNext()) {
int event = reader.next();
switch (event) {
case XMLStreamConstants.START_ELEMENT:
currentElement = reader.getLocalName();
if ("book".equals(currentElement)) {
category = reader.getAttributeValue(null, "category");
System.out.println("Found a book. Category: " + category);
}
break;
case XMLStreamConstants.CHARACTERS:
if (currentElement != null) {
String text = reader.getText().trim();
if (!text.isEmpty()) {
switch (currentElement) {
case "title":
System.out.println(" Title: " + text);
break;
case "author":
System.out.println(" Author: " + text);
break;
case "year":
System.out.println(" Year: " + text);
break;
case "price":
System.out.println(" Price: " + text);
break;
}
}
}
break;
case XMLStreamConstants.END_ELEMENT:
if ("book".equals(reader.getLocalName())) {
// 一本书解析完毕
}
currentElement = null; // 重置当前元素
break;
}
}
} catch (XMLStreamException | FactoryConfigurationError e) {
e.printStackTrace();
}
}
}
使用 Jackson/Gson (推荐用于 JSON,也支持 XML)
如果你已经在项目中使用了 Jackson 或 Gson 来处理 JSON,那么它们也提供了处理 XML 的能力,这通常非常方便,因为它可以将 XML 直接映射到 Java 对象(反序列化)。
添加 Jackson XML 依赖
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.15.2</version>
</dependency>
创建 Java 模型类
// Book.java
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "book")
public class Book {
@JacksonXmlProperty(isAttribute = true, localName = "category")
private String category;
@JacksonXmlProperty(localName = "title")
private Title title;
@JacksonXmlProperty(localName = "author")
private String author;
@JacksonXmlProperty(localName = "year")
private int year;
@JacksonXmlProperty(localName = "price")
private double price;
// Getters and Setters
// ... (省略)
}
java
public class Title {
@JacksonXmlProperty(isAttribute = true, localName = "lang")
private String lang;
@JacksonXmlProperty(localName = "#text")
private String value;
// Getters and Setters
// ... (省略)
}
解析代码
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.IOException;
public class JacksonXmlParser {
public static void main(String[] args) {
String xmlString = """
<bookstore>
<book category="FICTION">
<title lang="en">The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<year>1925</year>
<price>10.99</price>
</book>
</bookstore>
""";
XmlMapper xmlMapper = new XmlMapper();
try {
// 直接将 XML 字符串映射为 List<Book>
// 注意:Jackson 需要一个根元素,这里我们假设根元素是 book,或者使用 @JacksonXmlRootElement 注解
// 更简单的方式是创建一个 Bookstore 类
Bookstore bookstore = xmlMapper.readValue(xmlString, Bookstore.class);
for (Book book : bookstore.getBooks()) {
System.out.println("Book Category: " + book.getCategory());
System.out.println(" Title: " + book.getTitle().getValue());
System.out.println(" Author: " + book.getAuthor());
System.out.println(" Year: " + book.getYear());
System.out.println(" Price: " + book.getPrice());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// Bookstore.java
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import java.util.List;
@JacksonXmlRootElement(localName = "bookstore")
public class Bookstore {
private List<Book> book;
public List<Book> getBooks() {
return book;
}
public void setBooks(List<Book> book) {
this.book = book;
}
}
总结与选择建议
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| DOM | 简单直观,树形结构易于遍历和修改 | 内存消耗大,解析速度慢,不适合大文件 | 小型 XML 文件,需要频繁查询和修改数据的场景 |
| SAX | 内存占用极小,解析速度快,适合大文件 | 代码复杂,只能顺序读取,不能修改数据 | 大型 XML 文件(如日志文件),内存受限的环境 |
| StAX | 内存效率高,代码比 SAX 清晰,可读性好,性能优秀 | 比 DOM 稍复杂 | 大多数 Java 应用,是处理 XML 的现代推荐方式 |
| Jackson/Gson | 极其方便,与 JSON 处理方式统一,自动映射到 POJO | 需要额外依赖,对复杂 XML 映射可能需要额外配置 | 已经在使用 Jackson/Gson 的项目,或者希望用声明式方式处理 XML |
给初学者的建议:
- 如果你的 XML 很小(比如几百行),直接用 DOM,最简单,不容易出错。
- 如果你的 XML 很大(比如几百兆),或者你对性能有要求,学习并使用 StAX,它在易用性和性能之间取得了很好的平衡。
- 如果你的项目已经在用 Jackson/Gson,并且你想保持技术栈的统一,那么使用 Jackson XML 模块会非常舒服。
