Работа с XML в Swift (iOS/macOS): от парсинга до создания
XML (eXtensible Markup Language) продолжает использоваться в legacy-системах, веб-сервисах (SOAP, RSS) и конфигурационных файлах. В Swift для iOS/macOS нет встроенной библиотеки с синтаксическим сахаром, но есть мощный XMLParser (SAX-парсер), а также популярная сторонняя библиотека AEXML (DOM-подход). В этой статье разберём оба подхода.
1. Встроенный XMLParser (SAX-подход)
XMLParser — это событийно-ориентированный (SAX) парсер из Foundation. Он не загружает весь документ в память, а вызывает методы делегата при встрече элементов. Идеален для больших файлов.
Пример: парсинг RSS-ленты
import Foundation
class RSSParser: NSObject, XMLParserDelegate {
private var currentElement = ""
private var currentTitle = ""
private var items: [String] = []
func parse(data: Data) -> [String] {
let parser = XMLParser(data: data)
parser.delegate = self
parser.parse()
return items
}
// MARK: - XMLParserDelegate
func parser(_ parser: XMLParser, didStartElement elementName: String,
namespaceURI: String?, qualifiedName qName: String?,
attributes attributeDict: [String : String] = [:]) {
currentElement = elementName
if elementName == "item" {
currentTitle = ""
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
if currentElement == "title" {
currentTitle += string
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String,
namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "title" && !currentTitle.isEmpty {
items.append(currentTitle.trimmingCharacters(in: .whitespacesAndNewlines))
}
}
}
// Использование
let xmlString = """
<rss>
<channel>
<item><title>Swift 6.0</title></item>
<item><title>Новые фичи Xcode</title></item>
</channel>
</rss>
"""
if let data = xmlString.data(using: .utf8) {
let parser = RSSParser()
let titles = parser.parse(data: data)
print(titles) // ["Swift 6.0", "Новые фичи Xcode"]
}
Важно: foundCharacters может вызываться несколько раз для одного текстового узла (особенно с кириллицей). Всегда накапливайте строку, а не присваивайте.
2. AEXML — удобная DOM-библиотека
AEXML — лёгкая библиотека для работы с XML в стиле DOM. Позволяет читать и создавать XML без ручного управления событиями. Устанавливается через Swift Package Manager или CocoaPods.
Установка через Swift Package Manager
Добавьте в Package.swift или через Xcode: File → Add Packages → введите URL: https://github.com/tadija/AEXML.git
Пример: чтение XML
import AEXML
func parseWithAEXML(xmlString: String) -> [String: String]? {
do {
let xmlDoc = try AEXMLDocument(xml: xmlString)
let root = xmlDoc.root
// Получаем значение элемента
let name = root["user"]["name"].value ?? ""
let age = root["user"]["age"].value ?? ""
// Доступ по атрибуту
let id = root["user"].attributes["id"] ?? ""
return ["id": id, "name": name, "age": age]
} catch {
print("Ошибка парсинга: \(error)")
return nil
}
}
// Пример XML
let xmlData = """
<root>
<user id="42">
<name>Иван Петров</name>
<age>30</age>
</user>
</root>
"""
if let result = parseWithAEXML(xmlString: xmlData) {
print(result) // ["id": "42", "name": "Иван Петров", "age": "30"]
}
Пример: создание XML
import AEXML
func createXML() -> String {
let root = AEXMLElement(name: "catalog")
root.addAttribute(name: "version", value: "1.0")
let book = AEXMLElement(name: "book")
book.addChild(name: "title", value: "Swift для начинающих")
book.addChild(name: "author", value: "Анна Смирнова")
book.addChild(name: "price", value: "29.99")
root.addChild(book)
let document = AEXMLDocument(root: root)
return document.xml
}
let xmlOutput = createXML()
print(xmlOutput)
// Вывод:
// <catalog version="1