You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SAX Parser解析XML时如何精准保留标签内容中的空格?

解决SAX解析XML时的空白保留与多余空白过滤问题

给定XML文件(注意标签前的缩进空白):

<?xml version="1.0" encoding="UTF-8"?>
<main>
    <tagA>190</tagA>
    <tagB>  :  </tagB>
    <tagc>2019-07-02</tagc>
</main>

预期解析结果:

tagA "190"
tagB "  :  "
tagC "2019-07-02"

问题:使用SAX的DefaultHandler时,characters()方法会被多次调用,直接拼接会包含元素间的缩进换行等多余空白;修剪内容会丢失tagB的有效空格,不修剪则tagA、tagC的结果不符合预期;尝试取最后一次characters结果不可靠(大文件内容可能拆分多次),预先线性化文件又担心大文件内存安全。

核心思路

通过跟踪当前是否处于目标元素内部,区分元素间的空白节点(缩进、换行等无效空白)和元素内的文本内容(包括需要保留的有效空白),再针对不同元素应用不同的空白处理规则。

具体实现步骤

  1. 标记当前元素状态:在自定义Handler中添加布尔变量,标记是否处于需要处理的元素内部。
  2. 累积元素文本内容:用StringBuilder实时累积当前元素内的所有字符片段,避免单次characters()调用丢失内容。
  3. 分元素处理空白:维护一个需要保留原始空白的元素列表,其他元素的内容自动修剪空白,列表内的元素直接保留原始内容。

代码示例

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.HashSet;
import java.util.Set;

public class CustomXMLHandler extends DefaultHandler {
    // 需要保留原始空白的元素集合
    private static final Set<String> PRESERVE_WHITESPACES = new HashSet<>();
    static {
        PRESERVE_WHITESPACES.add("tagB");
    }

    private boolean inTargetElement = false;
    private StringBuilder currentContent = new StringBuilder();
    private String currentTagName;

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        // 进入目标元素时,标记状态并重置内容缓冲区
        currentTagName = qName;
        inTargetElement = true;
        currentContent.setLength(0);
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        // 仅当处于目标元素内部时,才累积字符内容
        if (inTargetElement) {
            currentContent.append(ch, start, length);
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (inTargetElement) {
            String content;
            if (PRESERVE_WHITESPACES.contains(qName)) {
                // 保留原始空白
                content = currentContent.toString();
            } else {
                // 修剪多余空白
                content = currentContent.toString().trim();
            }
            // 输出结果(可替换为业务逻辑处理)
            System.out.printf("%s \"%s\"%n", qName, content);
            // 重置状态
            inTargetElement = false;
            currentTagName = null;
        }
    }
}

大文件适配说明

  • 每个元素处理完成后立即清空StringBuilder,不会在内存中累积整个XML文件内容,内存占用始终保持在单个元素内容的量级,完全适配大文件场景。
  • 无需预先修改XML文件,避免了大文件读写的额外开销和内存溢出风险。

内容的提问来源于stack exchange,提问作者ilmagowalter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 04:10:35