在Java开发中,从输入流InputStream解析XML是常见的需求,比如读取网络请求返回的XML数据、解析本地文件流中的XML内容等,不同的解析方式适配不同的业务场景,下面介绍几种主流的实现方案。

DOM解析方式
DOM解析会将整个XML文档加载到内存中,形成一棵DOM树,方便开发者随机访问和修改文档节点,适合XML体积较小、需要频繁操作文档结构的场景。
实现步骤
- 创建
DocumentBuilderFactory实例 - 通过工厂类获取
DocumentBuilder实例 - 调用
DocumentBuilder的parse方法,传入InputStream对象得到Document对象 - 通过
Document对象提供的方法操作XML节点
代码示例
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
public class DomXmlParser {
public static void parseXmlByDom(InputStream inputStream) {
try {
// 创建DocumentBuilderFactory实例
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 获取DocumentBuilder实例
DocumentBuilder builder = factory.newDocumentBuilder();
// 解析输入流得到Document对象
Document document = builder.parse(inputStream);
// 获取根节点
Element rootElement = document.getDocumentElement();
System.out.println("根节点名称:" + rootElement.getNodeName());
// 获取指定标签名的节点列表
NodeList nodeList = rootElement.getElementsByTagName("user");
for (int i = 0; i < nodeList.getLength(); i++) {
Element userElement = (Element) nodeList.item(i);
String id = userElement.getAttribute("id");
String name = userElement.getElementsByTagName("name").item(0).getTextContent();
String age = userElement.getElementsByTagName("age").item(0).getTextContent();
System.out.println("用户id:" + id + ",姓名:" + name + ",年龄:" + age);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
SAX解析方式
SAX解析是基于事件驱动的解析方式,不会将整个XML文档加载到内存中,而是逐行读取并触发对应的事件,适合处理大体积的XML文件,内存占用更低。
实现步骤
- 创建
SAXParserFactory实例 - 通过工厂类获取
SAXParser实例 - 自定义
DefaultHandler子类,重写事件处理方法 - 调用
SAXParser的parse方法,传入InputStream和自定义Handler实例
代码示例
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.InputStream;
public class SaxXmlParser {
public static void parseXmlBySax(InputStream inputStream) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
// 自定义Handler处理解析事件
DefaultHandler handler = new DefaultHandler() {
private String currentElement = null;
private String currentId = null;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
currentElement = qName;
if ("user".equals(qName)) {
currentId = attributes.getValue("id");
System.out.println("开始解析用户节点,id:" + currentId);
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if ("name".equals(currentElement)) {
String name = new String(ch, start, length);
System.out.println("用户姓名:" + name);
} else if ("age".equals(currentElement)) {
String age = new String(ch, start, length);
System.out.println("用户年龄:" + age);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("user".equals(qName)) {
System.out.println("用户节点解析完成");
}
currentElement = null;
}
};
saxParser.parse(inputStream, handler);
} catch (Exception e) {
e.printStackTrace();
}
}
}
StAX解析方式
StAX解析是一种拉式的解析方式,开发者可以主动控制解析进度,按需读取XML节点,兼顾了灵活性和低内存占用的特点,使用起来比SAX更直观。
实现步骤
- 创建
XMLInputFactory实例 - 通过工厂类获取
XMLEventReader实例,传入InputStream对象 - 循环遍历
XMLEventReader中的事件,处理对应节点
代码示例
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import java.io.InputStream;
public class StaxXmlParser {
public static void parseXmlByStax(InputStream inputStream) {
try {
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(inputStream);
while (reader.hasNext()) {
int eventType = reader.next();
switch (eventType) {
case XMLStreamConstants.START_ELEMENT:
String elementName = reader.getLocalName();
if ("user".equals(elementName)) {
String id = reader.getAttributeValue(null, "id");
System.out.println("用户id:" + id);
} else if ("name".equals(elementName)) {
System.out.println("姓名:" + reader.getElementText());
} else if ("age".equals(elementName)) {
System.out.println("年龄:" + reader.getElementText());
}
break;
default:
break;
}
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
不同解析方式对比
三种解析方式的特性对比如下:
| 解析方式 | 内存占用 | 操作灵活性 | 适用场景 |
|---|---|---|---|
| DOM解析 | 较高,需要加载整个文档 | 高,可随机访问修改节点 | 小体积XML,需要操作文档结构 |
| SAX解析 | 低,逐行读取不加载全文档 | 低,基于事件被动触发 | 大体积XML,仅需读取数据 |
| StAX解析 | 低,按需读取节点 | 较高,主动控制解析进度 | 中大型XML,需要灵活控制解析流程 |
注意事项
- 解析完成后需要手动关闭
InputStream流,避免资源泄漏 - 如果XML中包含特殊字符,需要提前处理编码问题,确保输入流的编码和XML声明的编码一致
- 生产环境中建议对解析过程添加异常捕获,避免非法XML格式导致程序崩溃
JavaInputStreamXML解析DOM解析SAX解析修改时间:2026-06-11 19:00:41