Last active
April 30, 2018 02:38
-
-
Save norsez/76f3a830b9f7f4da5be3b0439cf63520 to your computer and use it in GitHub Desktop.
Medium.com RSS XML parser written in Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Created by norsez on 30/4/18. | |
import Foundation | |
struct RssItem { | |
var title = "unknown" | |
var categories: [String] = [] | |
var pubDate = "unknown" | |
var link = "http://" | |
var content = "<h1>Hello World</h1>" | |
var creator = "n.a." | |
} | |
struct RssFeed { | |
var title = "unknown" | |
var description = "n.a." | |
var link = "http://" | |
var icon = "http://" | |
var items: [RssItem] = [] | |
} | |
class DevMediumRSSXMLParser: NSObject, XMLParserDelegate { | |
var stringBuf = "" | |
var cdataBuf = "" | |
var feed = RssFeed() | |
var currentPathStack = [String]() | |
var currentItem: RssItem? | |
//MARK: Tags | |
struct Tag { | |
static let RSS = "rss" | |
static let Channel = "channel" | |
static let Title = "title" | |
static let Description = "description" | |
static let Link = "link" | |
static let Image = "image" | |
static let Url = "url" | |
static let ContentEncoded = "content:encoded" | |
static let AtomUpdated = "atom:updated" | |
static let Category = "category" | |
static let DcCreator = "dc:creator" | |
static let Item = "item" | |
static let path_feed_title = [Tag.RSS, Tag.Channel, Tag.Title] | |
static let path_feed_desc = [Tag.RSS, Tag.Channel, Tag.Description] | |
static let path_feed_link = [Tag.RSS, Tag.Channel, Tag.Link] | |
static let path_feed_icon = [Tag.RSS, Tag.Channel, Image, Tag.Url] | |
static let path_feed_item = [Tag.RSS, Tag.Channel, Tag.Item] | |
static let path_feed_item_title = [Tag.RSS, Tag.Channel, Tag.Item, Tag.Title] | |
static let path_feed_item_link = [Tag.RSS, Tag.Channel, Tag.Item, Tag.Link] | |
static let path_feed_item_category = [Tag.RSS, Tag.Channel, Tag.Item, Tag.Category] | |
static let path_feed_item_creator = [Tag.RSS, Tag.Channel, Tag.Item, Tag.DcCreator] | |
static let path_feed_item_createdDate = [Tag.RSS, Tag.Channel, Tag.Item, Tag.AtomUpdated] | |
static let path_feed_item_content = [Tag.RSS, Tag.Channel, Tag.Item, Tag.ContentEncoded] | |
//Convenience method for checking the equality of two path stacks | |
static func pathEquals(path1: [String], path2: [String]) -> Bool { | |
if path1.count != path2.count { | |
return false | |
} | |
for index in stride(from: path1.count-1, to: 0, by: -1) { | |
if path1[index] != path2[index] { | |
return false | |
} | |
} | |
return true | |
} | |
} | |
//MARK: parser method | |
func processParsing() { | |
if Tag.pathEquals(path1: Tag.path_feed_title, path2: self.currentPathStack) { | |
self.feed.title = self.cdataBuf | |
}else if Tag.pathEquals(path1: Tag.path_feed_desc, path2: self.currentPathStack) { | |
self.feed.description = self.cdataBuf | |
}else if Tag.pathEquals(path1: Tag.path_feed_link, path2: self.currentPathStack) { | |
self.feed.link = self.stringBuf | |
}else if Tag.pathEquals(path1: Tag.path_feed_icon, path2: self.currentPathStack) { | |
self.feed.icon = self.stringBuf | |
}else if Tag.pathEquals(path1: Tag.path_feed_title, path2: self.currentPathStack) { | |
self.feed.title = self.cdataBuf | |
}else if Tag.pathEquals(path1: Tag.path_feed_item_title, path2: self.currentPathStack) { | |
self.currentItem?.title = self.cdataBuf | |
}else if Tag.pathEquals(path1: Tag.path_feed_item_link, path2: self.currentPathStack) { | |
self.currentItem?.link = self.stringBuf | |
}else if Tag.pathEquals(path1: Tag.path_feed_item_category, path2: self.currentPathStack) { | |
self.currentItem?.categories.append(self.cdataBuf) | |
}else if Tag.pathEquals(path1: Tag.path_feed_item_createdDate, path2: self.currentPathStack) { | |
self.currentItem?.pubDate = self.stringBuf | |
}else if Tag.pathEquals(path1: Tag.path_feed_item_creator, path2: self.currentPathStack) { | |
self.currentItem?.creator = self.cdataBuf | |
}else if Tag.pathEquals(path1: Tag.path_feed_item_content, path2: self.currentPathStack) { | |
self.currentItem?.content = self.cdataBuf | |
} | |
} | |
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { | |
self.currentPathStack.append(elementName) | |
if elementName == Tag.Item { | |
self.currentItem = RssItem() | |
} | |
} | |
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { | |
processParsing() | |
//buffer clean up | |
if let lastElem = self.currentPathStack.popLast() { | |
if lastElem != elementName { | |
Logger.log(withText: "warning: unmatched element stack popped \(lastElem) Vs. actual: \(elementName)") | |
} | |
} | |
self.stringBuf = "" | |
self.cdataBuf = "" | |
if elementName == Tag.Item { | |
if let item = self.currentItem { | |
self.feed.items.append(item) | |
self.currentItem = nil | |
} | |
} | |
} | |
func parser(_ parser: XMLParser, foundCDATA CDATABlock: Data) { | |
if let cdblock = NSString(data: CDATABlock, encoding: String.Encoding.utf8.rawValue) as String?{ | |
self.cdataBuf.append(contentsOf: cdblock) | |
} | |
} | |
func parser(_ parser: XMLParser, foundCharacters string: String) { | |
self.stringBuf.append(contentsOf: string) | |
} | |
func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) { | |
Logger.log(withErrorText: parseError.localizedDescription) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment