如何解析CDATA段内嵌XML的XML文件 避免Java堆内存溢出
内嵌CDATA大体积XML的解析方案
核心逻辑是全程使用流式解析,完全避免全量加载大体积内容到堆内存,解决Java堆OOM问题。
- 实现思路:
用JDK自带的StAX(流式拉取XML解析API)串联两层XML的解析过程:先流式解析外层XML,定位到<c>标签的CDATA段时直接读取字符流,不转存为完整字符串,直接将流传递给内层XML的流式解析器处理,全程内存仅留存当前解析的节点片段,250M的内嵌XML不需要全部加载到内存。 - 代码实现示例:
import javax.xml.stream.*; import java.io.*; public class NestedXmlParser { public static void main(String[] args) throws Exception { // 直接读取文件流,不要提前读入内存转为字符串/字节数组 FileInputStream outerFileStream = new FileInputStream("你的外层XML文件路径.xml"); XMLInputFactory staxFactory = XMLInputFactory.newInstance(); // 外层XML流式解析 XMLStreamReader outerReader = staxFactory.createXMLStreamReader(outerFileStream); while (outerReader.hasNext()) { int eventType = outerReader.next(); // 定位到<c>标签 if (eventType == XMLStreamConstants.START_ELEMENT && "c".equals(outerReader.getLocalName())) { while (outerReader.hasNext()) { int innerEventType = outerReader.next(); // 命中CDATA段 if (innerEventType == XMLStreamConstants.CDATA) { // 直接获取CDATA字符流,不要调用getText()(会全量读取成字符串导致OOM) Reader cdataStream = outerReader.getTextCharacters(); // 内层XML直接复用流解析,无需缓存全量内容 XMLStreamReader innerReader = staxFactory.createXMLStreamReader(cdataStream); while (innerReader.hasNext()) { int innerEvent = innerReader.next(); // 此处添加你的内层XML节点处理逻辑即可 // if (innerEvent == XMLStreamConstants.START_ELEMENT) { // System.out.println(innerReader.getLocalName()); // } } innerReader.close(); break; } // 遇到c标签结束直接跳出 if (innerEventType == XMLStreamConstants.END_ELEMENT && "c".equals(outerReader.getLocalName())) { break; } } break; } } outerReader.close(); outerFileStream.close(); } }
- 注意事项:
- 绝对不要调用
XMLStreamReader.getText()方法读取CDATA内容,该方法会把整个CDATA段一次性加载为字符串,直接触发OOM,必须使用getTextCharacters()获取流处理。 - 全程使用文件流直接解析,不要先把整个外层XML读入内存再处理。
- 绝对不要调用
内容的提问来源于stack exchange,提问作者paul
相关产品推荐
相关产品推荐

