Finish first draft of OPML parser.

This commit is contained in:
Brent Simmons 2024-08-26 20:03:58 -07:00
parent e29a232b77
commit e7a82376b0
2 changed files with 35 additions and 5 deletions

View File

@ -31,7 +31,7 @@ public class OPMLItem {
} }
func addItem(_ item: OPMLItem) { func add(_ item: OPMLItem) {
if items == nil { if items == nil {
items = [OPMLItem]() items = [OPMLItem]()

View File

@ -19,6 +19,11 @@ public final class OPMLParser {
itemStack.last itemStack.last
} }
struct XMLKey {
static let title = "title".utf8CString
static let outline = "outline".utf8CString
}
/// Returns nil if data cant be parsed (if its not OPML). /// Returns nil if data cant be parsed (if its not OPML).
public static func document(with parserData: ParserData) -> OPMLDocument? { public static func document(with parserData: ParserData) -> OPMLDocument? {
@ -53,16 +58,16 @@ private extension OPMLParser {
data.containsASCIIString("<opml") data.containsASCIIString("<opml")
} }
func pushItem(_ item: OPMLItem) { func push(_ item: OPMLItem) {
itemStack.append(item) itemStack.append(item)
} }
func popItem() { func popItem() {
assert(itemStack.count > 0)
guard itemStack.count > 0 else { guard itemStack.count > 0 else {
assertionFailure("itemStack.count must be > 0") assertionFailure("itemStack.count must be > 0")
return
} }
itemStack.dropLast() itemStack.dropLast()
@ -71,15 +76,40 @@ private extension OPMLParser {
extension OPMLParser: SAXParserDelegate { extension OPMLParser: SAXParserDelegate {
func saxParser(_: SAXParser, xmlStartElement: XMLPointer, prefix: XMLPointer?, uri: XMLPointer?, namespaceCount: Int, namespaces: UnsafeMutablePointer<XMLPointer?>?, attributeCount: Int, attributesDefaultedCount: Int, attributes: UnsafeMutablePointer<XMLPointer?>?) { func saxParser(_ saxParser: SAXParser, xmlStartElement localName: XMLPointer, prefix: XMLPointer?, uri: XMLPointer?, namespaceCount: Int, namespaces: UnsafeMutablePointer<XMLPointer?>?, attributeCount: Int, attributesDefaultedCount: Int, attributes: UnsafeMutablePointer<XMLPointer?>?) {
if SAXEqualStrings(localName, XMLKey.title) {
saxParser.beginStoringCharacters()
return
} }
func saxParser(_: SAXParser, xmlEndElement: XMLPointer, prefix: XMLPointer?, uri: XMLPointer?) { 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: 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) { func saxParser(_: SAXParser, xmlCharactersFound: XMLPointer, count: Int) {
// Nothing to do, but method is required.
} }
} }