XMLParserDelegate 解析失败数据为空的主因是未调用 parse();需确保 delegate 赋值后调用 parse(),验证数据编码为 UTF-8,禁用 DTD 外部实体,用栈管理嵌套层级,大文件须后台解析并避免字符串拼接。

XMLParserDelegate 解析失败时没报错但数据为空
常见现象是 parser(_:didStartElement:namespaceURI:qualifiedName:attributes:) 完全没被调用,或者只触发一次就停住。根本原因不是 XML 格式错,而是你没调用 parse() —— 很多人以为初始化 XMLParser 就自动开始解析了。
实操建议:
- 确保在
XMLParser实例创建后、且 delegate 已赋值完毕,再调用parser.parse() - 检查 XML 数据源:如果是从网络加载,必须等
Data完整到达后再传给XMLParser(data:);用文件路径初始化时,确认URL有效且文件可读 - iOS 15+ 上如果 XML 含 DTD 声明(如
<!DOCTYPE ...>),默认会拒绝解析,需设置parser.shouldResolveExternalEntities = false并捕获parser(_:parseErrorOccurred:)中的NSXMLParserInternalError
嵌套结构里 parent/child 关系丢失
XMLParser 是事件驱动、无状态的流式解析器,它不维护节点树。你看到的 <book><author>... 在回调里只是连续两个 didStartElement,没有内置父子引用。
实操建议:
- 自己用栈管理层级:遇到
didStartElement就push当前元素名,遇到didEndElement就pop;当前栈顶就是父元素 - 不要依赖
parser.currentTag(不存在)或试图在foundCharacters里“回溯”上一个标签——字符数据回调可能被切片多次,且和标签回调异步 - 如果需要完整 DOM 式结构,别硬扛,改用
SWXMLHash或XMLCoder,XMLParserDelegate不适合深度嵌套+多同名子节点的场景
中文或特殊字符解析成乱码或空字符串
典型错误是把 UTF-8 编码的 XML 当作 ASCII 或 Latin-1 处理。iOS 系统默认按 UTF-8 解析,但如果你手动构造 Data 或从非标准来源读取,编码可能错位。
实操建议:
- 验证原始
Data是否真为 UTF-8:用String(data: encoding: .utf8)能正常转出中文才安全 - 避免用
String(bytes:encoding:)手动解码后再喂给 parser;直接传原始Data给XMLParser(data:) - 如果 XML 声明里写了
encoding="GB2312",iOS 不支持 GBK 系列编码,必须先用String.Encoding.gbk(需第三方库如SwiftGBK)转成 UTF-8Data再解析
解析大文件时内存暴涨或主线程卡死
XMLParser 本身轻量,但如果你在 foundCharacters 里反复拼接 String、或把所有节点缓存进数组,就会触发大量临时对象分配。
实操建议:
- 在
foundCharacters中只做最小动作:用characters.append(contentsOf:)追加到预分配的NSMutableString或[UInt8],别用+=拼String - 解析过程必须在后台队列进行:
DispatchQueue.global(qos: .userInitiated).async { parser.parse() },否则阻塞 UI - 超过 10MB 的 XML 文件,考虑分块解析(如用
InputStream流式读取 + 自定义缓冲区),或换用基于 SAX 的更底层方案(如 libxml2 封装)
真正麻烦的是混合命名空间 + CDATA + 实体引用 + 递归嵌套四者同时出现——这时候 delegate 回调的顺序和边界已经很难靠手工状态机稳住,该换方案就换。










