Make progress on getting RSParser.framework to build.

This commit is contained in:
Brent Simmons 2017-06-25 14:06:01 -07:00
parent 6f0e4a9da6
commit 1ad4474b29
37 changed files with 307 additions and 294 deletions

View File

@ -16,7 +16,7 @@ public struct FeedParser {
static let minNumberOfBytesRequired = 128 static let minNumberOfBytesRequired = 128
public static func feedType(parserData: ParserData) -> FeedType { public static func feedType(_ parserData: ParserData) -> FeedType {
// Can call with partial data while still downloading, for instance. // Can call with partial data while still downloading, for instance.
// If theres not enough data, return .unknown. Ask again when theres more data. // If theres not enough data, return .unknown. Ask again when theres more data.
@ -26,38 +26,40 @@ public struct FeedParser {
return .unknown return .unknown
} }
if parserData.data.isProbablyJSONFeed() { let nsdata = parserData.data as NSData
if nsdata.isProbablyJSONFeed() {
return .jsonFeed return .jsonFeed
} }
if parserData.data.isProbablyRSSInJSON() { if nsdata.isProbablyRSSInJSON() {
return .rssInJSON return .rssInJSON
} }
if parserData.data.isProbablyHTML() { if nsdata.isProbablyHTML() {
return .notAFeed return .notAFeed
} }
if parserData.data.isProbablyRSS() { if nsdata.isProbablyRSS() {
return .rss return .rss
} }
if parserData.data.isProbablyAtom() { if nsdata.isProbablyAtom() {
return .atom return .atom
} }
return .notAFeed return .notAFeed
} }
public static func parseFeed(parserData: ParserData) -> ParsedFeed? { public static func parseFeed(_ parserData: ParserData) throws -> ParsedFeed? {
do {
let type = feedType(parserData) let type = feedType(parserData)
switch type { switch type {
case .jsonFeed: case .jsonFeed:
return JSONFeedParser.parse(parserData) return try JSONFeedParser.parse(parserData)
case .rssInJSON: case .rssInJSON:
return RSSInJSONFeedParser.parse(parserData) return try RSSInJSONParser.parse(parserData)
case .rss: case .rss:
return RSSParser.parse(parserData) return RSSParser.parse(parserData)
@ -69,4 +71,6 @@ public struct FeedParser {
return nil return nil
} }
} }
catch { throw error }
}
} }

View File

@ -17,6 +17,7 @@ public struct FeedParserError: Error {
case jsonFeedVersionNotFound case jsonFeedVersionNotFound
case jsonFeedItemsNotFound case jsonFeedItemsNotFound
case jsonFeedTitleNotFound case jsonFeedTitleNotFound
case invalidJSON
} }
public let errorType: FeedParserErrorType public let errorType: FeedParserErrorType

View File

