From e7a82376b0fa32dae2b0b706c46176101a4b725a Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Mon, 26 Aug 2024 20:03:58 -0700 Subject: [PATCH] Finish first draft of OPML parser. --- .../Parser/Sources/Parser/OPML/OPMLItem.swift | 2 +- .../Sources/Parser/OPML/OPMLParser.swift | 38 +++++++++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/Modules/Parser/Sources/Parser/OPML/OPMLItem.swift b/Modules/Parser/Sources/Parser/OPML/OPMLItem.swift index 9a1e0b23e..a00a4ce35 100644 --- a/Modules/Parser/Sources/Parser/OPML/OPMLItem.swift +++ b/Modules/Parser/Sources/Parser/OPML/OPMLItem.swift @@ -31,7 +31,7 @@ public class OPMLItem { } - func addItem(_ item: OPMLItem) { + func add(_ item: OPMLItem) { if items == nil { items = [OPMLItem]() diff --git a/Modules/Parser/Sources/Parser/OPML/OPMLParser.swift b/Modules/Parser/Sources/Parser/OPML/OPMLParser.swift index 59b972158..59ae75b7b 100644 --- a/Modules/Parser/Sources/Parser/OPML/OPMLParser.swift +++ b/Modules/Parser/Sources/Parser/OPML/OPMLParser.swift @@ -19,6 +19,11 @@ public final class OPMLParser { itemStack.last } + struct XMLKey { + static let title = "title".utf8CString + static let outline = "outline".utf8CString + } + /// Returns nil if data can’t be parsed (if it’s not OPML). public static func document(with parserData: ParserData) -> OPMLDocument? { @@ -53,16 +58,16 @@ private extension OPMLParser { data.containsASCIIString(" 0) guard itemStack.count > 0 else { assertionFailure("itemStack.count must be > 0") + return } itemStack.dropLast() @@ -71,15 +76,40 @@ private extension OPMLParser { extension OPMLParser: SAXParserDelegate { - func saxParser(_: SAXParser, xmlStartElement: XMLPointer, prefix: XMLPointer?, uri: XMLPointer?, namespaceCount: Int, namespaces: UnsafeMutablePointer?, attributeCount: Int, attributesDefaultedCount: Int, attributes: UnsafeMutablePointer?) { + func saxParser(_ saxParser: SAXParser, xmlStartElement localName: XMLPointer, prefix: XMLPointer?, uri: XMLPointer?, namespaceCount: Int, namespaces: UnsafeMutablePointer?, attributeCount: Int, attributesDefaultedCount: Int, attributes: UnsafeMutablePointer?) { + if SAXEqualStrings(localName, XMLKey.title) { + saxParser.beginStoringCharacters() + return + } + + if !SAXEqualStrings(localName, XMLKey.outline) { + return + } + + let attributesDictionary = saxParser.attributesDictionary(attributes, attributeCount: attributeCount) + let item = OPMLItem(attributes: attributesDictionary) + + currentItem?.add(item) + push(item) } - func saxParser(_: SAXParser, xmlEndElement: XMLPointer, prefix: XMLPointer?, uri: XMLPointer?) { + func saxParser(_ saxParser: SAXParser, xmlEndElement localName: XMLPointer, prefix: XMLPointer?, uri: XMLPointer?) { + if SAXEqualStrings(localname, XMLKey.title) { + if let item = currentItem as? OPMLDocument { + item.title = saxParser.currentStringWithTrimmedWhitespace + } + return + } + + if SAXEqualStrings(localName, XMLKey.outline) { + popItem() + } } func saxParser(_: SAXParser, xmlCharactersFound: XMLPointer, count: Int) { + // Nothing to do, but method is required. } }