在企业级开发中,经常需要把第三方系统返回的XML数据转换成Excel报表供运营或财务使用。Java生态里,解析XML有DOM、SAX、StAX等多种方式,而生成Excel最成熟的库莫过于Apache POI。本文以一个订单XML为例,演示如何解析后写出xlsx文件。

一、XML解析方案选择
DOM解析会把整个文档加载进内存,形成树结构,适合几兆以内的小文件,代码直观、调试方便。SAX则是事件驱动,边读边处理,内存占用低,但写起来要自己维护状态机。对于大多数后台报表任务,文件不超过几十兆,用DOM更省心。
下面先用标准JDK自带的DocumentBuilder完成解析,不需要引入额外依赖。我们需要处理命名空间时要格外小心,否则getElementsByTagName可能返回空列表。建议先打印根节点名称确认结构。
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import java.io.File;
public class XmlReader {
public Document parse(String path) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 忽略命名空间,简化查询
factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new File(path));
}
public void printOrders(Document doc) {
NodeList nodes = doc.getElementsByTagName("order");
for (int i = 0; i < nodes.getLength(); i++) {
Element e = (Element) nodes.item(i);
String id = e.getAttribute("id");
String amount = e.getElementsByTagName("amount").item(0).getTextContent();
System.out.println("订单号:" + id + " 金额:" + amount);
}
}
}
二、Apache POI写Excel基础
Apache POI的XSSF模块对应Office Open XML格式(xlsx)。核心类是XSSFWorkbook、XSSFSheet、XSSFRow和XSSFCell。创建工作簿后,先建sheet,再循环建行与单元格,最后用FileOutputStream写出。
需要注意的是,POI在写出大文件时默认会把所有数据放内存,可能触发OOM。如果数据量超过五万行,应使用SXSSFWorkbook,它用临时文件做滑动窗口。下面的例子先用普通XSSFWorkbook演示基本API。
import org.apache.poi.xssf.usermodel.*;
import java.io.FileOutputStream;
public class ExcelWriter {
public void write(java.util.List<String[]> data, String out) throws Exception {
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet("订单表");
// 表头样式
XSSFCellStyle headStyle = wb.createCellStyle();
XSSFFont font = wb.createFont();
font.setBold(true);
headStyle.setFont(font);
for (int r = 0; r < data.size(); r++) {
XSSFRow row = sheet.createRow(r);
String[] cols = data.get(r);
for (int c = 0; c < cols.length; c++) {
XSSFCell cell = row.createCell(c);
cell.setCellValue(cols[c]);
if (r == 0) {
cell.setCellStyle(headStyle);
}
}
}
try (FileOutputStream fos = new FileOutputStream(out)) {
wb.write(fos);
}
wb.close();
}
}
三、将解析与生成串起来
真实场景中,我们会先解析XML拿到订单集合,再组装成二维数组传给ExcelWriter。这样职责分离,后续若改成分库分表查询也容易替换数据源。下面的代码演示整合过程,并加了简单异常处理。
如果XML里日期是字符串,可以用SimpleDateFormat转成Date再写入,POI支持setCellValue(Date)并配合日期格式。另外,中文乱码通常源于文件读取编码,建议用InputStreamReader指定UTF-8。
import org.w3c.dom.*;
import java.util.*;
public class XmlToExcel {
public static void main(String[] args) {
try {
XmlReader reader = new XmlReader();
Document doc = reader.parse("orders.xml");
List<String[]> rows = new ArrayList<>();
rows.add(new String[]{"订单号", "金额", "客户"});
NodeList list = doc.getElementsByTagName("order");
for (int i = 0; i < list.getLength(); i++) {
Element e = (Element) list.item(i);
String id = e.getAttribute("id");
String amount = e.getElementsByTagName("amount").item(0).getTextContent();
String cust = e.getElementsByTagName("customer").item(0).getTextContent();
rows.add(new String[]{id, amount, cust});
}
new ExcelWriter().write(rows, "orders.xlsx");
System.out.println("生成完成");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
四、性能与避坑要点
当XML体积大且只需提取部分字段时,DOM会浪费内存。可改用SAX,在startElement里判断标签名并暂存,endElement里输出一行。与之对应,Excel侧使用SXSSFWorkbook,设置窗口为1000行,旧行自动刷盘。
另一个常见坑是POI依赖的commons-compress或stax-api版本冲突,导致NoSuchMethodError。建议在Maven里锁定poi-ooxml版本,并排除旧传递依赖。此外,写完workbook必须close,否则临时文件不清理,磁盘会被占满。
| 解析方式 | 内存占用 | 适用规模 |
|---|---|---|
| DOM | 高 | 小于50MB |
| SAX | 低 | 数百MB |
| StAX | 低 | 流式处理 |
掌握上述组合,你就能用Java稳定地把各类XML单据转成业务人员喜欢的Excel了。
Java_XML解析Apache_POIExcel生成修改时间:2026-08-08 09:33:28