Работа с XML в Swift: парсинг, создание и обработка данных (iOS/macOS)

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Работа с 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                    

Рекомендаций