推荐使用系统原生 XMLParser,它基于 SAX 事件驱动、内存占用低;需实现 XMLParserDelegate,在 didStartElement、foundCharacters、didEndElement 中协同管理状态、累积文本、组装对象。

Swift 中解析 XML 推荐使用系统原生的 XMLParser(基于 SAX 的事件驱动解析器),它 内存占用 低、适合大文件,但需要配合 XMLParserDelegate 实现回调逻辑。关键不是“怎么写协议”,而是理清生命周期、状态管理与数据组装的配合。
理解 XMLParser 的工作方式
XMLParser 不生成 DOM 树,而是在读取过程中按顺序触发代理方法:遇到开始标签调用 parser(_:didStartElement:namespaceURI:qualifiedName:attributes:),遇到文本内容调用 parser(_:foundCharacters:),遇到结束标签调用 parser(_:didEndElement:namespaceURI:qualifiedName:)。所有解析逻辑都靠你在这些回调里手动维护上下文状态。
实现 XMLParserDelegate 的核心要点
你需要一个符合 XMLParserDelegate 协议的类(通常是解析器的持有者),并在其中处理三类关键事件:
- 开始标签时记录当前路径和属性:比如进入
就标记“现在在 item 节点内”,同时缓存attributes字典(如id="123") - 文本内容需累积拼接:
foundCharacters可能被多次调用(尤其含换行或 CDATA),不能直接赋值,要用String.append()或可变字符串缓冲区 - 结束标签时完成对象组装:比如离开
就把当前收集的 title、link、pubDate 等字段塞进一个FeedItem实例,并添加到结果数组中
避免常见陷阱的操作建议
很多崩溃或数据错乱源于状态管理疏忽:
- 不要在
foundCharacters里直接处理空格 / 换行——先 trim,或只对非空白节点提取文本 - 嵌套结构(如
)需用 栈或层级计数跟踪深度,否则容易把子节点文本误塞到父对象里 - 解析中途出错(如 编码 不匹配、格式非法)会触发
parser(_:parseErrorOccurred:),务必实现它并检查parser.parserError,而不是忽略 - 解析完成后,
parserDidEndDocument是最终确认点,此时才应通知 UI 或返回结果
一个极简可用的结构示例
假设解析 RSS 的 列表:
定义模型:struct FeedItem {var title = ""; var link =""}
在 delegate 类中声明:private var currentElement = ""; private var currentItem = FeedItem(); private var items = [FeedItem]()
在 didStartElement 中判断:if elementName =="item"{currentItem = FeedItem() },再根据 elementName 切换 currentElement(如 “title”、”link”)
在 foundCharacters 中:let text = string.trimmingCharacters(in: .whitespacesAndNewlines); if !text.isEmpty {switch currentElement { case"title": currentItem.title += text ……} }
在 didEndElement 中:if elementName =="item" {items.append(currentItem) }