2017-06-21 07:00:19 +02:00
|
|
|
|
//
|
|
|
|
|
// FeedParser.swift
|
|
|
|
|
// RSParser
|
|
|
|
|
//
|
|
|
|
|
// Created by Brent Simmons on 6/20/17.
|
|
|
|
|
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
|
|
2017-06-27 04:37:30 +02:00
|
|
|
|
// FeedParser handles RSS, Atom, JSON Feed, and RSS-in-JSON.
|
|
|
|
|
// You don’t need to know the type of feed.
|
2017-06-25 19:23:30 +02:00
|
|
|
|
|
2017-07-02 02:22:19 +02:00
|
|
|
|
public typealias FeedParserCallback = (_ parsedFeed: ParsedFeed?, _ error: Error?) -> Void
|
|
|
|
|
|
2017-06-21 07:00:19 +02:00
|
|
|
|
public struct FeedParser {
|
|
|
|
|
|
2017-07-02 02:22:19 +02:00
|
|
|
|
public static func canParse(_ parserData: ParserData) -> Bool {
|
|
|
|
|
|
|
|
|
|
let type = feedType(parserData)
|
2017-12-01 22:19:30 +01:00
|
|
|
|
|
2017-07-02 02:22:19 +02:00
|
|
|
|
switch type {
|
|
|
|
|
case .jsonFeed, .rssInJSON, .rss, .atom:
|
|
|
|
|
return true
|
|
|
|
|
default:
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-01 22:19:30 +01:00
|
|
|
|
public static func mightBeAbleToParseBasedOnPartialData(_ parserData: ParserData) -> Bool {
|
|
|
|
|
|
|
|
|
|
let type = feedType(parserData, isPartialData: true)
|
|
|
|
|
|
|
|
|
|
switch type {
|
|
|
|
|
case .jsonFeed, .rssInJSON, .rss, .atom, .unknown:
|
|
|
|
|
return true
|
|
|
|
|
default:
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-27 04:37:30 +02:00
|
|
|
|
public static func parse(_ parserData: ParserData) throws -> ParsedFeed? {
|
2017-06-25 19:23:30 +02:00
|
|
|
|
|
2017-06-27 04:37:30 +02:00
|
|
|
|
// This is generally fast enough to call on the main thread —
|
2017-06-26 01:32:07 +02:00
|
|
|
|
// but it’s probably a good idea to use a background queue if
|
|
|
|
|
// you might be doing a lot of parsing. (Such as in a feed reader.)
|
|
|
|
|
|
2017-06-25 23:06:01 +02:00
|
|
|
|
do {
|
|
|
|
|
let type = feedType(parserData)
|
2017-06-25 19:23:30 +02:00
|
|
|
|
|
2017-06-25 23:06:01 +02:00
|
|
|
|
switch type {
|
2017-06-25 19:23:30 +02:00
|
|
|
|
|
2017-06-25 23:06:01 +02:00
|
|
|
|
case .jsonFeed:
|
|
|
|
|
return try JSONFeedParser.parse(parserData)
|
2017-06-25 19:23:30 +02:00
|
|
|
|
|
2017-06-25 23:06:01 +02:00
|
|
|
|
case .rssInJSON:
|
|
|
|
|
return try RSSInJSONParser.parse(parserData)
|
2017-06-25 19:23:30 +02:00
|
|
|
|
|
2017-06-25 23:06:01 +02:00
|
|
|
|
case .rss:
|
|
|
|
|
return RSSParser.parse(parserData)
|
2017-06-21 07:00:19 +02:00
|
|
|
|
|
2017-06-25 23:06:01 +02:00
|
|
|
|
case .atom:
|
2017-06-26 01:32:07 +02:00
|
|
|
|
return AtomParser.parse(parserData)
|
2017-06-21 07:00:19 +02:00
|
|
|
|
|
2017-06-25 23:06:01 +02:00
|
|
|
|
case .unknown, .notAFeed:
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2017-06-25 19:23:30 +02:00
|
|
|
|
}
|
2017-06-25 23:06:01 +02:00
|
|
|
|
catch { throw error }
|
2017-06-21 07:00:19 +02:00
|
|
|
|
}
|
2017-07-02 02:22:19 +02:00
|
|
|
|
|
|
|
|
|
public static func parse(_ parserData: ParserData, _ callback: @escaping FeedParserCallback) {
|
|
|
|
|
|
|
|
|
|
DispatchQueue.global(qos: .background).async {
|
|
|
|
|
do {
|
|
|
|
|
let parsedFeed = try parse(parserData)
|
|
|
|
|
DispatchQueue.main.async {
|
|
|
|
|
callback(parsedFeed, nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch {
|
|
|
|
|
DispatchQueue.main.async {
|
|
|
|
|
callback(nil, error)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-21 07:00:19 +02:00
|
|
|
|
}
|