@ -12,10 +12,12 @@ import Foundation
public struct JSONFeedParser { public struct JSONFeedParser {
public static func parse(parserData: ParserData) throws -> ParsedFeed? { public static func parse(_ parserData: ParserData) throws -> ParsedFeed? {
do { do {
let parsedObject = try JSONSerialization.jsonObject(with: parserData.data) guard let parsedObject = try JSONSerialization.jsonObject(with: parserData.data) as? JSONDictionary else {
throw FeedParserError(.invalidJSON)
}
guard let version = parsedObject["version"] as? String, version.hasPrefix("https://jsonfeed.org/version/") else { guard let version = parsedObject["version"] as? String, version.hasPrefix("https://jsonfeed.org/version/") else {
throw FeedParserError(.jsonFeedVersionNotFound) throw FeedParserError(.jsonFeedVersionNotFound)
@ -27,13 +29,13 @@ public struct JSONFeedParser {
throw FeedParserError(.jsonFeedTitleNotFound) throw FeedParserError(.jsonFeedTitleNotFound)
} }
let authors = parseAuthors(parsedObject)
let homePageURL = parsedObject["home_page_url"] as? String let homePageURL = parsedObject["home_page_url"] as? String
let feedURL = parsedObject["feed_url"] ?? parserData.url let feedURL = parsedObject["feed_url"] as? String ?? parserData.url
let feedDescription = parsedObject["description"] as? String let feedDescription = parsedObject["description"] as? String
let nextURL = parsedObject["next_url"] as? String let nextURL = parsedObject["next_url"] as? String
let iconURL = parsedObject["icon_url"] as? String let iconURL = parsedObject["icon_url"] as? String
let faviconURL = parsedObject["favicon_url"] as? String let faviconURL = parsedObject["favicon_url"] as? String
let authors = parseAuthors(parsedObject)
let expired = parsedObject["expired"] as? Bool ?? false let expired = parsedObject["expired"] as? Bool ?? false
let hubs = parseHubs(parsedObject) let hubs = parseHubs(parsedObject)
@ -48,15 +50,15 @@ public struct JSONFeedParser {
private extension JSONFeedParser { private extension JSONFeedParser {
func parseAuthors(_ dictionary: JSONDictionary) -> [ParsedAuthor]? { static func parseAuthors(_ dictionary: JSONDictionary) -> [ParsedAuthor]? {
guard let authorDictionary = dictionary["author"] as? JSONDictionary else { guard let authorDictionary = dictionary["author"] as? JSONDictionary else {
return nil return nil
} }
let name = authorDictionary["name"] let name = authorDictionary["name"] as? String
let url = authorDictionary["url"] let url = authorDictionary["url"] as? String
let avatar = authorDictionary["avatar"] let avatar = authorDictionary["avatar"] as? String
if name == nil && url == nil && avatar == nil { if name == nil && url == nil && avatar == nil {
return nil return nil
} }
@ -64,14 +66,14 @@ private extension JSONFeedParser {
return [parsedAuthor] return [parsedAuthor]
} }
func parseHubs(_ dictionary: JSONDictionary) -> [ParsedHub]? { static func parseHubs(_ dictionary: JSONDictionary) -> [ParsedHub]? {
guard let hubsArray = dictionary["hubs"] as? JSONArray else { guard let hubsArray = dictionary["hubs"] as? JSONArray else {
return nil return nil
} }
let hubs = hubsArray.flatMap { (oneHubDictionary) -> ParsedHub? in let hubs = hubsArray.flatMap { (oneHubDictionary) -> ParsedHub? in
guard let oneHubURL = oneHubDictionary["url"], let oneHubType = oneHubDictionary["type"] else { guard let oneHubURL = oneHubDictionary["url"] as? String, let oneHubType = oneHubDictionary["type"] as? String else {
return nil return nil
} }
return ParsedHub(type: oneHubType, url: oneHubURL) return ParsedHub(type: oneHubType, url: oneHubURL)
@ -79,14 +81,14 @@ private extension JSONFeedParser {
return hubs.isEmpty ? nil : hubs return hubs.isEmpty ? nil : hubs
} }
func parseItems(_ itemsArray: JSONArray) -> [ParsedItem] { static func parseItems(_ itemsArray: JSONArray) -> [ParsedItem] {
return itemsArray.flatMap { (oneItemDictionary) -> ParsedItem? in return itemsArray.flatMap { (oneItemDictionary) -> ParsedItem? in
return parseItem(oneItemDictionary) return parseItem(oneItemDictionary)
} }
} }
func parseItem(_ itemDictionary: JSONDictionary) -> ParsedItem? { static func parseItem(_ itemDictionary: JSONDictionary) -> ParsedItem? {
guard let uniqueID = parseUniqueID(itemDictionary) else { guard let uniqueID = parseUniqueID(itemDictionary) else {
return nil return nil
@ -105,8 +107,8 @@ private extension JSONFeedParser {
let imageURL = itemDictionary["image"] as? String let imageURL = itemDictionary["image"] as? String
let bannerImageURL = itemDictionary["banner_image"] as? String let bannerImageURL = itemDictionary["banner_image"] as? String
let datePublished = parseDate(itemDictionary["date_published"]) let datePublished = parseDate(itemDictionary["date_published"] as? String)
let dateModified = parseDate(itemDictionary["date_modified"]) let dateModified = parseDate(itemDictionary["date_modified"] as? String)
let authors = parseAuthors(itemDictionary) let authors = parseAuthors(itemDictionary)
let tags = itemDictionary["tags"] as? [String] let tags = itemDictionary["tags"] as? [String]
@ -115,7 +117,7 @@ private extension JSONFeedParser {
return ParsedItem(uniqueID: uniqueID, url: url, externalURL: externalURL, title: title, contentHTML: contentHTML, contentText: contentText, summary: summary, imageURL: imageURL, bannerImageURL: bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: tags, attachments: attachments) return ParsedItem(uniqueID: uniqueID, url: url, externalURL: externalURL, title: title, contentHTML: contentHTML, contentText: contentText, summary: summary, imageURL: imageURL, bannerImageURL: bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: tags, attachments: attachments)
} }
func parseUniqueID(_ itemDictionary: JSONDictionary) -> String? { static func parseUniqueID(_ itemDictionary: JSONDictionary) -> String? {
if let uniqueID = itemDictionary["id"] as? String { if let uniqueID = itemDictionary["id"] as? String {
return uniqueID // Spec says it must be a string return uniqueID // Spec says it must be a string
@ -130,7 +132,7 @@ private extension JSONFeedParser {
return nil return nil
} }
func parseDate(_ dateString: String?) -> Date? { static func parseDate(_ dateString: String?) -> Date? {
guard let dateString = dateString, !dateString.isEmpty else { guard let dateString = dateString, !dateString.isEmpty else {
return nil return nil
@ -138,7 +140,7 @@ private extension JSONFeedParser {
return RSDateWithString(dateString) return RSDateWithString(dateString)
} }
func parseAttachments(_ itemDictionary: JSONDictionary) -> [ParsedAttachment]? { static func parseAttachments(_ itemDictionary: JSONDictionary) -> [ParsedAttachment]? {
guard let attachmentsArray = itemDictionary["attachments"] as? JSONArray else { guard let attachmentsArray = itemDictionary["attachments"] as? JSONArray else {
return nil return nil
@ -148,7 +150,7 @@ private extension JSONFeedParser {
} }
} }
func parseAttachment(_ attachmentObject: JSONDictionary) -> ParsedAttachment? { static func parseAttachment(_ attachmentObject: JSONDictionary) -> ParsedAttachment? {
guard let url = attachmentObject["url"] as? String else { guard let url = attachmentObject["url"] as? String else {
return nil return nil

View File

@ -13,10 +13,12 @@ import Foundation
public struct RSSInJSONParser { public struct RSSInJSONParser {
public static func parse(parserData: ParserData) throws -> ParsedFeed? { public static func parse(_ parserData: ParserData) throws -> ParsedFeed? {
do { do {
let parsedObject = try JSONSerialization.jsonObject(with: parserData.data) guard let parsedObject = try JSONSerialization.jsonObject(with: parserData.data) as? JSONDictionary else {
throw FeedParserError(.invalidJSON)
}
guard let channelObject = parsedObject["channel"] as? JSONDictionary else { guard let channelObject = parsedObject["channel"] as? JSONDictionary else {
throw FeedParserError(.rssChannelNotFound) throw FeedParserError(.rssChannelNotFound)
@ -32,7 +34,7 @@ public struct RSSInJSONParser {
itemsObject = channelObject["items"] as? JSONArray itemsObject = channelObject["items"] as? JSONArray
} }
if itemsObject == nil { if itemsObject == nil {
itemsObject == parsedObject["items"] as? JSONArray itemsObject = parsedObject["items"] as? JSONArray
} }
if itemsObject == nil { if itemsObject == nil {
throw FeedParserError(.rssItemsNotFound) throw FeedParserError(.rssItemsNotFound)
@ -43,7 +45,7 @@ public struct RSSInJSONParser {
let feedURL = parserData.url let feedURL = parserData.url
let feedDescription = channelObject["description"] as? String let feedDescription = channelObject["description"] as? String
let items = parseItems(itemsObject) let items = parseItems(itemsObject!)
return ParsedFeed(type: .rssInJSON, title: title, homePageURL: homePageURL, feedURL: feedURL, feedDescription: feedDescription, nextURL: nil, iconURL: nil, faviconURL: nil, authors: nil, expired: false, hubs: nil, items: items) return ParsedFeed(type: .rssInJSON, title: title, homePageURL: homePageURL, feedURL: feedURL, feedDescription: feedDescription, nextURL: nil, iconURL: nil, faviconURL: nil, authors: nil, expired: false, hubs: nil, items: items)
@ -56,19 +58,19 @@ private extension RSSInJSONParser {
static func parseItems(_ itemsObject: JSONArray) -> [ParsedItem] { static func parseItems(_ itemsObject: JSONArray) -> [ParsedItem] {
return itemsObject.flatMap{ (oneItemDictionary) -> ParsedItem in return itemsObject.flatMap{ (oneItemDictionary) -> ParsedItem? in
return parsedItemWithDictionary(oneItemDictionary) return parsedItemWithDictionary(oneItemDictionary)
} }
} }
static func parsedItemWithDictionary(_ JSONDictionary: itemDictionary) -> ParsedItem? { static func parsedItemWithDictionary(_ itemDictionary: JSONDictionary) -> ParsedItem? {
let externalURL = itemDictionary["link"] as? String let externalURL = itemDictionary["link"] as? String
let title = itemDictionary["title"] as? String let title = itemDictionary["title"] as? String
var contentHTML = itemDictionary["description"] as? String var contentHTML = itemDictionary["description"] as? String
var contentText = nil var contentText: String? = nil
if contentHTML != nil && !(contentHTML!.contains("<")) { if contentHTML != nil && !(contentHTML!.contains("<")) {
contentText = contentHTML contentText = contentHTML
contentHTML = nil contentHTML = nil
@ -77,9 +79,9 @@ private extension RSSInJSONParser {
return nil return nil
} }
var datePublished: Date = nil var datePublished: Date? = nil
if let datePublishedString = itemDictionary["pubDate"] as? String { if let datePublishedString = itemDictionary["pubDate"] as? String {
datePublished = RSDateWithString(datePublishedString as NSString) datePublished = RSDateWithString(datePublishedString)
} }
let authors = parseAuthors(itemDictionary) let authors = parseAuthors(itemDictionary)
@ -112,14 +114,14 @@ private extension RSSInJSONParser {
} }
if s.isEmpty { if s.isEmpty {
// Sheesh. Tough case. // Sheesh. Tough case.
if contentHTML != nil { if let _ = contentHTML {
s = contentHTML s = contentHTML!
} }
if contentText != nil { if let _ = contentText {
s = contentText s = contentText!
} }
} }
uniqueID = (s as NSString).rsxml_md5HashString() uniqueID = (s as NSString).rsparser_md5Hash()
} }
return ParsedItem(uniqueID: uniqueID, url: nil, externalURL: externalURL, title: title, contentHTML: contentHTML, contentText: contentText, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: datePublished, dateModified: nil, authors: authors, tags: tags, attachments: attachments) return ParsedItem(uniqueID: uniqueID, url: nil, externalURL: externalURL, title: title, contentHTML: contentHTML, contentText: contentText, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: datePublished, dateModified: nil, authors: authors, tags: tags, attachments: attachments)
@ -137,11 +139,14 @@ private extension RSSInJSONParser {
static func parseTags(_ itemDictionary: JSONDictionary) -> [String]? { static func parseTags(_ itemDictionary: JSONDictionary) -> [String]? {
if let categoryObject = itemDictionary["category"] as? JSONDictionary { if let categoryObject = itemDictionary["category"] as? JSONDictionary {
return categoryObject["#value"] if let oneTag = categoryObject["#value"] as? String {
return [oneTag]
}
return nil
} }
else if let categoryArray = itemDictionary["category"] as? JSONArray { else if let categoryArray = itemDictionary["category"] as? JSONArray {
return categoryArray.flatMap{ (categoryObject) in return categoryArray.flatMap{ (categoryObject) in
return categoryObject["#value"] return categoryObject["#value"] as? String
} }
} }
return nil return nil

View File

@ -1,6 +1,6 @@
// //
// RSAtomParser.h // RSAtomParser.h
// RSXML // RSParser
// //
// Created by Brent Simmons on 1/15/15. // Created by Brent Simmons on 1/15/15.
// Copyright (c) 2015 Ranchero Software LLC. All rights reserved. // Copyright (c) 2015 Ranchero Software LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
// //
// RSAtomParser.m // RSAtomParser.m
// RSXML // RSParser
// //
// Created by Brent Simmons on 1/15/15. // Created by Brent Simmons on 1/15/15.
// Copyright (c) 2015 Ranchero Software LLC. All rights reserved. // Copyright (c) 2015 Ranchero Software LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
// //
// RSFeedParser.h // RSFeedParser.h
// RSXML // RSParser
// //
// Created by Brent Simmons on 1/4/15. // Created by Brent Simmons on 1/4/15.
// Copyright (c) 2015 Ranchero Software LLC. All rights reserved. // Copyright (c) 2015 Ranchero Software LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
// //
// FeedParser.m // FeedParser.m
// RSXML // RSParser
// //
// Created by Brent Simmons on 1/4/15. // Created by Brent Simmons on 1/4/15.
// Copyright (c) 2015 Ranchero Software LLC. All rights reserved. // Copyright (c) 2015 Ranchero Software LLC. All rights reserved.

View File

@ -56,16 +56,16 @@
datePublishedTimeStampString = [NSString stringWithFormat:@"%.0f", self.datePublished.timeIntervalSince1970]; datePublishedTimeStampString = [NSString stringWithFormat:@"%.0f", self.datePublished.timeIntervalSince1970];
} }
if (!RSXMLStringIsEmpty(self.guid)) { if (!RSParserStringIsEmpty(self.guid)) {
[s appendString:self.guid]; [s appendString:self.guid];
} }
else if (!RSXMLStringIsEmpty(self.link) && self.datePublished != nil) { else if (!RSParserStringIsEmpty(self.link) && self.datePublished != nil) {
[s appendString:self.link]; [s appendString:self.link];
[s appendString:datePublishedTimeStampString]; [s appendString:datePublishedTimeStampString];
} }
else if (!RSXMLStringIsEmpty(self.title) && self.datePublished != nil) { else if (!RSParserStringIsEmpty(self.title) && self.datePublished != nil) {
[s appendString:self.title]; [s appendString:self.title];
[s appendString:datePublishedTimeStampString]; [s appendString:datePublishedTimeStampString];
} }
@ -74,19 +74,19 @@
[s appendString:datePublishedTimeStampString]; [s appendString:datePublishedTimeStampString];
} }
else if (!RSXMLStringIsEmpty(self.link)) { else if (!RSParserStringIsEmpty(self.link)) {
[s appendString:self.link]; [s appendString:self.link];
} }
else if (!RSXMLStringIsEmpty(self.title)) { else if (!RSParserStringIsEmpty(self.title)) {
[s appendString:self.title]; [s appendString:self.title];
} }
else if (!RSXMLStringIsEmpty(self.body)) { else if (!RSParserStringIsEmpty(self.body)) {
[s appendString:self.body]; [s appendString:self.body];
} }
NSAssert(!RSXMLStringIsEmpty(self.feedURL), nil); NSAssert(!RSParserStringIsEmpty(self.feedURL), nil);
[s appendString:self.feedURL]; [s appendString:self.feedURL];
return [s rsxml_md5HashString]; return [s rsxml_md5HashString];

View File

@ -1,6 +1,6 @@
// //
// RSRSSParser.h // RSRSSParser.h
// RSXML // RSParser
// //
// Created by Brent Simmons on 1/6/15. // Created by Brent Simmons on 1/6/15.
// Copyright (c) 2015 Ranchero Software LLC. All rights reserved. // Copyright (c) 2015 Ranchero Software LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
// //
// RSRSSParser.m // RSRSSParser.m
// RSXML // RSParser
// //
// Created by Brent Simmons on 1/6/15. // Created by Brent Simmons on 1/6/15.
// Copyright (c) 2015 Ranchero Software LLC. All rights reserved. // Copyright (c) 2015 Ranchero Software LLC. All rights reserved.
@ -256,7 +256,7 @@ static const NSInteger kTrueLength = 5;
self.currentArticle.guid = self.parser.currentStringWithTrimmedWhitespace; self.currentArticle.guid = self.parser.currentStringWithTrimmedWhitespace;
NSString *isPermaLinkValue = [self.currentAttributes rsxml_objectForCaseInsensitiveKey:@"ispermalink"]; NSString *isPermaLinkValue = [self.currentAttributes rsparser_objectForCaseInsensitiveKey:@"ispermalink"];
if (!isPermaLinkValue || ![isPermaLinkValue isEqualToString:@"false"]) { if (!isPermaLinkValue || ![isPermaLinkValue isEqualToString:@"false"]) {
self.currentArticle.permalink = [self urlString:self.currentArticle.guid]; self.currentArticle.permalink = [self urlString:self.currentArticle.guid];
} }

View File

@ -1,6 +1,6 @@
// //
// RSHTMLLinkParser.h // RSHTMLLinkParser.h
// RSXML // RSParser
// //
// Created by Brent Simmons on 8/7/16. // Created by Brent Simmons on 8/7/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved. // Copyright © 2016 Ranchero Software, LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
// //
// RSHTMLLinkParser.m // RSHTMLLinkParser.m
// RSXML // RSParser
// //
// Created by Brent Simmons on 8/7/16. // Created by Brent Simmons on 8/7/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved. // Copyright © 2016 Ranchero Software, LLC. All rights reserved.
@ -88,7 +88,7 @@ static NSString *kHrefKey = @"href";
- (NSString *)urlStringFromDictionary:(NSDictionary *)d { - (NSString *)urlStringFromDictionary:(NSDictionary *)d {
NSString *href = [d rsxml_objectForCaseInsensitiveKey:kHrefKey]; NSString *href = [d rsparser_objectForCaseInsensitiveKey:kHrefKey];
if (!href) { if (!href) {
return nil; return nil;
} }
@ -102,7 +102,7 @@ static NSString *kTitleKey = @"title";
- (NSString *)titleFromDictionary:(NSDictionary *)d { - (NSString *)titleFromDictionary:(NSDictionary *)d {
return [d rsxml_objectForCaseInsensitiveKey:kTitleKey]; return [d rsparser_objectForCaseInsensitiveKey:kTitleKey];
} }
@ -127,7 +127,7 @@ static const NSInteger kAnchorLength = 2;
[self.links addObject:link]; [self.links addObject:link];
NSDictionary *d = [SAXParser attributesDictionary:attributes]; NSDictionary *d = [SAXParser attributesDictionary:attributes];
if (!RSXMLIsEmpty(d)) { if (!RSParser_IsEmpty(d)) {
[self handleLinkAttributes:d]; [self handleLinkAttributes:d];
} }

View File

@ -1,6 +1,6 @@
// //
// RSHTMLMetadata.h // RSHTMLMetadata.h
// RSXML // RSParser
// //
// Created by Brent Simmons on 3/6/16. // Created by Brent Simmons on 3/6/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved. // Copyright © 2016 Ranchero Software, LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
// //
// RSHTMLMetadata.m // RSHTMLMetadata.m
// RSXML // RSParser
// //
// Created by Brent Simmons on 3/6/16. // Created by Brent Simmons on 3/6/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved. // Copyright © 2016 Ranchero Software, LLC. All rights reserved.
@ -114,12 +114,12 @@ static NSString *kTypeKey = @"type";
continue; continue;
} }
NSString *oneType = [oneDictionary rsxml_objectForCaseInsensitiveKey:kTypeKey]; NSString *oneType = [oneDictionary rsparser_objectForCaseInsensitiveKey:kTypeKey];
if (!typeIsFeedType(oneType)) { if (!typeIsFeedType(oneType)) {
continue; continue;
} }
if (RSXMLStringIsEmpty(urlStringFromDictionary(oneDictionary))) { if (RSParserStringIsEmpty(urlStringFromDictionary(oneDictionary))) {
continue; continue;
} }
@ -142,18 +142,18 @@ static NSString *kTypeKey = @"type";
static NSString *relValue(NSDictionary *d) { static NSString *relValue(NSDictionary *d) {
return [d rsxml_objectForCaseInsensitiveKey:kRelKey]; return [d rsparser_objectForCaseInsensitiveKey:kRelKey];
} }
static NSString *urlStringFromDictionary(NSDictionary *d) { static NSString *urlStringFromDictionary(NSDictionary *d) {
NSString *urlString = [d rsxml_objectForCaseInsensitiveKey:kHrefKey]; NSString *urlString = [d rsparser_objectForCaseInsensitiveKey:kHrefKey];
if (urlString) { if (urlString) {
return urlString; return urlString;
} }
return [d rsxml_objectForCaseInsensitiveKey:kSrcKey]; return [d rsparser_objectForCaseInsensitiveKey:kSrcKey];
} }
@ -172,7 +172,7 @@ static NSString *absoluteURLStringWithRelativeURLString(NSString *relativeURLStr
static NSString *absoluteURLStringWithDictionary(NSDictionary *d, NSString *baseURLString) { static NSString *absoluteURLStringWithDictionary(NSDictionary *d, NSString *baseURLString) {
NSString *urlString = urlStringFromDictionary(d); NSString *urlString = urlStringFromDictionary(d);
if (RSXMLStringIsEmpty(urlString)) { if (RSParserStringIsEmpty(urlString)) {
return nil; return nil;
} }
return absoluteURLStringWithRelativeURLString(urlString, baseURLString); return absoluteURLStringWithRelativeURLString(urlString, baseURLString);
@ -213,8 +213,8 @@ static BOOL typeIsFeedType(NSString *type) {
} }
_urlString = absoluteURLStringWithDictionary(d, baseURLString); _urlString = absoluteURLStringWithDictionary(d, baseURLString);
_sizes = [d rsxml_objectForCaseInsensitiveKey:kSizesKey]; _sizes = [d rsparser_objectForCaseInsensitiveKey:kSizesKey];
_rel = [d rsxml_objectForCaseInsensitiveKey:kRelKey]; _rel = [d rsparser_objectForCaseInsensitiveKey:kRelKey];
return self; return self;
} }
@ -234,8 +234,8 @@ static BOOL typeIsFeedType(NSString *type) {
} }
_urlString = absoluteURLStringWithDictionary(d, baseURLString); _urlString = absoluteURLStringWithDictionary(d, baseURLString);
_title = [d rsxml_objectForCaseInsensitiveKey:kTitleKey]; _title = [d rsparser_objectForCaseInsensitiveKey:kTitleKey];
_type = [d rsxml_objectForCaseInsensitiveKey:kTypeKey]; _type = [d rsparser_objectForCaseInsensitiveKey:kTypeKey];
return self; return self;
} }

View File

@ -1,6 +1,6 @@
// //
// RSHTMLMetadataParser.h // RSHTMLMetadataParser.h
// RSXML // RSParser
// //
// Created by Brent Simmons on 3/6/16. // Created by Brent Simmons on 3/6/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved. // Copyright © 2016 Ranchero Software, LLC. All rights reserved.

View File

@ -76,21 +76,21 @@ static NSString *kRelKey = @"rel";
- (NSString *)linkForDictionary:(NSDictionary *)d { - (NSString *)linkForDictionary:(NSDictionary *)d {
NSString *link = [d rsxml_objectForCaseInsensitiveKey:kHrefKey]; NSString *link = [d rsparser_objectForCaseInsensitiveKey:kHrefKey];
if (link) { if (link) {
return link; return link;
} }
return [d rsxml_objectForCaseInsensitiveKey:kSrcKey]; return [d rsparser_objectForCaseInsensitiveKey:kSrcKey];
} }
- (void)handleLinkAttributes:(NSDictionary *)d { - (void)handleLinkAttributes:(NSDictionary *)d {
if (RSXMLStringIsEmpty([d rsxml_objectForCaseInsensitiveKey:kRelKey])) { if (RSParserStringIsEmpty([d rsparser_objectForCaseInsensitiveKey:kRelKey])) {
return; return;
} }
if (RSXMLStringIsEmpty([self linkForDictionary:d])) { if (RSParserStringIsEmpty([self linkForDictionary:d])) {
return; return;
} }
@ -121,7 +121,7 @@ static const NSInteger kLinkLength = 5;
} }
NSDictionary *d = [SAXParser attributesDictionary:attributes]; NSDictionary *d = [SAXParser attributesDictionary:attributes];
if (!RSXMLIsEmpty(d)) { if (!RSParser_IsEmpty(d)) {
[self handleLinkAttributes:d]; [self handleLinkAttributes:d];
} }
} }

View File

@ -1,6 +1,6 @@
// //
// RSSAXHTMLParser.h // RSSAXHTMLParser.h
// RSXML // RSParser
// //
// Created by Brent Simmons on 3/6/16. // Created by Brent Simmons on 3/6/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved. // Copyright © 2016 Ranchero Software, LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
// //
// RSSAXHTMLParser.m // RSSAXHTMLParser.m
// RSXML // RSParser
// //
// Created by Brent Simmons on 3/6/16. // Created by Brent Simmons on 3/6/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved. // Copyright © 2016 Ranchero Software, LLC. All rights reserved.
@ -150,7 +150,7 @@ static xmlSAXHandler saxHandlerStruct;
- (NSString *)currentString { - (NSString *)currentString {
NSData *d = self.currentCharacters; NSData *d = self.currentCharacters;
if (RSXMLIsEmpty(d)) { if (RSParserObjectIsEmpty(d)) {
return nil; return nil;
} }

View File

@ -23,43 +23,43 @@ NSString *OPMLXMLURLKey = @"xmlUrl";
- (NSString *)opml_text { - (NSString *)opml_text {
return [self rsxml_objectForCaseInsensitiveKey:OPMLTextKey]; return [self rsparser_objectForCaseInsensitiveKey:OPMLTextKey];
} }
- (NSString *)opml_title { - (NSString *)opml_title {
return [self rsxml_objectForCaseInsensitiveKey:OPMLTitleKey]; return [self rsparser_objectForCaseInsensitiveKey:OPMLTitleKey];
} }
- (NSString *)opml_description { - (NSString *)opml_description {
return [self rsxml_objectForCaseInsensitiveKey:OPMLDescriptionKey]; return [self rsparser_objectForCaseInsensitiveKey:OPMLDescriptionKey];
} }
- (NSString *)opml_type { - (NSString *)opml_type {
return [self rsxml_objectForCaseInsensitiveKey:OPMLTypeKey]; return [self rsparser_objectForCaseInsensitiveKey:OPMLTypeKey];
} }
- (NSString *)opml_version { - (NSString *)opml_version {
return [self rsxml_objectForCaseInsensitiveKey:OPMLVersionKey]; return [self rsparser_objectForCaseInsensitiveKey:OPMLVersionKey];
} }
- (NSString *)opml_htmlUrl { - (NSString *)opml_htmlUrl {
return [self rsxml_objectForCaseInsensitiveKey:OPMLHMTLURLKey]; return [self rsparser_objectForCaseInsensitiveKey:OPMLHMTLURLKey];
} }
- (NSString *)opml_xmlUrl { - (NSString *)opml_xmlUrl {
return [self rsxml_objectForCaseInsensitiveKey:OPMLXMLURLKey]; return [self rsparser_objectForCaseInsensitiveKey:OPMLXMLURLKey];
} }

View File

@ -14,28 +14,28 @@
- (instancetype)initWithTitle:(NSString *)title feedDescription:(NSString *)feedDescription homePageURL:(NSString *)homePageURL feedURL:(NSString *)feedURL { - (instancetype)initWithTitle:(NSString *)title feedDescription:(NSString *)feedDescription homePageURL:(NSString *)homePageURL feedURL:(NSString *)feedURL {
NSParameterAssert(!RSXMLIsEmpty(feedURL)); NSParameterAssert(!RSParserStringIsEmpty(feedURL));
self = [super init]; self = [super init];
if (!self) { if (!self) {
return nil; return nil;
} }
if (RSXMLIsEmpty(title)) { if (RSParserStringIsEmpty(title)) {
_title = nil; _title = nil;
} }
else { else {
_title = title; _title = title;
} }
if (RSXMLIsEmpty(feedDescription)) { if (RSParserStringIsEmpty(feedDescription)) {
_feedDescription = nil; _feedDescription = nil;
} }
else { else {
_feedDescription = feedDescription; _feedDescription = feedDescription;
} }
if (RSXMLIsEmpty(homePageURL)) { if (RSParserStringIsEmpty(homePageURL)) {
_homePageURL = nil; _homePageURL = nil;
} }
else { else {

View File

@ -55,7 +55,7 @@
} }
NSString *feedURL = self.attributes.opml_xmlUrl; NSString *feedURL = self.attributes.opml_xmlUrl;
if (RSXMLIsEmpty(feedURL)) { if (RSParserObjectIsEmpty(feedURL)) {
return nil; return nil;
} }

View File

@ -9,7 +9,8 @@
@import Foundation; @import Foundation;
#import <RSParser/NSData+RSParser.h> #import <RSParser/NSData+RSParser.h>
#import <RSParser/RSParser.h> #import <RSParser/RSDateParser.h>
#import <RSParser/NSString+RSParser.h>
//#import <RSXML/RSSAXParser.h> //#import <RSXML/RSSAXParser.h>
//#import <RSXML/RSXMLData.h> //#import <RSXML/RSXMLData.h>

View File

@ -28,12 +28,12 @@
84469D0C1EFA307E004A6B28 /* RSHTMLMetadataParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D041EFA307E004A6B28 /* RSHTMLMetadataParser.m */; }; 84469D0C1EFA307E004A6B28 /* RSHTMLMetadataParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D041EFA307E004A6B28 /* RSHTMLMetadataParser.m */; };
84469D0D1EFA307E004A6B28 /* RSSAXHTMLParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D051EFA307E004A6B28 /* RSSAXHTMLParser.h */; }; 84469D0D1EFA307E004A6B28 /* RSSAXHTMLParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D051EFA307E004A6B28 /* RSSAXHTMLParser.h */; };
84469D0E1EFA307E004A6B28 /* RSSAXHTMLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D061EFA307E004A6B28 /* RSSAXHTMLParser.m */; }; 84469D0E1EFA307E004A6B28 /* RSSAXHTMLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D061EFA307E004A6B28 /* RSSAXHTMLParser.m */; };
84469D161EFA30A2004A6B28 /* NSString+RSXML.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D101EFA30A2004A6B28 /* NSString+RSXML.h */; }; 84469D161EFA30A2004A6B28 /* NSString+RSParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D101EFA30A2004A6B28 /* NSString+RSParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
84469D171EFA30A2004A6B28 /* NSString+RSXML.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D111EFA30A2004A6B28 /* NSString+RSXML.m */; }; 84469D171EFA30A2004A6B28 /* NSString+RSParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D111EFA30A2004A6B28 /* NSString+RSParser.m */; };
84469D181EFA30A2004A6B28 /* RSDateParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D121EFA30A2004A6B28 /* RSDateParser.h */; }; 84469D181EFA30A2004A6B28 /* RSDateParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D121EFA30A2004A6B28 /* RSDateParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
84469D191EFA30A2004A6B28 /* RSDateParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D131EFA30A2004A6B28 /* RSDateParser.m */; }; 84469D191EFA30A2004A6B28 /* RSDateParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D131EFA30A2004A6B28 /* RSDateParser.m */; };
84469D1A1EFA30A2004A6B28 /* RSXMLInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D141EFA30A2004A6B28 /* RSXMLInternal.h */; }; 84469D1A1EFA30A2004A6B28 /* RSParserInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D141EFA30A2004A6B28 /* RSParserInternal.h */; };
84469D1B1EFA30A2004A6B28 /* RSXMLInternal.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D151EFA30A2004A6B28 /* RSXMLInternal.m */; }; 84469D1B1EFA30A2004A6B28 /* RSParserInternal.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D151EFA30A2004A6B28 /* RSParserInternal.m */; };
84469D271EFA3134004A6B28 /* RSAtomParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D1D1EFA3134004A6B28 /* RSAtomParser.h */; }; 84469D271EFA3134004A6B28 /* RSAtomParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D1D1EFA3134004A6B28 /* RSAtomParser.h */; };
84469D281EFA3134004A6B28 /* RSAtomParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D1E1EFA3134004A6B28 /* RSAtomParser.m */; }; 84469D281EFA3134004A6B28 /* RSAtomParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D1E1EFA3134004A6B28 /* RSAtomParser.m */; };
84469D291EFA3134004A6B28 /* RSFeedParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D1F1EFA3134004A6B28 /* RSFeedParser.h */; }; 84469D291EFA3134004A6B28 /* RSFeedParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D1F1EFA3134004A6B28 /* RSFeedParser.h */; };
@ -45,7 +45,7 @@
84469D2F1EFA3134004A6B28 /* RSRSSParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D251EFA3134004A6B28 /* RSRSSParser.h */; }; 84469D2F1EFA3134004A6B28 /* RSRSSParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D251EFA3134004A6B28 /* RSRSSParser.h */; };
84469D301EFA3134004A6B28 /* RSRSSParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D261EFA3134004A6B28 /* RSRSSParser.m */; }; 84469D301EFA3134004A6B28 /* RSRSSParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D261EFA3134004A6B28 /* RSRSSParser.m */; };
84469D321EFA31CF004A6B28 /* FeedParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84469D311EFA31CF004A6B28 /* FeedParser.swift */; }; 84469D321EFA31CF004A6B28 /* FeedParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84469D311EFA31CF004A6B28 /* FeedParser.swift */; };
84469D351EFF1190004A6B28 /* NSData+RSParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D331EFF1190004A6B28 /* NSData+RSParser.h */; }; 84469D351EFF1190004A6B28 /* NSData+RSParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D331EFF1190004A6B28 /* NSData+RSParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
84469D361EFF1190004A6B28 /* NSData+RSParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D341EFF1190004A6B28 /* NSData+RSParser.m */; }; 84469D361EFF1190004A6B28 /* NSData+RSParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D341EFF1190004A6B28 /* NSData+RSParser.m */; };
84469D381EFF2645004A6B28 /* RSSInJSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84469D371EFF2645004A6B28 /* RSSInJSONParser.swift */; }; 84469D381EFF2645004A6B28 /* RSSInJSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84469D371EFF2645004A6B28 /* RSSInJSONParser.swift */; };
84469D401EFF29A9004A6B28 /* FeedParserError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84469D3F1EFF29A9004A6B28 /* FeedParserError.swift */; }; 84469D401EFF29A9004A6B28 /* FeedParserError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84469D3F1EFF29A9004A6B28 /* FeedParserError.swift */; };
@ -94,12 +94,12 @@
84469D041EFA307E004A6B28 /* RSHTMLMetadataParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSHTMLMetadataParser.m; sourceTree = "<group>"; }; 84469D041EFA307E004A6B28 /* RSHTMLMetadataParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSHTMLMetadataParser.m; sourceTree = "<group>"; };
84469D051EFA307E004A6B28 /* RSSAXHTMLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSSAXHTMLParser.h; sourceTree = "<group>"; }; 84469D051EFA307E004A6B28 /* RSSAXHTMLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSSAXHTMLParser.h; sourceTree = "<group>"; };
84469D061EFA307E004A6B28 /* RSSAXHTMLParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSSAXHTMLParser.m; sourceTree = "<group>"; }; 84469D061EFA307E004A6B28 /* RSSAXHTMLParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSSAXHTMLParser.m; sourceTree = "<group>"; };
84469D101EFA30A2004A6B28 /* NSString+RSXML.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+RSXML.h"; sourceTree = "<group>"; }; 84469D101EFA30A2004A6B28 /* NSString+RSParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+RSParser.h"; sourceTree = "<group>"; };
84469D111EFA30A2004A6B28 /* NSString+RSXML.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+RSXML.m"; sourceTree = "<group>"; }; 84469D111EFA30A2004A6B28 /* NSString+RSParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+RSParser.m"; sourceTree = "<group>"; };
84469D121EFA30A2004A6B28 /* RSDateParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSDateParser.h; sourceTree = "<group>"; }; 84469D121EFA30A2004A6B28 /* RSDateParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RSDateParser.h; path = Utilities/RSDateParser.h; sourceTree = "<group>"; };
84469D131EFA30A2004A6B28 /* RSDateParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSDateParser.m; sourceTree = "<group>"; }; 84469D131EFA30A2004A6B28 /* RSDateParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RSDateParser.m; path = Utilities/RSDateParser.m; sourceTree = "<group>"; };
84469D141EFA30A2004A6B28 /* RSXMLInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSXMLInternal.h; sourceTree = "<group>"; }; 84469D141EFA30A2004A6B28 /* RSParserInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSParserInternal.h; sourceTree = "<group>"; };
84469D151EFA30A2004A6B28 /* RSXMLInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSXMLInternal.m; sourceTree = "<group>"; }; 84469D151EFA30A2004A6B28 /* RSParserInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSParserInternal.m; sourceTree = "<group>"; };
84469D1D1EFA3134004A6B28 /* RSAtomParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSAtomParser.h; sourceTree = "<group>"; }; 84469D1D1EFA3134004A6B28 /* RSAtomParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSAtomParser.h; sourceTree = "<group>"; };
84469D1E1EFA3134004A6B28 /* RSAtomParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSAtomParser.m; sourceTree = "<group>"; }; 84469D1E1EFA3134004A6B28 /* RSAtomParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSAtomParser.m; sourceTree = "<group>"; };
84469D1F1EFA3134004A6B28 /* RSFeedParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSFeedParser.h; sourceTree = "<group>"; }; 84469D1F1EFA3134004A6B28 /* RSFeedParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSFeedParser.h; sourceTree = "<group>"; };
@ -150,6 +150,15 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
84285AA61F004879002E8708 /* Dates */ = {
isa = PBXGroup;
children = (
84469D121EFA30A2004A6B28 /* RSDateParser.h */,
84469D131EFA30A2004A6B28 /* RSDateParser.m */,
);
name = Dates;
sourceTree = "<group>";
};
84469CE31EFA2FB0004A6B28 /* Feeds */ = { 84469CE31EFA2FB0004A6B28 /* Feeds */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -213,12 +222,10 @@
children = ( children = (
84469D331EFF1190004A6B28 /* NSData+RSParser.h */, 84469D331EFF1190004A6B28 /* NSData+RSParser.h */,
84469D341EFF1190004A6B28 /* NSData+RSParser.m */, 84469D341EFF1190004A6B28 /* NSData+RSParser.m */,
84469D101EFA30A2004A6B28 /* NSString+RSXML.h */, 84469D101EFA30A2004A6B28 /* NSString+RSParser.h */,
84469D111EFA30A2004A6B28 /* NSString+RSXML.m */, 84469D111EFA30A2004A6B28 /* NSString+RSParser.m */,
84469D121EFA30A2004A6B28 /* RSDateParser.h */, 84469D141EFA30A2004A6B28 /* RSParserInternal.h */,
84469D131EFA30A2004A6B28 /* RSDateParser.m */, 84469D151EFA30A2004A6B28 /* RSParserInternal.m */,
84469D141EFA30A2004A6B28 /* RSXMLInternal.h */,
84469D151EFA30A2004A6B28 /* RSXMLInternal.m */,
); );
path = Utilities; path = Utilities;
sourceTree = "<group>"; sourceTree = "<group>";
@ -257,6 +264,7 @@
84D81BDA1EFA28E700652332 /* RSParser.h */, 84D81BDA1EFA28E700652332 /* RSParser.h */,
84469CE11EFA2F3E004A6B28 /* ParserData.swift */, 84469CE11EFA2F3E004A6B28 /* ParserData.swift */,
84469CE31EFA2FB0004A6B28 /* Feeds */, 84469CE31EFA2FB0004A6B28 /* Feeds */,
84285AA61F004879002E8708 /* Dates */,
84469CE41EFA3000004A6B28 /* OPML */, 84469CE41EFA3000004A6B28 /* OPML */,
84469CFE1EFA307E004A6B28 /* HTML */, 84469CFE1EFA307E004A6B28 /* HTML */,
84469CF91EFA3069004A6B28 /* SAX */, 84469CF91EFA3069004A6B28 /* SAX */,
@ -298,7 +306,7 @@
84469CF51EFA3000004A6B28 /* RSOPMLItem.h in Headers */, 84469CF51EFA3000004A6B28 /* RSOPMLItem.h in Headers */,
84469D2D1EFA3134004A6B28 /* RSParsedFeed.h in Headers */, 84469D2D1EFA3134004A6B28 /* RSParsedFeed.h in Headers */,
84469D181EFA30A2004A6B28 /* RSDateParser.h in Headers */, 84469D181EFA30A2004A6B28 /* RSDateParser.h in Headers */,
84469D1A1EFA30A2004A6B28 /* RSXMLInternal.h in Headers */, 84469D1A1EFA30A2004A6B28 /* RSParserInternal.h in Headers */,
84469D351EFF1190004A6B28 /* NSData+RSParser.h in Headers */, 84469D351EFF1190004A6B28 /* NSData+RSParser.h in Headers */,
84D81BDC1EFA28E700652332 /* RSParser.h in Headers */, 84D81BDC1EFA28E700652332 /* RSParser.h in Headers */,
84469D0B1EFA307E004A6B28 /* RSHTMLMetadataParser.h in Headers */, 84469D0B1EFA307E004A6B28 /* RSHTMLMetadataParser.h in Headers */,
@ -311,7 +319,7 @@
84469CF31EFA3000004A6B28 /* RSOPMLFeedSpecifier.h in Headers */, 84469CF31EFA3000004A6B28 /* RSOPMLFeedSpecifier.h in Headers */,
84469CF11EFA3000004A6B28 /* RSOPMLDocument.h in Headers */, 84469CF11EFA3000004A6B28 /* RSOPMLDocument.h in Headers */,
84469D091EFA307E004A6B28 /* RSHTMLMetadata.h in Headers */, 84469D091EFA307E004A6B28 /* RSHTMLMetadata.h in Headers */,
84469D161EFA30A2004A6B28 /* NSString+RSXML.h in Headers */, 84469D161EFA30A2004A6B28 /* NSString+RSParser.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -414,7 +422,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
84469D081EFA307E004A6B28 /* RSHTMLLinkParser.m in Sources */, 84469D081EFA307E004A6B28 /* RSHTMLLinkParser.m in Sources */,
84469D1B1EFA30A2004A6B28 /* RSXMLInternal.m in Sources */, 84469D1B1EFA30A2004A6B28 /* RSParserInternal.m in Sources */,
84D81BE21EFA2D0900652332 /* ParsedAuthor.swift in Sources */, 84D81BE21EFA2D0900652332 /* ParsedAuthor.swift in Sources */,
84469D0E1EFA307E004A6B28 /* RSSAXHTMLParser.m in Sources */, 84469D0E1EFA307E004A6B28 /* RSSAXHTMLParser.m in Sources */,
84469CF41EFA3000004A6B28 /* RSOPMLFeedSpecifier.m in Sources */, 84469CF41EFA3000004A6B28 /* RSOPMLFeedSpecifier.m in Sources */,
@ -431,7 +439,7 @@
84469D421EFF2B2D004A6B28 /* JSONTypes.swift in Sources */, 84469D421EFF2B2D004A6B28 /* JSONTypes.swift in Sources */,
84469D0C1EFA307E004A6B28 /* RSHTMLMetadataParser.m in Sources */, 84469D0C1EFA307E004A6B28 /* RSHTMLMetadataParser.m in Sources */,
84469D0A1EFA307E004A6B28 /* RSHTMLMetadata.m in Sources */, 84469D0A1EFA307E004A6B28 /* RSHTMLMetadata.m in Sources */,
84469D171EFA30A2004A6B28 /* NSString+RSXML.m in Sources */, 84469D171EFA30A2004A6B28 /* NSString+RSParser.m in Sources */,
84469D2C1EFA3134004A6B28 /* RSParsedArticle.m in Sources */, 84469D2C1EFA3134004A6B28 /* RSParsedArticle.m in Sources */,
84469D2E1EFA3134004A6B28 /* RSParsedFeed.m in Sources */, 84469D2E1EFA3134004A6B28 /* RSParsedFeed.m in Sources */,
84469CF81EFA3000004A6B28 /* RSOPMLParser.m in Sources */, 84469CF81EFA3000004A6B28 /* RSOPMLParser.m in Sources */,

View File

@ -1,6 +1,6 @@
// //
// RSSAXParser.h // RSSAXParser.h
// RSXML // RSParser
// //
// Created by Brent Simmons on 3/25/15. // Created by Brent Simmons on 3/25/15.
// Copyright (c) 2015 Ranchero Software, LLC. All rights reserved. // Copyright (c) 2015 Ranchero Software, LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
// //
// RSSAXParser.m // RSSAXParser.m
// RSXML // RSParser
// //
// Created by Brent Simmons on 3/25/15. // Created by Brent Simmons on 3/25/15.
// Copyright (c) 2015 Ranchero Software, LLC. All rights reserved. // Copyright (c) 2015 Ranchero Software, LLC. All rights reserved.
@ -152,7 +152,7 @@ static xmlSAXHandler saxHandlerStruct;
- (NSString *)currentString { - (NSString *)currentString {
NSData *d = self.currentCharacters; NSData *d = self.currentCharacters;
if (RSXMLIsEmpty(d)) { if (RSParserObjectIsEmpty(d)) {
return nil; return nil;
} }

View File

@ -15,6 +15,11 @@
- (BOOL)isProbablyXML; - (BOOL)isProbablyXML;
- (BOOL)isProbablyJSON; - (BOOL)isProbablyJSON;
- (BOOL)isProbablyJSONFeed;
- (BOOL)isProbablyRSSInJSON;
- (BOOL)isProbablyRSS;
- (BOOL)isProbablyAtom;
@end @end

View File

@ -39,7 +39,7 @@ static BOOL bytesStartWithStringIgnoringWhitespace(const char *string, const cha
return didFindString("https://jsonfeed.org/version/", self.bytes, self.length); return didFindString("https://jsonfeed.org/version/", self.bytes, self.length);
} }
- (BOOL)isProbablyRSSInJSONFeed { - (BOOL)isProbablyRSSInJSON {
if (![self isProbablyJSON]) { if (![self isProbablyJSON]) {
return NO; return NO;

View File

@ -0,0 +1,18 @@
//
// NSString+RSParser.h
// RSParser
//
// Created by Brent Simmons on 9/25/15.
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
//
@import Foundation;
@interface NSString (RSParser)
- (NSString *)rsparser_stringByDecodingHTMLEntities;
- (NSString *)rsparser_md5Hash;
@end

View File

@ -1,24 +1,24 @@
// //
// NSString+RSXML.m // NSString+RSParser.m
// RSXML // RSParser
// //
// Created by Brent Simmons on 9/25/15. // Created by Brent Simmons on 9/25/15.
// Copyright © 2015 Ranchero Software, LLC. All rights reserved. // Copyright © 2015 Ranchero Software, LLC. All rights reserved.
// //
#import "NSString+RSXML.h" #import "NSString+RSParser.h"
@interface NSScanner (RSXML) @interface NSScanner (RSParser)
- (BOOL)rs_scanEntityValue:(NSString * _Nullable * _Nullable)decodedEntity; - (BOOL)rs_scanEntityValue:(NSString * _Nullable * _Nullable)decodedEntity;
@end @end
@implementation NSString (RSXML) @implementation NSString (RSParser)
- (NSString *)rs_stringByDecodingHTMLEntities { - (NSString *)rsparser_stringByDecodingHTMLEntities {
@autoreleasepool { @autoreleasepool {
@ -60,7 +60,7 @@
static NSDictionary *RSEntitiesDictionary(void); static NSDictionary *RSEntitiesDictionary(void);
static NSString *RSXMLStringWithValue(unichar value); static NSString *RSParserStringWithValue(unichar value);
- (NSString * _Nullable)rs_stringByDecodingEntity { - (NSString * _Nullable)rs_stringByDecodingEntity {
@ -87,7 +87,7 @@ static NSString *RSXMLStringWithValue(unichar value);
scanner.charactersToBeSkipped = [NSCharacterSet characterSetWithCharactersInString:@"#x"]; scanner.charactersToBeSkipped = [NSCharacterSet characterSetWithCharactersInString:@"#x"];
unsigned int hexValue = 0; unsigned int hexValue = 0;
if ([scanner scanHexInt:&hexValue]) { if ([scanner scanHexInt:&hexValue]) {
return RSXMLStringWithValue((unichar)hexValue); return RSParserStringWithValue((unichar)hexValue);
} }
return nil; return nil;
} }
@ -98,15 +98,33 @@ static NSString *RSXMLStringWithValue(unichar value);
if (value < 1) { if (value < 1) {
return nil; return nil;
} }
return RSXMLStringWithValue((unichar)value); return RSParserStringWithValue((unichar)value);
} }
return nil; return nil;
} }
- (NSData *)_rsparser_md5HashData {
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
unsigned char hash[CC_MD5_DIGEST_LENGTH];
CC_MD5(data.bytes, (CC_LONG)data.length, hash);
return [NSData dataWithBytes:(const void *)hash length:CC_MD5_DIGEST_LENGTH];
}
- (NSString *)rsparser_md5Hash {
NSData *md5Data = [self _rsparser_md5HashData];
const Byte *bytes = md5Data.bytes;
return [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]];
}
@end @end
@implementation NSScanner (RSXML) @implementation NSScanner (RSParser)
- (BOOL)rs_scanEntityValue:(NSString * _Nullable * _Nullable)decodedEntity { - (BOOL)rs_scanEntityValue:(NSString * _Nullable * _Nullable)decodedEntity {
@ -144,7 +162,7 @@ static NSString *RSXMLStringWithValue(unichar value);
@end @end
static NSString *RSXMLStringWithValue(unichar value) { static NSString *RSParserStringWithValue(unichar value) {
return [[NSString alloc] initWithFormat:@"%C", value]; return [[NSString alloc] initWithFormat:@"%C", value];
} }
@ -169,7 +187,7 @@ static NSDictionary *RSEntitiesDictionary(void) {
@"#150": @"-", @"#150": @"-",
@"#151": @"—", @"#151": @"—",
@"#153": @"™", @"#153": @"™",
@"#160": RSXMLStringWithValue(160), @"#160": RSParserStringWithValue(160),
@"#161": @"¡", @"#161": @"¡",
@"#162": @"¢", @"#162": @"¢",
@"#163": @"£", @"#163": @"£",
@ -277,7 +295,7 @@ static NSDictionary *RSEntitiesDictionary(void) {
@"#8220": @"“", @"#8220": @"“",
@"#8221": @"”", @"#8221": @"”",
@"#8230": @"…", @"#8230": @"…",
@"#8617": RSXMLStringWithValue(8617), @"#8617": RSParserStringWithValue(8617),
@"AElig": @"Æ", @"AElig": @"Æ",
@"Aacute": @"Á", @"Aacute": @"Á",
@"Acirc": @"Â", @"Acirc": @"Â",
@ -394,14 +412,14 @@ static NSDictionary *RSEntitiesDictionary(void) {
@"yen": @"¥", @"yen": @"¥",
@"yuml": @"ÿ", @"yuml": @"ÿ",
@"infin": @"∞", @"infin": @"∞",
@"nbsp": RSXMLStringWithValue(160), @"nbsp": RSParserStringWithValue(160),
@"#x21A9": RSXMLStringWithValue(8617), @"#x21A9": RSParserStringWithValue(8617),
@"#xFE0E": RSXMLStringWithValue(65038), @"#xFE0E": RSParserStringWithValue(65038),
@"#x2019": RSXMLStringWithValue(8217), @"#x2019": RSParserStringWithValue(8217),
@"#x2026": RSXMLStringWithValue(8230), @"#x2026": RSParserStringWithValue(8230),
@"#x201C": RSXMLStringWithValue(8220), @"#x201C": RSParserStringWithValue(8220),
@"#x201D": RSXMLStringWithValue(8221), @"#x201D": RSParserStringWithValue(8221),
@"#x2014": RSXMLStringWithValue(8212)}; @"#x2014": RSParserStringWithValue(8212)};
}); });
return entitiesDictionary; return entitiesDictionary;

View File

@ -1,16 +0,0 @@
//
// NSString+RSXML.h
// RSXML
//
// Created by Brent Simmons on 9/25/15.
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
//
@import Foundation;
@interface NSString (RSXML)
- (NSString *)rs_stringByDecodingHTMLEntities;
@end

View File

@ -1,6 +1,6 @@
// //
// RSDateParser.h // RSDateParser.h
// RSXML // RSParser
// //
// Created by Brent Simmons on 3/25/15. // Created by Brent Simmons on 3/25/15.
// Copyright (c) 2015 Ranchero Software, LLC. All rights reserved. // Copyright (c) 2015 Ranchero Software, LLC. All rights reserved.
@ -9,17 +9,14 @@
@import Foundation; @import Foundation;
/*Common web dates -- RFC 822 and 8601 -- are handled here: // Common web dates -- RFC 822 and 8601 -- are handled here: the formats you find in JSON and XML feeds.
the formats you find in JSON and XML feeds. // These may return nil. They may also return garbage, given bad input.
Any of these may return nil. They may also return garbage, given bad input.*/
NSDate *RSDateWithString(NSString *dateString); NSDate *RSDateWithString(NSString *dateString);
/*If you're using a SAX parser, you have the bytes and don't need to convert to a string first. // If you're using a SAX parser, you have the bytes and don't need to convert to a string first.
It's faster and uses less memory. // It's faster and uses less memory.
(Assumes bytes are UTF-8 or ASCII. If you're using the libxml SAX parser, this will work.)*/ // (Assumes bytes are UTF-8 or ASCII. If you're using the libxml SAX parser, this will work.)
NSDate *RSDateWithBytes(const char *bytes, NSUInteger numberOfBytes); NSDate *RSDateWithBytes(const char *bytes, NSUInteger numberOfBytes);

View File

@ -1,6 +1,6 @@
// //
// RSDateParser.m // RSDateParser.m
// RSXML // RSParser
// //
// Created by Brent Simmons on 3/25/15. // Created by Brent Simmons on 3/25/15.
// Copyright (c) 2015 Ranchero Software, LLC. All rights reserved. // Copyright (c) 2015 Ranchero Software, LLC. All rights reserved.

View File

@ -0,0 +1,24 @@
//
// RSParserInternal.h
// RSParser
//
// Created by Brent Simmons on 12/26/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
//
@import Foundation;
NS_ASSUME_NONNULL_BEGIN
BOOL RSParser_IsEmpty(id _Nullable obj);
BOOL RSParserStringIsEmpty(NSString * _Nullable s);
@interface NSDictionary (RSParserInternal)
- (nullable id)rsparser_objectForCaseInsensitiveKey:(NSString *)key;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,60 @@
//
// RSXMLInternal.m
// RSParser
//
// Created by Brent Simmons on 12/26/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
//
#import <CommonCrypto/CommonDigest.h>
#import "RSXMLInternal.h"
static BOOL RSParserIsNil(id obj) {
return obj == nil || obj == [NSNull null];
}
BOOL RSParserObjectIsEmpty(id obj) {
if (RSParserIsNil(obj)) {
return YES;
}
if ([obj respondsToSelector:@selector(count)]) {
return [obj count] < 1;
}
if ([obj respondsToSelector:@selector(length)]) {
return [obj length] < 1;
}
return NO; /*Shouldn't get here very often.*/
}
BOOL RSParserStringIsEmpty(NSString *s) {
return RSParserIsNil(s) || s.length < 1;
}
@implementation NSDictionary (RSParserInternal)
- (nullable id)rsparser_objectForCaseInsensitiveKey:(NSString *)key {
id obj = self[key];
if (obj) {
return obj;
}
for (NSString *oneKey in self.allKeys) {
if ([oneKey isKindOfClass:[NSString class]] && [key caseInsensitiveCompare:oneKey] == NSOrderedSame) {
return self[oneKey];
}
}
return nil;
}
@end

View File

@ -1,31 +0,0 @@
//
// RSXMLInternal.h
// RSXML
//
// Created by Brent Simmons on 12/26/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
//
@import Foundation;
NS_ASSUME_NONNULL_BEGIN
BOOL RSXMLIsEmpty(id _Nullable obj);
BOOL RSXMLStringIsEmpty(NSString * _Nullable s);
@interface NSString (RSXMLInternal)
- (NSString *)rsxml_md5HashString;
@end
@interface NSDictionary (RSXMLInternal)
- (nullable id)rsxml_objectForCaseInsensitiveKey:(NSString *)key;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,83 +0,0 @@
//
// RSXMLInternal.m
// RSXML
//
// Created by Brent Simmons on 12/26/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
//
#import <CommonCrypto/CommonDigest.h>
#import "RSXMLInternal.h"
static BOOL RSXMLIsNil(id obj) {
return obj == nil || obj == [NSNull null];
}
BOOL RSXMLIsEmpty(id obj) {
if (RSXMLIsNil(obj)) {
return YES;
}
if ([obj respondsToSelector:@selector(count)]) {
return [obj count] < 1;
}
if ([obj respondsToSelector:@selector(length)]) {
return [obj length] < 1;
}
return NO; /*Shouldn't get here very often.*/
}
BOOL RSXMLStringIsEmpty(NSString *s) {
return RSXMLIsNil(s) || s.length < 1;
}
@implementation NSString (RSXMLInternal)
- (NSData *)rsxml_md5Hash {
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
unsigned char hash[CC_MD5_DIGEST_LENGTH];
CC_MD5(data.bytes, (CC_LONG)data.length, hash);
return [NSData dataWithBytes:(const void *)hash length:CC_MD5_DIGEST_LENGTH];
}
- (NSString *)rsxml_md5HashString {
NSData *md5Data = [self rsxml_md5Hash];
const Byte *bytes = md5Data.bytes;
return [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]];
}
@end
@implementation NSDictionary (RSXMLInternal)
- (nullable id)rsxml_objectForCaseInsensitiveKey:(NSString *)key {
id obj = self[key];
if (obj) {
return obj;
}
for (NSString *oneKey in self.allKeys) {
if ([oneKey isKindOfClass:[NSString class]] && [key caseInsensitiveCompare:oneKey] == NSOrderedSame) {
return self[oneKey];
}
}
return nil;
}
@end