Excel文件解析 - 什么是SAX和DOM

Excel文件本质是XML文件,对应两种解析方式

  • SAX 流式读取,对应 XSSFReader
  • DOM 树读取,对应 Workbook

很好的问题!让我用通俗易懂的方式解释 SAX 和 DOM 这两种 XML 解析模式。

核心概念

XML 解析器读取 XML 文件时有两种基本策略:

  • SAX:边读边处理(流式)
  • DOM:全部读入后再处理(树状)

SAX (Simple API for XML)

工作原理

复制代码
XML 文件:  →   解析器  →  事件触发  →  你的代码处理
<root>          ↓           ↓
  <a>1</a>   开始读取   "遇到开始标签 <a>"
  <b>2</b>   继续读取   "遇到开始标签 <b>"
</root>       ↓           ↓
           继续读取   "遇到内容 2"
                      "遇到结束标签 </b>"
                      "遇到结束标签 </a>"
                      ...

代码示例

java 复制代码
// SAX 解析器会回调这些方法
public class MyHandler extends DefaultHandler {
    @Override
    public void startElement(String uri, String name, String qName, Attributes atts) {
        System.out.println("开始标签: " + qName);
    }
    
    @Override
    public void characters(char ch[], int start, int length) {
        System.out.println("内容: " + new String(ch, start, length));
    }
    
    @Override
    public void endElement(String uri, String name, String qName) {
        System.out.println("结束标签: " + qName);
    }
}

生活中的类比:流水线工人

  • 你站在流水线旁
  • 产品(数据)一个接一个经过
  • 你看到一个就处理一个
  • 不需要记住之前的产品
  • 优点:省空间,速度快
  • 缺点:不能回头看前面的产品

SAX 的特点

优点 缺点
✅ 内存占用极低 ❌ 只能顺序读取
✅ 处理速度快 ❌ 不能随机访问
✅ 适合大文件 ❌ 代码稍复杂
✅ 可以随时停止 ❌ 需要自己维护状态

DOM (Document Object Model)

工作原理

复制代码
XML 文件:  →   解析器  →  内存中的树  →  你的代码操作
<root>          ↓           ↓
  <a>1</a>   全部读取    root
  <b>2</b>   构建树      ├── a: "1"
</root>                  └── b: "2"
                         整棵树都在内存中!

代码示例

java 复制代码
// DOM 解析后,整个文档树都在内存中
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File("data.xml"));

// 可以随意访问任何节点
NodeList nodes = doc.getElementsByTagName("a");
for (int i = 0; i < nodes.getLength(); i++) {
    System.out.println(nodes.item(i).getTextContent());
}

// 可以修改节点
nodes.item(0).setTextContent("新值");

// 可以添加新节点
Element newElement = doc.createElement("c");
newElement.setTextContent("3");
doc.getDocumentElement().appendChild(newElement);

生活中的类比:图书馆管理员

  • 把所有书(数据)都搬到阅览室
  • 可以随时去翻任何一本书
  • 可以在书上做笔记、修改
  • 但需要很大的阅览室(内存)
  • 优点:灵活方便
  • 缺点:占空间,搬书耗时间

DOM 的特点

优点 缺点
✅ 可以随机访问任何节点 ❌ 内存占用高
✅ 可以修改文档 ❌ 加载整个文件慢
✅ 可以遍历多次 ❌ 不适合大文件
✅ 代码简单直观 ❌ 需要等待全部加载

直观对比

读取一个 10MB 的 XML 文件

SAX 方式
复制代码
内存占用:约 20MB
处理时间:1 秒
工作方式:像看电视,边播边看
DOM 方式
复制代码
内存占用:约 200MB+
处理时间:3 秒
工作方式:像下载电影,全下载完再看

具体示例对比

假设有这个 XML 文件:

xml 复制代码
<students>
    <student id="1">
        <name>张三</name>
        <age>20</age>
    </student>
    <student id="2">
        <name>李四</name>
        <age>21</age>
    </student>
    <student id="3">
        <name>王五</name>
        <age>22</age>
    </student>
</students>

SAX 处理流程(事件驱动)

复制代码
1. 开始标签 <students>    → 触发 startElement()
2. 开始标签 <student>     → 触发 startElement()
3. 开始标签 <name>        → 触发 startElement()
4. 内容 "张三"            → 触发 characters()
5. 结束标签 </name>       → 触发 endElement()
6. 开始标签 <age>         → 触发 startElement()
7. 内容 "20"              → 触发 characters()
8. 结束标签 </age>        → 触发 endElement()
9. 结束标签 </student>    → 触发 endElement()
...(继续处理后面的学生)

DOM 处理流程(树状结构)

复制代码
加载完成后,内存中是这样的树:

Document
 └── students
      ├── student (id="1")
      │    ├── name: "张三"
      │    └── age: "20"
      ├── student (id="2")
      │    ├── name: "李四"
      │    └── age: "21"
      └── student (id="3")
           ├── name: "王五"
           └── age: "22"

然后你可以:
- 直接访问第3个学生:doc.getElementsByTagName("student").item(2)
- 修改年龄:student.getElementsByTagName("age").item(0).setTextContent("23")
- 删除某个学生
- 添加新学生

什么时候用哪种?

用 SAX 的场景 ✅

  • 📄 大文件(> 10MB)
  • 🚀 只需要读取一次(不需要回看)
  • 💾 内存受限(嵌入式设备、高并发场景)
  • 📊 数据导入(Excel、CSV 等批量处理)
  • 🔍 提取特定信息(比如只找某个标签的内容)

用 DOM 的场景 ✅

  • 📝 需要修改文档(增删改)
  • 🔀 需要随机访问(跳到任意位置)
  • 🔄 需要多次遍历
  • 📦 小文件(< 1MB)
  • 🛠️ 复杂查询(XPath、XSLT)
  • 🎨 需要结构化操作(维护文档关系)

回到你的 Excel 解析问题

java 复制代码
// SAX 方式(你看到的第一个代码)
XMLReader parser = XMLReaderFactory.createXMLReader(...);
parser.parse(sheetSource);
// 优点:处理 100MB 的 Excel 只需 50MB 内存

// DOM 方式(你看到的第二个代码)
Workbook workbook = WorkbookFactory.create(inputStream);
// 缺点:100MB 的 Excel 可能需要 2GB+ 内存

结论 :Excel 文件本质上是 XML(.xlsx 是 ZIP+XML),批量导入场景下,SAX 是更优的选择

希望这个解释能帮你理解 SAX 和 DOM 的区别!

相关推荐
悟能不能悟2 小时前
echo 怎么设置不换行
java
jaysee-sjc2 小时前
【项目二】用GUI编程实现石头迷阵游戏
java·开发语言·算法·游戏
それども2 小时前
Excel文件解析 - SAX和DOM方式的区别
java·前端·excel
それども2 小时前
Excel文件解析 - SAX startRow cell endRow 执行顺序
java·前端·excel
梦因you而美2 小时前
Python win32com操作Excel:彻底禁用链接更新及各类弹窗(实测有效)
python·excel·win32com·禁用链接更新·excel弹框
それども2 小时前
Excel文件解析 - SAX startRow cell endRow 执行时机
java·excel
椎4952 小时前
java微服务01-快速入门、mybatisplus
java·微服务
为什么不问问神奇的海螺呢丶2 小时前
n9e categraf k8s监控配置-n9e k8s监控看板
java·容器·kubernetes
浩浩测试一下2 小时前
内网---> ForceChangePassword 权限滥用
java·服务器·网络·安全·web安全·网络安全·系统安全