v2.0.0 release; move all docref to header + optional NSXML

This commit is contained in:
relikd
2019-09-14 14:58:11 +02:00
parent ea7cc9c36f
commit 631ddc9064
25 changed files with 108 additions and 83 deletions

View File

@@ -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";

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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];
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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"];

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

@@ -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

View File

@@ -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

View File

@@ -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;
} }

View File

@@ -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

View File

@@ -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];

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

@@ -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

View File

@@ -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);
} }

View File

@@ -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

View File

@@ -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);
} }

View File

@@ -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 {

View File

@@ -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>