v2.0.0 release; move all docref to header + optional NSXML
This commit is contained in:
@@ -560,7 +560,7 @@
|
|||||||
DYLIB_CURRENT_VERSION = 1;
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
TARGET_IOS,
|
"TARGET_IOS=1",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2";
|
HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2";
|
||||||
@@ -586,7 +586,7 @@
|
|||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
DYLIB_CURRENT_VERSION = 1;
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = TARGET_IOS;
|
GCC_PREPROCESSOR_DEFINITIONS = "TARGET_IOS=1";
|
||||||
HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2";
|
HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2";
|
||||||
INFOPLIST_FILE = RSXMLiOS/Info.plist;
|
INFOPLIST_FILE = RSXMLiOS/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@@ -743,10 +743,6 @@
|
|||||||
DYLIB_CURRENT_VERSION = 1;
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
FRAMEWORK_VERSION = A;
|
FRAMEWORK_VERSION = A;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
|
||||||
TARGET_MAC,
|
|
||||||
"$(inherited)",
|
|
||||||
);
|
|
||||||
HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2";
|
HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2";
|
||||||
INFOPLIST_FILE = RSXML/Info.plist;
|
INFOPLIST_FILE = RSXML/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@@ -770,7 +766,6 @@
|
|||||||
DYLIB_CURRENT_VERSION = 1;
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
FRAMEWORK_VERSION = A;
|
FRAMEWORK_VERSION = A;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = TARGET_MAC;
|
|
||||||
HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2";
|
HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2";
|
||||||
INFOPLIST_FILE = RSXML/Info.plist;
|
INFOPLIST_FILE = RSXML/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@@ -787,10 +782,6 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
|
||||||
TARGET_MAC,
|
|
||||||
"$(inherited)",
|
|
||||||
);
|
|
||||||
HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2";
|
HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2";
|
||||||
INFOPLIST_FILE = RSXMLTests/Info.plist;
|
INFOPLIST_FILE = RSXMLTests/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||||
@@ -805,7 +796,6 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = TARGET_MAC;
|
|
||||||
HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2";
|
HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2";
|
||||||
INFOPLIST_FILE = RSXMLTests/Info.plist;
|
INFOPLIST_FILE = RSXMLTests/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>FMWK</string>
|
<string>FMWK</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0</string>
|
<string>2.0.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
// <feed> <entry>
|
// <feed> <entry>
|
||||||
// https://validator.w3.org/feed/docs/rfc4287.html
|
// https://validator.w3.org/feed/docs/rfc4287.html
|
||||||
|
|
||||||
|
/// Feed parser for Atom xml feeds. Expects the tags @c <feed> and @c <entry> to be existent.
|
||||||
@interface RSAtomParser : RSFeedParser
|
@interface RSAtomParser : RSFeedParser
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -26,10 +26,13 @@
|
|||||||
|
|
||||||
@class RSParsedFeed, RSParsedArticle;
|
@class RSParsedFeed, RSParsedArticle;
|
||||||
|
|
||||||
|
/// Generic feed parser. Used for atom, RSS, and RDF feeds.
|
||||||
@interface RSFeedParser : RSXMLParser<RSParsedFeed*>
|
@interface RSFeedParser : RSXMLParser<RSParsedFeed*>
|
||||||
@property (nonatomic, readonly) RSParsedFeed *parsedFeed;
|
@property (nonatomic, readonly) RSParsedFeed *parsedFeed;
|
||||||
@property (nonatomic, weak) RSParsedArticle *currentArticle;
|
@property (nonatomic, weak) RSParsedArticle *currentArticle;
|
||||||
|
|
||||||
|
/// @return @c NSDate by parsing RFC 822 and 8601 date strings.
|
||||||
- (NSDate *)dateFromCharacters:(NSData *)data;
|
- (NSDate *)dateFromCharacters:(NSData *)data;
|
||||||
|
/// @return currentString by removing HTML encoded entities.
|
||||||
- (NSString *)decodeHTMLEntities:(NSString *)str;
|
- (NSString *)decodeHTMLEntities:(NSString *)str;
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -45,12 +45,12 @@
|
|||||||
return _parsedFeed;
|
return _parsedFeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return @c NSDate by parsing RFC 822 and 8601 date strings.
|
// docref in header
|
||||||
- (NSDate *)dateFromCharacters:(NSData *)data {
|
- (NSDate *)dateFromCharacters:(NSData *)data {
|
||||||
return RSDateWithBytes(data.bytes, data.length);
|
return RSDateWithBytes(data.bytes, data.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return currentString by removing HTML encoded entities.
|
// docref in header
|
||||||
- (NSString *)decodeHTMLEntities:(NSString *)str {
|
- (NSString *)decodeHTMLEntities:(NSString *)str {
|
||||||
return [str rsxml_stringByDecodingHTMLEntities];
|
return [str rsxml_stringByDecodingHTMLEntities];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,5 +27,6 @@
|
|||||||
|
|
||||||
@class RSHTMLMetadataAnchor;
|
@class RSHTMLMetadataAnchor;
|
||||||
|
|
||||||
|
/// HTML parser for html header metadata. Used to extract generic anchor tags.
|
||||||
@interface RSHTMLLinkParser : RSXMLParser<NSArray<RSHTMLMetadataAnchor*>*>
|
@interface RSHTMLLinkParser : RSXMLParser<NSArray<RSHTMLMetadataAnchor*>*>
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ RSFeedType RSFeedTypeFromLinkTypeAttribute(NSString * typeStr);
|
|||||||
|
|
||||||
@class RSHTMLMetadataIconLink, RSHTMLMetadataFeedLink;
|
@class RSHTMLMetadataIconLink, RSHTMLMetadataFeedLink;
|
||||||
|
|
||||||
|
/// Parsed result type for HTML metadata.
|
||||||
@interface RSHTMLMetadata : NSObject
|
@interface RSHTMLMetadata : NSObject
|
||||||
@property (nonatomic, copy, nullable) NSString *faviconLink;
|
@property (nonatomic, copy, nullable) NSString *faviconLink;
|
||||||
@property (nonatomic, nonnull) NSArray <RSHTMLMetadataIconLink *> *iconLinks;
|
@property (nonatomic, nonnull) NSArray <RSHTMLMetadataIconLink *> *iconLinks;
|
||||||
@@ -51,6 +52,7 @@ RSFeedType RSFeedTypeFromLinkTypeAttribute(NSString * typeStr);
|
|||||||
|
|
||||||
@interface RSHTMLMetadataIconLink : RSHTMLMetadataLink
|
@interface RSHTMLMetadataIconLink : RSHTMLMetadataLink
|
||||||
@property (nonatomic, copy, nullable) NSString *sizes;
|
@property (nonatomic, copy, nullable) NSString *sizes;
|
||||||
|
/// Parses size on the fly. Expects the following format: @c "{int}x{int}" . Returns @c CGSizeZero otherwise.
|
||||||
- (CGSize)getSize;
|
- (CGSize)getSize;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ RSFeedType RSFeedTypeFromLinkTypeAttribute(NSString * typeStr) {
|
|||||||
|
|
||||||
@implementation RSHTMLMetadataIconLink
|
@implementation RSHTMLMetadataIconLink
|
||||||
|
|
||||||
|
// docref in header
|
||||||
- (CGSize)getSize {
|
- (CGSize)getSize {
|
||||||
if (self.sizes && self.sizes.length > 0) {
|
if (self.sizes && self.sizes.length > 0) {
|
||||||
NSArray<NSString*> *parts = [self.sizes componentsSeparatedByString:@"x"];
|
NSArray<NSString*> *parts = [self.sizes componentsSeparatedByString:@"x"];
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
@class RSHTMLMetadata;
|
@class RSHTMLMetadata;
|
||||||
|
|
||||||
|
/// HTML parser for html header metadata. Used to extract feed and favicon URLs.
|
||||||
@interface RSHTMLMetadataParser : RSXMLParser<RSHTMLMetadata*>
|
@interface RSHTMLMetadataParser : RSXMLParser<RSHTMLMetadata*>
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -23,32 +23,44 @@
|
|||||||
|
|
||||||
@import Foundation;
|
@import Foundation;
|
||||||
|
|
||||||
|
#ifndef TARGET_IOS
|
||||||
|
#define OPML_EXPORT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
// OPML allows for arbitrary attributes.
|
// OPML allows for arbitrary attributes.
|
||||||
// These are the common attributes in OPML files used as RSS subscription lists.
|
// These are the common attributes in OPML files used as RSS subscription lists.
|
||||||
|
|
||||||
extern NSString *OPMLTextKey; //text
|
/** Constant: @c \@"text" */ extern NSString *OPMLTextKey;
|
||||||
extern NSString *OPMLTitleKey; //title
|
/** Constant: @c \@"title" */ extern NSString *OPMLTitleKey;
|
||||||
extern NSString *OPMLDescriptionKey; //description
|
/** Constant: @c \@"description" */ extern NSString *OPMLDescriptionKey;
|
||||||
extern NSString *OPMLTypeKey; //type
|
/** Constant: @c \@"type" */ extern NSString *OPMLTypeKey;
|
||||||
extern NSString *OPMLVersionKey; //version
|
/** Constant: @c \@"version" */ extern NSString *OPMLVersionKey;
|
||||||
extern NSString *OPMLHMTLURLKey; //htmlUrl
|
/** Constant: @c \@"htmlUrl" */ extern NSString *OPMLHMTLURLKey;
|
||||||
extern NSString *OPMLXMLURLKey; //xmlUrl
|
/** Constant: @c \@"xmlUrl" */ extern NSString *OPMLXMLURLKey;
|
||||||
|
|
||||||
|
|
||||||
|
/// Parsed result type for opml files. @c children can be arbitrary nested.
|
||||||
@interface RSOPMLItem : NSObject
|
@interface RSOPMLItem : NSObject
|
||||||
|
/// Can be arbitrary nested.
|
||||||
@property (nonatomic) NSArray<RSOPMLItem*> *children;
|
@property (nonatomic) NSArray<RSOPMLItem*> *children;
|
||||||
@property (nonatomic) NSDictionary *attributes;
|
@property (nonatomic) NSDictionary *attributes;
|
||||||
@property (nonatomic, readonly) BOOL isFolder; // true if children.count > 0
|
/// Returns @c YES if @c children.count @c > @c 0
|
||||||
@property (nonatomic, readonly) NSString *displayName; //May be nil.
|
@property (nonatomic, readonly) BOOL isFolder;
|
||||||
|
@property (nonatomic, readonly, nullable) NSString *displayName;
|
||||||
|
|
||||||
+ (instancetype)itemWithAttributes:(NSDictionary *)attribs;
|
+ (instancetype)itemWithAttributes:(NSDictionary *)attribs;
|
||||||
|
|
||||||
|
/// Appends one child to the internal children array (creates new empty array if necessary).
|
||||||
- (void)addChild:(RSOPMLItem *)child;
|
- (void)addChild:(RSOPMLItem *)child;
|
||||||
|
/// Sets a value in the internal dictionary (creates new empty dictionary if necessary).
|
||||||
- (void)setAttribute:(id)value forKey:(NSString *)key;
|
- (void)setAttribute:(id)value forKey:(NSString *)key;
|
||||||
|
/// @return Value for key (case-independent).
|
||||||
- (id)attributeForKey:(NSString *)key;
|
- (id)attributeForKey:(NSString *)key;
|
||||||
|
|
||||||
|
/// Print object description for debugging purposes.
|
||||||
- (NSString *)recursiveDescription;
|
- (NSString *)recursiveDescription;
|
||||||
#ifdef TARGET_MAC
|
#if OPML_EXPORT
|
||||||
|
/// Can be used to export directly to @c .opml file.
|
||||||
- (NSXMLDocument *)exportXML;
|
- (NSXMLDocument *)exportXML;
|
||||||
#endif
|
#endif
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ NSString *OPMLXMLURLKey = @"xmlUrl";
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @return Value for @c OPMLTitleKey. If not set, use @c OPMLTextKey, else return @c nil.
|
/// @return Value for @c OPMLTitleKey. If not set, use @c OPMLTextKey, else return @c nil.
|
||||||
- (NSString *)displayName {
|
- (nullable NSString *)displayName {
|
||||||
NSString *title = [self attributeForKey:OPMLTitleKey];
|
NSString *title = [self attributeForKey:OPMLTitleKey];
|
||||||
if (!title) {
|
if (!title) {
|
||||||
title = [self attributeForKey:OPMLTextKey];
|
title = [self attributeForKey:OPMLTextKey];
|
||||||
@@ -82,7 +82,7 @@ NSString *OPMLXMLURLKey = @"xmlUrl";
|
|||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends one child to the internal children array (creates new empty array if necessary).
|
// docref in header
|
||||||
- (void)addChild:(RSOPMLItem *)child {
|
- (void)addChild:(RSOPMLItem *)child {
|
||||||
if (!self.mutableChildren) {
|
if (!self.mutableChildren) {
|
||||||
self.mutableChildren = [NSMutableArray new];
|
self.mutableChildren = [NSMutableArray new];
|
||||||
@@ -90,7 +90,7 @@ NSString *OPMLXMLURLKey = @"xmlUrl";
|
|||||||
[self.mutableChildren addObject:child];
|
[self.mutableChildren addObject:child];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a value in the internal dictionary (creates new empty dictionary if necessary).
|
// docref in header
|
||||||
- (void)setAttribute:(id)value forKey:(NSString *)key {
|
- (void)setAttribute:(id)value forKey:(NSString *)key {
|
||||||
if (!self.mutableAttributes) {
|
if (!self.mutableAttributes) {
|
||||||
self.mutableAttributes = [NSMutableDictionary new];
|
self.mutableAttributes = [NSMutableDictionary new];
|
||||||
@@ -98,7 +98,7 @@ NSString *OPMLXMLURLKey = @"xmlUrl";
|
|||||||
[self.mutableAttributes setValue:value forKey:key];
|
[self.mutableAttributes setValue:value forKey:key];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return Value for key (case-independent).
|
// docref in header
|
||||||
- (id)attributeForKey:(NSString *)key {
|
- (id)attributeForKey:(NSString *)key {
|
||||||
if (self.mutableAttributes.count > 0 && key && key.length > 0) {
|
if (self.mutableAttributes.count > 0 && key && key.length > 0) {
|
||||||
return [self.mutableAttributes rsxml_objectForCaseInsensitiveKey:key];
|
return [self.mutableAttributes rsxml_objectForCaseInsensitiveKey:key];
|
||||||
@@ -128,16 +128,16 @@ NSString *OPMLXMLURLKey = @"xmlUrl";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print object description for debugging purposes.
|
// docref in header
|
||||||
- (NSString *)recursiveDescription {
|
- (NSString *)recursiveDescription {
|
||||||
NSMutableString *mStr = [NSMutableString new];
|
NSMutableString *mStr = [NSMutableString new];
|
||||||
[self appendStringRecursive:mStr indent:@""];
|
[self appendStringRecursive:mStr indent:@""];
|
||||||
return mStr;
|
return mStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TARGET_MAC
|
#if OPML_EXPORT
|
||||||
|
|
||||||
/// Can be used to export directly to @c .opml file.
|
// docref in header
|
||||||
- (NSXMLDocument *)exportXML {
|
- (NSXMLDocument *)exportXML {
|
||||||
NSXMLElement *head = [NSXMLElement elementWithName:@"head"];
|
NSXMLElement *head = [NSXMLElement elementWithName:@"head"];
|
||||||
for (NSString *key in _mutableAttributes) {
|
for (NSString *key in _mutableAttributes) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
@class RSOPMLItem;
|
@class RSOPMLItem;
|
||||||
|
|
||||||
|
/// OPML parser for structured opml files. Expects the tags @c <opml> and @c <outline> to be existent.
|
||||||
@interface RSOPMLParser: RSXMLParser<RSOPMLItem*>
|
@interface RSOPMLParser: RSXMLParser<RSOPMLItem*>
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -24,14 +24,12 @@
|
|||||||
|
|
||||||
@import Foundation;
|
@import Foundation;
|
||||||
|
|
||||||
|
/// Parsed result type for articles. Does contain article specific attributes like abstract and content.
|
||||||
@interface RSParsedArticle : NSObject
|
@interface RSParsedArticle : NSObject
|
||||||
|
|
||||||
- (nonnull instancetype)initWithFeedURL:(NSURL * _Nonnull)feedURL dateParsed:(NSDate*)parsed;
|
|
||||||
|
|
||||||
@property (nonatomic, readonly, nonnull) NSURL *feedURL;
|
@property (nonatomic, readonly, nonnull) NSURL *feedURL;
|
||||||
@property (nonatomic, readonly, nonnull) NSDate *dateParsed;
|
@property (nonatomic, readonly, nonnull) NSDate *dateParsed;
|
||||||
@property (nonatomic, readonly, nonnull) NSString *articleID; //Calculated. Don't get until other properties have been set.
|
/// Calculated. Don't get until other properties have been set.
|
||||||
|
@property (nonatomic, readonly, nonnull) NSString *articleID;
|
||||||
|
|
||||||
@property (nonatomic, nullable) NSString *guid;
|
@property (nonatomic, nullable) NSString *guid;
|
||||||
@property (nonatomic, nullable) NSString *title;
|
@property (nonatomic, nullable) NSString *title;
|
||||||
@@ -43,7 +41,9 @@
|
|||||||
@property (nonatomic, nullable) NSDate *datePublished;
|
@property (nonatomic, nullable) NSDate *datePublished;
|
||||||
@property (nonatomic, nullable) NSDate *dateModified;
|
@property (nonatomic, nullable) NSDate *dateModified;
|
||||||
|
|
||||||
- (void)calculateArticleID; // Optimization. Call after all properties have been set. Call on a background thread.
|
- (nonnull instancetype)initWithFeedURL:(NSURL * _Nonnull)feedURL dateParsed:(NSDate*)parsed;
|
||||||
|
///Initiate calculation of article id. For optimization, call on a background thread after all properties have been set.
|
||||||
|
- (void)calculateArticleID;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -46,9 +46,7 @@
|
|||||||
|
|
||||||
#pragma mark - Unique Article ID
|
#pragma mark - Unique Article ID
|
||||||
|
|
||||||
/**
|
// docref in header
|
||||||
Article ID will be generated on the first access.
|
|
||||||
*/
|
|
||||||
- (NSString *)articleID {
|
- (NSString *)articleID {
|
||||||
if (!_internalArticleID) {
|
if (!_internalArticleID) {
|
||||||
_internalArticleID = self.calculatedUniqueID;
|
_internalArticleID = self.calculatedUniqueID;
|
||||||
@@ -56,9 +54,7 @@
|
|||||||
return _internalArticleID;
|
return _internalArticleID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// docref in header
|
||||||
Initiate calculation of article id.
|
|
||||||
*/
|
|
||||||
- (void)calculateArticleID {
|
- (void)calculateArticleID {
|
||||||
(void)self.articleID;
|
(void)self.articleID;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
@class RSParsedArticle;
|
@class RSParsedArticle;
|
||||||
|
|
||||||
|
/// Parsed result type for feeds. Does contain feed specific attributes and a sorted list or articles.
|
||||||
@interface RSParsedFeed : NSObject
|
@interface RSParsedFeed : NSObject
|
||||||
@property (nonatomic, readonly, nonnull) NSURL *url;
|
@property (nonatomic, readonly, nonnull) NSURL *url;
|
||||||
@property (nonatomic, readonly, nonnull) NSDate *dateParsed;
|
@property (nonatomic, readonly, nonnull) NSDate *dateParsed;
|
||||||
@@ -36,6 +37,7 @@
|
|||||||
@property (nonatomic, nullable) NSString *subtitle;
|
@property (nonatomic, nullable) NSString *subtitle;
|
||||||
|
|
||||||
- (nonnull instancetype)initWithURL:(NSURL * _Nonnull)url;
|
- (nonnull instancetype)initWithURL:(NSURL * _Nonnull)url;
|
||||||
|
/// Append new @c RSParsedArticle object to @c .articles and return newly inserted instance.
|
||||||
- (RSParsedArticle *)appendNewArticle;
|
- (RSParsedArticle *)appendNewArticle;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -46,9 +46,7 @@
|
|||||||
return _mutableArticles;
|
return _mutableArticles;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// docref in header
|
||||||
Append new @c RSParsedArticle object to @c .articles and return newly inserted instance.
|
|
||||||
*/
|
|
||||||
- (RSParsedArticle *)appendNewArticle {
|
- (RSParsedArticle *)appendNewArticle {
|
||||||
RSParsedArticle *article = [[RSParsedArticle alloc] initWithFeedURL:self.url dateParsed:_dateParsed];
|
RSParsedArticle *article = [[RSParsedArticle alloc] initWithFeedURL:self.url dateParsed:_dateParsed];
|
||||||
[_mutableArticles addObject:article];
|
[_mutableArticles addObject:article];
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
// <channel> <item>
|
// <channel> <item>
|
||||||
// https://cyber.harvard.edu/rss/rss.html
|
// https://cyber.harvard.edu/rss/rss.html
|
||||||
|
|
||||||
|
/// Feed parser for RSS xml and RDF xml feeds. Expects the tags @c <channel> and @c <item> to be existent.
|
||||||
@interface RSRSSParser : RSFeedParser
|
@interface RSRSSParser : RSFeedParser
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -68,11 +68,20 @@
|
|||||||
|
|
||||||
- (instancetype)initWithDelegate:(id<RSSAXParserDelegate>)delegate;
|
- (instancetype)initWithDelegate:(id<RSSAXParserDelegate>)delegate;
|
||||||
|
|
||||||
|
/// Initialize new xml or html parser context and start processing of data.
|
||||||
- (void)parseBytes:(const void *)bytes numberOfBytes:(NSUInteger)numberOfBytes;
|
- (void)parseBytes:(const void *)bytes numberOfBytes:(NSUInteger)numberOfBytes;
|
||||||
|
/// Will stop the sax parser from processing any further. @c saxParserDidReachEndOfDocument: will not be called.
|
||||||
- (void)cancel;
|
- (void)cancel;
|
||||||
|
/**
|
||||||
|
Delegate can call from @c XMLStartElement.
|
||||||
|
Characters will be available in @c XMLEndElement as @c currentCharacters property.
|
||||||
|
Storing characters is stopped after each @c XMLEndElement.
|
||||||
|
*/
|
||||||
- (void)beginStoringCharacters;
|
- (void)beginStoringCharacters;
|
||||||
|
|
||||||
|
/// Delegate can call from within @c XMLStartElement. Returns @c nil if @c numberOfAttributes @c < @c 1 .
|
||||||
- (NSDictionary *)attributesDictionary:(const unsigned char **)attributes numberOfAttributes:(NSInteger)numberOfAttributes;
|
- (NSDictionary *)attributesDictionary:(const unsigned char **)attributes numberOfAttributes:(NSInteger)numberOfAttributes;
|
||||||
|
/// Delegate can call from within @c XMLStartElement. Returns @c nil if @c attributes is @c nil .
|
||||||
- (NSDictionary *)attributesDictionaryHTML:(const unsigned char **)attributes;
|
- (NSDictionary *)attributesDictionaryHTML:(const unsigned char **)attributes;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -94,9 +94,7 @@ const NSErrorDomain kLIBXMLParserErrorDomain = @"LIBXMLParserErrorDomain";
|
|||||||
|
|
||||||
static xmlSAXHandler saxHandlerStruct;
|
static xmlSAXHandler saxHandlerStruct;
|
||||||
|
|
||||||
/**
|
// docref in header
|
||||||
Initialize new xml or html parser context and start processing of data.
|
|
||||||
*/
|
|
||||||
- (void)parseBytes:(const void *)bytes numberOfBytes:(NSUInteger)numberOfBytes {
|
- (void)parseBytes:(const void *)bytes numberOfBytes:(NSUInteger)numberOfBytes {
|
||||||
|
|
||||||
_parsingError = nil;
|
_parsingError = nil;
|
||||||
@@ -145,18 +143,14 @@ static xmlSAXHandler saxHandlerStruct;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Will stop the sax parser from processing any further. @c saxParserDidReachEndOfDocument: will not be called.
|
// docref in header
|
||||||
- (void)cancel {
|
- (void)cancel {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
xmlStopParser(self.context);
|
xmlStopParser(self.context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// docref in header
|
||||||
Delegate can call from @c XMLStartElement.
|
|
||||||
Characters will be available in @c XMLEndElement as @c currentCharacters property.
|
|
||||||
Storing characters is stopped after each @c XMLEndElement.
|
|
||||||
*/
|
|
||||||
- (void)beginStoringCharacters {
|
- (void)beginStoringCharacters {
|
||||||
self.storingCharacters = YES;
|
self.storingCharacters = YES;
|
||||||
self.characters = [NSMutableData new];
|
self.characters = [NSMutableData new];
|
||||||
@@ -194,9 +188,7 @@ static xmlSAXHandler saxHandlerStruct;
|
|||||||
#pragma mark - Attributes Dictionary
|
#pragma mark - Attributes Dictionary
|
||||||
|
|
||||||
|
|
||||||
/**
|
// docref in header
|
||||||
Delegate can call from within @c XMLStartElement. Returns @c nil if @c numberOfAttributes @c < @c 1.
|
|
||||||
*/
|
|
||||||
- (NSDictionary *)attributesDictionary:(const xmlChar **)attributes numberOfAttributes:(NSInteger)numberOfAttributes {
|
- (NSDictionary *)attributesDictionary:(const xmlChar **)attributes numberOfAttributes:(NSInteger)numberOfAttributes {
|
||||||
|
|
||||||
if (numberOfAttributes < 1 || !attributes) {
|
if (numberOfAttributes < 1 || !attributes) {
|
||||||
@@ -240,9 +232,7 @@ static xmlSAXHandler saxHandlerStruct;
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// docref in header
|
||||||
Delegate can call from within @c XMLStartElement. Returns @c nil if @c numberOfAttributes @c < @c 1.
|
|
||||||
*/
|
|
||||||
- (NSDictionary *)attributesDictionaryHTML:(const xmlChar **)attributes {
|
- (NSDictionary *)attributesDictionaryHTML:(const xmlChar **)attributes {
|
||||||
|
|
||||||
if (!attributes) {
|
if (!attributes) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
@class RSXMLParser;
|
@class RSXMLParser;
|
||||||
|
|
||||||
|
/// Wrapper class for xml data. Returns the designated parser for any given xml data.
|
||||||
@interface RSXMLData <__covariant T : RSXMLParser *> : NSObject
|
@interface RSXMLData <__covariant T : RSXMLParser *> : NSObject
|
||||||
@property (nonatomic, readonly, nonnull) NSURL *url;
|
@property (nonatomic, readonly, nonnull) NSURL *url;
|
||||||
@property (nonatomic, readonly, nullable) NSData *data;
|
@property (nonatomic, readonly, nullable) NSData *data;
|
||||||
@@ -35,7 +36,9 @@
|
|||||||
|
|
||||||
- (instancetype)initWithData:(NSData * _Nonnull)data url:(NSURL * _Nonnull)url;
|
- (instancetype)initWithData:(NSData * _Nonnull)data url:(NSURL * _Nonnull)url;
|
||||||
|
|
||||||
|
/// @return Kind of @c RSXMLParser or @c nil if no suitable parser found.
|
||||||
- (T _Nullable)getParser;
|
- (T _Nullable)getParser;
|
||||||
|
/// @return @c YES if any parser, regardless of type, is suitable.
|
||||||
- (BOOL)canParseData;
|
- (BOOL)canParseData;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -195,12 +195,12 @@ static const NSUInteger numberOfCharactersToSearch = 4096;
|
|||||||
#pragma mark - Check Methods to Determine Parser Type
|
#pragma mark - Check Methods to Determine Parser Type
|
||||||
|
|
||||||
|
|
||||||
/// @return Kind of @c RSXMLParser or @c nil if no suitable parser found.
|
// docref in header
|
||||||
- (id)getParser {
|
- (id)getParser {
|
||||||
return [_parserClass parserWithXMLData:self];
|
return [_parserClass parserWithXMLData:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return @c YES if any parser, regardless of type, is suitable.
|
// docref in header
|
||||||
- (BOOL)canParseData {
|
- (BOOL)canParseData {
|
||||||
return (_parserClass != nil && _parserError == nil);
|
return (_parserClass != nil && _parserError == nil);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,9 @@
|
|||||||
|
|
||||||
@class RSXMLData;
|
@class RSXMLData;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// | MARK: - Parser Delegate
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
@protocol RSXMLParserDelegate <NSObject>
|
@protocol RSXMLParserDelegate <NSObject>
|
||||||
@optional
|
@optional
|
||||||
@@ -56,14 +59,34 @@
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// | MARK: - Parser
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
Generic wrapper class for @c libxml parsing.
|
||||||
|
Could be one of @c RSRSSParser, @c RSAtomParser, @c RSOPMLParser, @c RSHTMLMetadataParser, and @c RSHTMLLinkParser
|
||||||
|
*/
|
||||||
@interface RSXMLParser<__covariant T> : NSObject <RSXMLParserDelegate, RSSAXParserDelegate>
|
@interface RSXMLParser<__covariant T> : NSObject <RSXMLParserDelegate, RSSAXParserDelegate>
|
||||||
@property (nonatomic, readonly, nonnull, copy) NSURL *documentURI;
|
@property (nonatomic, readonly, nonnull, copy) NSURL *documentURI;
|
||||||
@property (nonatomic, assign) BOOL dontStopOnLowerAsciiBytes;
|
@property (nonatomic, assign) BOOL dontStopOnLowerAsciiBytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Designated initializer. Runs a check whether it matches the detected parser in @c RSXMLData.
|
||||||
|
Keeps an internal pointer to the @c RSXMLData and initializes a new @c RSSAXParser.
|
||||||
|
*/
|
||||||
+ (instancetype)parserWithXMLData:(RSXMLData * _Nonnull)xmlData;
|
+ (instancetype)parserWithXMLData:(RSXMLData * _Nonnull)xmlData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Parse the XML data on whatever thread this method is called.
|
||||||
|
|
||||||
|
@param error Sets @c error if parser gets unrecognized data or @c libxml runs into a parsing error.
|
||||||
|
@return The parsed object. The object type depends on the underlying data. @c RSParsedFeed, @c RSOPMLItem or @c RSHTMLMetadata.
|
||||||
|
*/
|
||||||
- (T _Nullable)parseSync:(NSError ** _Nullable)error;
|
- (T _Nullable)parseSync:(NSError ** _Nullable)error;
|
||||||
|
/// Dispatch new background thread, parse the data synchroniously on the background thread and exec callback on the main thread.
|
||||||
- (void)parseAsync:(void(^)(T _Nullable parsedDocument, NSError * _Nullable error))block;
|
- (void)parseAsync:(void(^)(T _Nullable parsedDocument, NSError * _Nullable error))block;
|
||||||
|
/// @return @c YES if @c .xmlInputError is @c nil.
|
||||||
- (BOOL)canParse;
|
- (BOOL)canParse;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -39,10 +39,7 @@
|
|||||||
+ (BOOL)isHTMLParser { return NO; } // override
|
+ (BOOL)isHTMLParser { return NO; } // override
|
||||||
- (id)xmlParserWillReturnDocument { return nil; } // override
|
- (id)xmlParserWillReturnDocument { return nil; } // override
|
||||||
|
|
||||||
/**
|
// docref in header
|
||||||
Designated initializer. Runs a check whether it matches the detected parser in @c RSXMLData.
|
|
||||||
Keeps an internal pointer to the @c RSXMLData and initializes a new @c RSSAXParser.
|
|
||||||
*/
|
|
||||||
+ (instancetype)parserWithXMLData:(nonnull RSXMLData *)xmlData {
|
+ (instancetype)parserWithXMLData:(nonnull RSXMLData *)xmlData {
|
||||||
if ([xmlData.parserClass isSubclassOfClass:[super class]]) {
|
if ([xmlData.parserClass isSubclassOfClass:[super class]]) {
|
||||||
return [[xmlData.parserClass alloc] initWithXMLData:xmlData];
|
return [[xmlData.parserClass alloc] initWithXMLData:xmlData];
|
||||||
@@ -85,12 +82,7 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// docref in header
|
||||||
Parse the XML data on whatever thread this method is called.
|
|
||||||
|
|
||||||
@param error Sets @c error if parser gets unrecognized data or libxml runs into a parsing error.
|
|
||||||
@return The parsed object. The object type depends on the underlying data. @c RSParsedFeed, @c RSOPMLItem or @c RSHTMLMetadata.
|
|
||||||
*/
|
|
||||||
- (id _Nullable)parseSync:(NSError **)error {
|
- (id _Nullable)parseSync:(NSError **)error {
|
||||||
if (_xmlInputError) {
|
if (_xmlInputError) {
|
||||||
if (error) *error = _xmlInputError;
|
if (error) *error = _xmlInputError;
|
||||||
@@ -109,9 +101,7 @@
|
|||||||
return [self xmlParserWillReturnDocument];
|
return [self xmlParserWillReturnDocument];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// docref in header
|
||||||
Dispatch new background thread, parse the data synchroniously on the background thread and exec callback on the main thread.
|
|
||||||
*/
|
|
||||||
- (void)parseAsync:(void(^)(id parsedDocument, NSError *error))block {
|
- (void)parseAsync:(void(^)(id parsedDocument, NSError *error))block {
|
||||||
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{ // QOS_CLASS_DEFAULT
|
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{ // QOS_CLASS_DEFAULT
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
@@ -124,7 +114,7 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return @c YES if @c .xmlInputError is @c nil.
|
// docref in header
|
||||||
- (BOOL)canParse {
|
- (BOOL)canParse {
|
||||||
return (self.xmlInputError == nil);
|
return (self.xmlInputError == nil);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,9 +42,8 @@
|
|||||||
return [[RSXMLData alloc] initWithData:d url:[NSURL fileURLWithPath:s]];
|
return [[RSXMLData alloc] initWithData:d url:[NSURL fileURLWithPath:s]];
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TARGET_MAC
|
|
||||||
|
|
||||||
- (void)testOPMLExport {
|
- (void)testOPMLExport {
|
||||||
|
#if OPML_EXPORT
|
||||||
RSOPMLItem *doc = [RSOPMLItem itemWithAttributes:@{OPMLTitleKey : @"Greetings from CCC",
|
RSOPMLItem *doc = [RSOPMLItem itemWithAttributes:@{OPMLTitleKey : @"Greetings from CCC",
|
||||||
@"dateCreated" : @"2018-12-27 23:12:04 +0100",
|
@"dateCreated" : @"2018-12-27 23:12:04 +0100",
|
||||||
@"ownerName" : @"RSXML Parser"}];
|
@"ownerName" : @"RSXML Parser"}];
|
||||||
@@ -76,9 +75,11 @@
|
|||||||
XCTAssertEqualObjects([document.children.lastObject attributeForKey:OPMLXMLURLKey], @"http://www.feed2.com/feed.atom");
|
XCTAssertEqualObjects([document.children.lastObject attributeForKey:OPMLXMLURLKey], @"http://www.feed2.com/feed.atom");
|
||||||
|
|
||||||
NSLog(@"%@", [document recursiveDescription]);
|
NSLog(@"%@", [document recursiveDescription]);
|
||||||
}
|
#else
|
||||||
|
NSLog(@"OPML export is disabled for this framework!");
|
||||||
|
XCTAssertNil(nil);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
- (void)testNotOPML {
|
- (void)testNotOPML {
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>FMWK</string>
|
<string>FMWK</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0</string>
|
<string>2.0.0</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
|
|||||||
Reference in New Issue
Block a user