العمل مع XML في Swift (iOS/macOS)
XML (لغة الترميز القابلة للتوسع) لا يزال تنسيقًا مطلوبًا لتبادل البيانات وملفات التكوين وتخزين المعلومات المنظمة. في نظام Apple البيئي (iOS، macOS، watchOS، tvOS)، توفر أدوات Foundation المدمجة طريقتين رئيسيتين للعمل مع XML: التحليل التدفقي (شبيه بـ SAX) باستخدام XMLParser ونهج DOM الشجري عبر XMLDocument (متاح على macOS). في هذه المقالة، سنشرح كلا الطريقتين بالتفصيل، ونقدم أمثلة عملية، ونناقش سيناريوهات الاستخدام النموذجية.
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