在 Swift (iOS/macOS) 中处理 XML
XML(可扩展标记语言)仍然是数据交换、配置文件以及存储结构化信息的热门格式。在 Apple 生态系统(iOS、macOS、watchOS、tvOS)中,Foundation 内置工具提供了两种主要的 XML 处理方法:使用 XMLParser 的流式解析(类似 SAX)以及通过 XMLDocument(仅在 macOS 上可用)实现的树状 DOM 方法。在本文中,我们将详细探讨这两种方法,提供实际示例,并介绍典型的使用场景。
1. 使用 XMLParser 进行流式解析
XMLParser 是一个事件驱动的解析器,包含在 Foundation 中。它不会将整个 XML 加载到内存中,而是顺序解析文档,在发现元素、属性、文本等内容时调用委托方法。这是处理大文件或流式数据的理想解决方案。
解析 RSS 订阅源的基本示例
import Foundation
// 1. 创建委托类class RSSParserDelegate: NSObject, XMLParserDelegate { var currentElement = "" var currentTitle = "" var currentLink = "" var items: [(title: String, link: String)] = [] // 在标签打开时调用 func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { currentElement = elementName if elementName == "item" { currentTitle = "" currentLink = "" } } // 在发现文本内容时调用 func parser(_ parser: XMLParser, foundCharacters string: String) { switch currentElement { case "title": currentTitle += string case "link": currentLink += string default: break } } // 在标签关闭时调用 func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { if elementName == "item" { items.append((title: currentTitle.trimmingCharacters(in: .whitespacesAndNewlines), link: currentLink.trimmingCharacters(in: .whitespacesAndNewlines))) } }}
// 2. 使用let xmlString = """<rss> <channel> <item> <title>Swift 5.9 Features</title> <link>https://example.com/swift-5-9</link> </item> </channel></rss>"""
guard let data = xmlString.data(using: .utf8) else { fatalError() }let parser = XMLParser(data: data)let delegate = RSSParserDelegate()parser.delegate = delegate
if parser.parse() { for item in delegate.items { print("Title: \\(item.title), Link: \\(item.link)") }} else { print("Parse error: \\(parser.parserError?.localizedDescription ?? "unknown")")}2. 树状模型:XMLDocument(仅限 macOS)
在 macOS 上(以及使用 Swift Package Manager 且框架 Foundation 处于 macOS 模式的应用程序中),可以使用 XMLDocument 类,它继承自 XMLNode。它允许将整个 XML 加载到内存中,并像操作树一样进行操作。这对于需要随机访问节点的小型文档非常方便。
创建和修改 XML 文档
import Foundation
// 创建根元素let rootElement = XMLElement(name: "catalog")let document = XMLDocument(rootElement: rootElement)
// 添加带属性的子元素let book = XMLElement(name: "book")book.addAttribute(XMLNode.attribute(withName: "id", stringValue: "101") as! XMLNode)let title = XMLElement(name: "title", stringValue: "Swift Programming")let author = XMLElement(name: "author", stringValu