Working with XML in Swift (iOS/macOS)
XML (Extensible Markup Language) remains a popular format for data exchange, configuration files, and storing structured information. In the Apple ecosystem (iOS, macOS, watchOS, tvOS), the built-in Foundation framework provides two main approaches to working with XML: streaming parsing (SAX-like) using XMLParser and tree-based DOM approach via XMLDocument (available on macOS). In this article, we will thoroughly examine both methods, provide practical examples, and cover typical use cases.
1. Streaming Parsing with XMLParser
XMLParser is an event-driven parser included in Foundation. It does not load the entire XML into memory but sequentially parses the document, calling delegate methods when it encounters elements, attributes, text, etc. This is an ideal solution for large files or streaming data.
Basic example of parsing an RSS feed
import Foundation
// 1. Create a delegate classclass RSSParserDelegate: NSObject, XMLParserDelegate { var currentElement = "" var currentTitle = "" var currentLink = "" var items: [(title: String, link: String)] = [] // Called when a start tag is encountered func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { currentElement = elementName if elementName == "item" { currentTitle = "" currentLink = "" } } // Called when text content is found func parser(_ parser: XMLParser, foundCharacters string: String) { switch currentElement { case "title": currentTitle += string case "link": currentLink += string default: break } } // Called when an end tag is encountered 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. Usagelet 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. Tree Model: XMLDocument (macOS only)
On macOS (and in applications using Swift Package Manager with the Foundation framework in macOS mode), the XMLDocument class, inheriting from XMLNode, is available. It allows loading the entire XML into memory and manipulating it as a tree. This is convenient for small documents when random access to nodes is needed.
Creating and modifying an XML document
import Foundation
// Create the root elementlet rootElement = XMLElement(name: "catalog")let document = XMLDocument(rootElement: rootElement)
// Add a child element with an attributelet 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 Also in library
OpenAPI / Swagger for Java: Complete Guide with Examples
Polars for Rust: Complete Guide with Examples
Log4j 2 / SLF4J for Java: Complete Guide with Examples
Data Validation in Rust: Overview of Libraries and Frameworks