From 111acb4f8fd2e860657f3c10388b3f47ef394acb Mon Sep 17 00:00:00 2001 From: iska Date: Wed, 20 May 2015 22:39:52 +0200 Subject: [PATCH 01/40] Add a convenience HTML Document initializer Creates a document directly given a HTML string, instead of manually creating a parser. --- HTMLKit/HTMLDocument.h | 2 ++ HTMLKit/HTMLDocument.m | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/HTMLKit/HTMLDocument.h b/HTMLKit/HTMLDocument.h index ddcec2b..7c0655f 100644 --- a/HTMLKit/HTMLDocument.h +++ b/HTMLKit/HTMLDocument.h @@ -27,6 +27,8 @@ typedef NS_ENUM(short, HTMLDocumentReadyState) @property (nonatomic, assign, readonly) HTMLDocumentReadyState readyState; ++ (instancetype)documentWithString:(NSString *)string; + - (HTMLNode *)adoptNode:(HTMLNode *)node; - (HTMLDocument *)associatedInertTemplateDocument; diff --git a/HTMLKit/HTMLDocument.m b/HTMLKit/HTMLDocument.m index 11e2a42..8a5329f 100644 --- a/HTMLKit/HTMLDocument.m +++ b/HTMLKit/HTMLDocument.m @@ -7,6 +7,7 @@ // #import "HTMLDocument.h" +#import "HTMLParser.h" #import "HTMLKitExceptions.h" @interface HTMLNode (Private) @@ -25,6 +26,12 @@ #pragma mark - Init ++ (instancetype)documentWithString:(NSString *)string +{ + HTMLParser *parser = [[HTMLParser alloc] initWithString:string]; + return [parser parseDocument]; +} + - (instancetype)init { self = [super initWithName:@"#document" type:HTMLNodeDocument]; From 74aec5778536420c8071cfdd996a73b182294680 Mon Sep 17 00:00:00 2001 From: iska Date: Thu, 21 May 2015 00:20:20 +0200 Subject: [PATCH 02/40] Add method to set inner HTML of an Element --- HTMLKit/HTMLElement.m | 9 +++++++++ HTMLKit/HTMLNode.h | 10 ++++++---- HTMLKit/HTMLNode.m | 12 ++++++++++++ HTMLKitTests/HTMLKitNodesTests.m | 13 +++++++++++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/HTMLKit/HTMLElement.m b/HTMLKit/HTMLElement.m index e12b5f7..11f0138 100644 --- a/HTMLKit/HTMLElement.m +++ b/HTMLKit/HTMLElement.m @@ -7,6 +7,7 @@ // #import "HTMLElement.h" +#import "HTMLParser.h" #import "HTMLDocument.h" #import "HTMLText.h" @@ -101,6 +102,14 @@ [self replaceAllChildNodesWithNode:node]; } +- (void)setInnerHTML:(NSString *)innerHTML +{ + HTMLParser *parser = [[HTMLParser alloc] initWithString:innerHTML]; + NSArray *fragmentNodes = [parser parseFragmentWithContextElement:self]; + [self removeAllChildNodes]; + [self appendNodes:fragmentNodes]; +} + #pragma mark - NSCopying - (id)copyWithZone:(NSZone *)zone diff --git a/HTMLKit/HTMLNode.h b/HTMLKit/HTMLNode.h index 332fb4f..f0d4c25 100644 --- a/HTMLKit/HTMLNode.h +++ b/HTMLKit/HTMLNode.h @@ -53,10 +53,16 @@ typedef NS_ENUM(short, HTMLNodeType) @property (nonatomic, copy) NSString *textContent; +@property (nonatomic, strong, readonly) NSString *outerHTML; + +@property (nonatomic, copy) NSString *innerHTML; + - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithName:(NSString *)name type:(HTMLNodeType)type; +- (HTMLElement *)asElement; + - (BOOL)hasChildNodes; - (BOOL)hasChildNodeOfType:(HTMLNodeType)type; @@ -97,10 +103,6 @@ typedef NS_ENUM(short, HTMLNodeType) - (NSEnumerator *)reverseTreeEnumerator; -- (NSString *)outerHTML; - -- (NSString *)innerHTML; - - (NSString *)treeDescription; @end diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index 470cc15..cc4f739 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -104,6 +104,13 @@ return nil; } +#pragma mark - Cast + +- (HTMLElement *)asElement +{ + return (HTMLElement *)self; +} + #pragma mark - Child Nodes - (BOOL)hasChildNodes @@ -471,6 +478,11 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin return [[self.childNodes.array valueForKey:@"outerHTML"] componentsJoinedByString:@""]; } +- (void)setInnerHTML:(NSString *)outerHTML +{ + [self doesNotRecognizeSelector:_cmd]; +} + #pragma mark - Description - (NSString *)treeDescription diff --git a/HTMLKitTests/HTMLKitNodesTests.m b/HTMLKitTests/HTMLKitNodesTests.m index e2b65cc..5bb051a 100644 --- a/HTMLKitTests/HTMLKitNodesTests.m +++ b/HTMLKitTests/HTMLKitNodesTests.m @@ -470,4 +470,17 @@ XCTAssertEqualObjects(thirdChild.parentNode, newParent); } +- (void)testElementSetInnerHTML +{ + HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"]; + [element appendNode:[[HTMLElement alloc] initWithTagName:@"img"]]; + + [element setInnerHTML:@"

"]; + + XCTAssertEqual(element.childNodesCount, 2); + + XCTAssertEqualObjects(element.firstChiledNode.asElement.tagName, @"p"); + XCTAssertEqualObjects([element childNodeAtIndex:1].asElement.tagName, @"p"); +} + @end From 1e9118078f655d1f07e6b61c426a13ad4b0680cf Mon Sep 17 00:00:00 2001 From: iska Date: Thu, 21 May 2015 23:24:13 +0200 Subject: [PATCH 03/40] Rename Nodes group to DOM --- HTMLKit.xcodeproj/project.pbxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index e00d8ff..bcc70a6 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -313,7 +313,7 @@ name = Tokenizer; sourceTree = ""; }; - 623719441AA1472B002E03C8 /* Nodes */ = { + 623719441AA1472B002E03C8 /* DOM */ = { isa = PBXGroup; children = ( 623719431AA12EE8002E03C8 /* HTMLQuirksMode.h */, @@ -337,7 +337,7 @@ 623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */, 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */, ); - name = Nodes; + name = DOM; sourceTree = ""; }; 623975581AC362A5007E26F1 /* Tree Construction */ = { @@ -421,7 +421,7 @@ 6238C9841AB8D6330006512E /* HTMLKitExceptions.m */, 62AE593219F97CCA0043F069 /* Tokenizing */, 628E16EC1ADAE71700B15A06 /* Parsing */, - 623719441AA1472B002E03C8 /* Nodes */, + 623719441AA1472B002E03C8 /* DOM */, 628E16ED1ADAE73700B15A06 /* Categories */, 628E16EE1ADAE75300B15A06 /* Structures */, 625A14B619C7829400AD0C32 /* Supporting Files */, From 2ee3b2d2b3e763c741703f87b50f29c6eb8089c2 Mon Sep 17 00:00:00 2001 From: iska Date: Fri, 22 May 2015 20:06:24 +0200 Subject: [PATCH 04/40] Rename HTMLNode header to HTMLDOM --- HTMLKit.xcodeproj/project.pbxproj | 10 +++++----- HTMLKit/{HTMLNodes.h => HTMLDOM.h} | 0 2 files changed, 5 insertions(+), 5 deletions(-) rename HTMLKit/{HTMLNodes.h => HTMLDOM.h} (100%) diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index bcc70a6..8490df7 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -118,7 +118,7 @@ 62AE594B19F9948A0043F069 /* HTMLCharacterToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 62AE594819F9948A0043F069 /* HTMLCharacterToken.m */; }; 62D8345919FB1AC4009205A9 /* HTML5LibTokenizerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 62D8345819FB1AC4009205A9 /* HTML5LibTokenizerTest.m */; }; 62D8345A19FB1AC4009205A9 /* HTML5LibTokenizerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 62D8345819FB1AC4009205A9 /* HTML5LibTokenizerTest.m */; }; - 62D89DB01AE7080300B6243D /* HTMLNodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 62362A3F1A9FDE8A00301989 /* HTMLNodes.h */; }; + 62D89DB01AE7080300B6243D /* HTMLDOM.h in Headers */ = {isa = PBXBuildFile; fileRef = 62362A3F1A9FDE8A00301989 /* HTMLDOM.h */; }; 62D89DB11AE7081600B6243D /* HTMLTokenizerStates.h in Headers */ = {isa = PBXBuildFile; fileRef = 624493A919CCE84A00BCDDF4 /* HTMLTokenizerStates.h */; }; 62D89DB21AE7081600B6243D /* HTMLTokenizerCharacters.h in Headers */ = {isa = PBXBuildFile; fileRef = 62E7CAAE19CDFFB500465A83 /* HTMLTokenizerCharacters.h */; }; 62D89DB31AE7081600B6243D /* HTMLNamespaces.h in Headers */ = {isa = PBXBuildFile; fileRef = 628B7CE61A080E1000602C87 /* HTMLNamespaces.h */; }; @@ -185,7 +185,7 @@ 6235CE9F1AA5170A0026937B /* HTMLMarker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLMarker.m; sourceTree = ""; }; 62362A3A1A9FA70400301989 /* HTMLText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLText.h; sourceTree = ""; }; 62362A3B1A9FA70400301989 /* HTMLText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLText.m; sourceTree = ""; }; - 62362A3F1A9FDE8A00301989 /* HTMLNodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLNodes.h; sourceTree = ""; }; + 62362A3F1A9FDE8A00301989 /* HTMLDOM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLDOM.h; sourceTree = ""; }; 62363C3B1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLListOfActiveFormattingElements.h; sourceTree = ""; }; 62363C3C1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLListOfActiveFormattingElements.m; sourceTree = ""; }; 6236738D1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTokenizerPerformance.m; sourceTree = ""; }; @@ -316,8 +316,7 @@ 623719441AA1472B002E03C8 /* DOM */ = { isa = PBXGroup; children = ( - 623719431AA12EE8002E03C8 /* HTMLQuirksMode.h */, - 62362A3F1A9FDE8A00301989 /* HTMLNodes.h */, + 62362A3F1A9FDE8A00301989 /* HTMLDOM.h */, 6234584C1A9D2FA4009BD491 /* HTMLNode.h */, 6234584D1A9D2FA4009BD491 /* HTMLNode.m */, 6279F87219E1808D00F12EE5 /* HTMLElement.h */, @@ -336,6 +335,7 @@ 623406E51ADB05AD004677A3 /* HTMLDocumentFragment.m */, 623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */, 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */, + 623719431AA12EE8002E03C8 /* HTMLQuirksMode.h */, ); name = DOM; sourceTree = ""; @@ -546,7 +546,7 @@ 62D89DB51AE7081600B6243D /* HTMLElementAdjustment.h in Headers */, 62D89DB61AE7081600B6243D /* HTMLParserInsertionModes.h in Headers */, 62D89DB71AE7081600B6243D /* HTMLQuirksMode.h in Headers */, - 62D89DB01AE7080300B6243D /* HTMLNodes.h in Headers */, + 62D89DB01AE7080300B6243D /* HTMLDOM.h in Headers */, 62F873EB19E088C90062683C /* HTMLParser.h in Headers */, 624AC8FF19FBF59800BD3C4A /* HTMLTokens.h in Headers */, 623916C31AC707250066B4FE /* HTMLNodeTreeEnumerator.h in Headers */, diff --git a/HTMLKit/HTMLNodes.h b/HTMLKit/HTMLDOM.h similarity index 100% rename from HTMLKit/HTMLNodes.h rename to HTMLKit/HTMLDOM.h From 11af0509a3efe958c68d6de86b04e6ef195f5718 Mon Sep 17 00:00:00 2001 From: iska Date: Wed, 27 May 2015 00:33:09 +0200 Subject: [PATCH 05/40] Rename type property to nodeType in HTMLNode for better clarity --- HTMLKit/HTMLDOM.h | 2 +- HTMLKit/HTMLDocument.m | 2 +- HTMLKit/HTMLDocumentFragment.m | 2 +- HTMLKit/HTMLElement.m | 4 +- HTMLKit/HTMLNode.h | 2 +- HTMLKit/HTMLNode.m | 60 ++++++++++----------- HTMLKit/HTMLParser.m | 8 +-- HTMLKitTests/HTMLKitNodesTests.m | 2 +- HTMLKitTests/HTMLKitTreeConstructionTests.m | 10 ++-- 9 files changed, 46 insertions(+), 46 deletions(-) diff --git a/HTMLKit/HTMLDOM.h b/HTMLKit/HTMLDOM.h index f0ffa0e..4e9d5ce 100644 --- a/HTMLKit/HTMLDOM.h +++ b/HTMLKit/HTMLDOM.h @@ -9,8 +9,8 @@ #import "HTMLNode.h" #import "HTMLDocument.h" #import "HTMLDocumentType.h" +#import "HTMLDocumentFragment.h" #import "HTMLElement.h" #import "HTMLComment.h" #import "HTMLText.h" #import "HTMLTemplate.h" -#import "HTMLDocumentFragment.h" diff --git a/HTMLKit/HTMLDocument.m b/HTMLKit/HTMLDocument.m index 8a5329f..7ae4e68 100644 --- a/HTMLKit/HTMLDocument.m +++ b/HTMLKit/HTMLDocument.m @@ -72,7 +72,7 @@ return nil; } - if (node.type == HTMLNodeDocument) { + if (node.nodeType == HTMLNodeDocument) { [NSException raise:HTMLKitNotSupportedError format:@"%@: Not Fount Error, adopting a document node. The operation is not supported.", NSStringFromSelector(_cmd)]; } diff --git a/HTMLKit/HTMLDocumentFragment.m b/HTMLKit/HTMLDocumentFragment.m index 6b549a8..adcde5e 100644 --- a/HTMLKit/HTMLDocumentFragment.m +++ b/HTMLKit/HTMLDocumentFragment.m @@ -33,7 +33,7 @@ { NSMutableString *content = [NSMutableString string]; for (HTMLNode *node in self.treeEnumerator) { - if (node.type == HTMLNodeText) { + if (node.nodeType == HTMLNodeText) { [content appendString:[(HTMLText *)node data]]; } } diff --git a/HTMLKit/HTMLElement.m b/HTMLKit/HTMLElement.m index 11f0138..8e9a18f 100644 --- a/HTMLKit/HTMLElement.m +++ b/HTMLKit/HTMLElement.m @@ -89,7 +89,7 @@ { NSMutableString *content = [NSMutableString string]; for (HTMLNode *node in self.treeEnumerator) { - if (node.type == HTMLNodeText) { + if (node.nodeType == HTMLNodeText) { [content appendString:[(HTMLText *)node data]]; } } @@ -146,7 +146,7 @@ return result; } - if ([self.tagName isEqualToAny:@"pre", @"textarea", @"listing", nil] && self.firstChiledNode.type == HTMLNodeText) { + if ([self.tagName isEqualToAny:@"pre", @"textarea", @"listing", nil] && self.firstChiledNode.nodeType == HTMLNodeText) { HTMLText *textNode = (HTMLText *)self.firstChiledNode; if ([textNode.data hasPrefix:@"\n"]) { [result appendString:@"\n"]; diff --git a/HTMLKit/HTMLNode.h b/HTMLKit/HTMLNode.h index f0d4c25..3c60f57 100644 --- a/HTMLKit/HTMLNode.h +++ b/HTMLKit/HTMLNode.h @@ -29,7 +29,7 @@ typedef NS_ENUM(short, HTMLNodeType) @interface HTMLNode : NSObject -@property (nonatomic, assign, readonly) HTMLNodeType type; +@property (nonatomic, assign, readonly) HTMLNodeType nodeType; @property (nonatomic, strong, readonly) NSString *name; diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index cc4f739..f0060f5 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -32,7 +32,7 @@ self = [super init]; if (self) { _name = name; - _type = type; + _nodeType = type; _childNodes = [NSMutableOrderedSet new]; } return self; @@ -42,7 +42,7 @@ - (HTMLDocument *)ownerDocument { - if (_type == HTMLNodeDocument) { + if (_nodeType == HTMLNodeDocument) { return (HTMLDocument *)self; } else { return _ownerDocument; @@ -68,7 +68,7 @@ - (HTMLElement *)parentElement { - return _parentNode.type == HTMLNodeElement ? (HTMLElement *)_parentNode : nil; + return _parentNode.nodeType == HTMLNodeElement ? (HTMLElement *)_parentNode : nil; } - (HTMLNode *)firstChiledNode @@ -121,7 +121,7 @@ - (BOOL)hasChildNodeOfType:(HTMLNodeType)type { NSUInteger index = [self.childNodes indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { - if ([(HTMLNode *)obj type] == type) { + if ([(HTMLNode *)obj nodeType] == type) { *stop = YES; return YES; } @@ -178,7 +178,7 @@ [self.ownerDocument adoptNode:node]; - NSArray *nodes = node.type == HTMLNodeDocumentFragment ? [NSArray arrayWithArray:node.childNodes.array] : @[node]; + NSArray *nodes = node.nodeType == HTMLNodeDocumentFragment ? [NSArray arrayWithArray:node.childNodes.array] : @[node]; NSUInteger index = [self indexOfChildNode:child]; if (index != NSNotFound) { @@ -188,7 +188,7 @@ [(NSMutableOrderedSet *)self.childNodes addObjectsFromArray:nodes]; } - if (node.type == HTMLNodeDocumentFragment) { + if (node.nodeType == HTMLNodeDocumentFragment) { [node removeAllChildNodes]; } @@ -281,7 +281,7 @@ - (void)doInsertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child { - NSArray *nodes = node.type == HTMLNodeDocumentFragment ? node.childNodes.array : @[node]; + NSArray *nodes = node.nodeType == HTMLNodeDocumentFragment ? node.childNodes.array : @[node]; NSUInteger index = [self indexOfChildNode:child]; if (index != NSNotFound) { @@ -298,9 +298,9 @@ NS_INLINE void CheckParentValid(HTMLNode *parent, NSString *cmd) { - if (parent.type != HTMLNodeDocument && - parent.type != HTMLNodeDocumentFragment && - parent.type != HTMLNodeElement) { + if (parent.nodeType != HTMLNodeDocument && + parent.nodeType != HTMLNodeDocumentFragment && + parent.nodeType != HTMLNodeElement) { [NSException raise:HTMLKitHierarchyRequestError format:@"%@: Hierarchy Request Error, inserting into %@ is not allowed. The operation would yield an incorrect node tree.", cmd, parent.name]; @@ -319,11 +319,11 @@ NS_INLINE void CheckChildsParent(HTMLNode *parent, HTMLNode *child, NSString *cm NS_INLINE void CheckInsertedNodeValid(HTMLNode *node, NSString *cmd) { - if (node.type != HTMLNodeDocumentFragment && - node.type != HTMLNodeDocumentType && - node.type != HTMLNodeElement && - node.type != HTMLNodeText && - node.type != HTMLNodeComment) { + if (node.nodeType != HTMLNodeDocumentFragment && + node.nodeType != HTMLNodeDocumentType && + node.nodeType != HTMLNodeElement && + node.nodeType != HTMLNodeText && + node.nodeType != HTMLNodeComment) { [NSException raise:HTMLKitHierarchyRequestError format:@"%@: Hierarchy Request Error, inserting a %@ is not allowed. The operation would yield an incorrect node tree.", cmd, node.name]; @@ -332,13 +332,13 @@ NS_INLINE void CheckInsertedNodeValid(HTMLNode *node, NSString *cmd) NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSString *cmd) { - if (node.type == HTMLNodeText && parent.type == HTMLNodeDocument) { + if (node.nodeType == HTMLNodeText && parent.nodeType == HTMLNodeDocument) { [NSException raise:HTMLKitHierarchyRequestError format:@"%@: Hierarchy Request Error, inserting a text node %@ into docuement is not allowed. The operation would yield an incorrect node tree.", cmd, parent.name]; } - if (node.type == HTMLNodeDocumentType && parent.type != HTMLNodeDocument) { + if (node.nodeType == HTMLNodeDocumentType && parent.nodeType != HTMLNodeDocument) { [NSException raise:HTMLKitHierarchyRequestError format:@"%@: Hierarchy Request Error, inserting a doctype %@ into a non-document node is not allowed. The operation would yield an incorrect node tree.", cmd, parent.name]; @@ -361,24 +361,24 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin NSStringFromSelector(_cmd), self, node]; }; - if (self.type == HTMLNodeDocument) { - switch (node.type) { + if (self.nodeType == HTMLNodeDocument) { + switch (node.nodeType) { case HTMLNodeDocumentFragment: if (node.childNodesCount > 1 || [node hasChildNodeOfType:HTMLNodeText]) { hierarchyError(); } else if (node.childNodesCount == 1) { if ([self hasChildNodeOfType:HTMLNodeElement] || - child.type == HTMLNodeDocumentType || - child.nextSibling.type == HTMLNodeDocumentType) { + child.nodeType == HTMLNodeDocumentType || + child.nextSibling.nodeType == HTMLNodeDocumentType) { hierarchyError(); } } break; case HTMLNodeElement: if ([self hasChildNodeOfType:HTMLNodeElement] || - child.type == HTMLNodeDocumentType || - (child != nil && child.nextSibling.type == HTMLNodeDocumentType)) { + child.nodeType == HTMLNodeDocumentType || + (child != nil && child.nextSibling.nodeType == HTMLNodeDocumentType)) { hierarchyError(); } break; @@ -413,21 +413,21 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin void (^ checkParentHasAnotherChildOfType)(HTMLNodeType) = ^ void (HTMLNodeType type) { [self enumerateChildNodesUsingBlock:^(HTMLNode *node, NSUInteger idx, BOOL *stop) { - if (node.type == type && node != child) { + if (node.nodeType == type && node != child) { *stop = YES; hierarchyError(); } }]; }; - if (self.type == HTMLNodeDocument) { - switch (node.type) { + if (self.nodeType == HTMLNodeDocument) { + switch (node.nodeType) { case HTMLNodeDocumentFragment: if (node.childNodesCount > 1 || [node hasChildNodeOfType:HTMLNodeText]) { hierarchyError(); } else if (node.childNodesCount == 1) { - if (child.nextSibling.type == HTMLNodeDocumentType) { + if (child.nextSibling.nodeType == HTMLNodeDocumentType) { hierarchyError(); } checkParentHasAnotherChildOfType(HTMLNodeElement); @@ -435,7 +435,7 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin break; case HTMLNodeElement: { - if (child.nextSibling.type == HTMLNodeDocumentType) { + if (child.nextSibling.nodeType == HTMLNodeDocumentType) { hierarchyError(); } checkParentHasAnotherChildOfType(HTMLNodeElement); @@ -443,7 +443,7 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin } case HTMLNodeDocumentType: { - if (child.previousSibling.type == HTMLNodeElement) { + if (child.previousSibling.nodeType == HTMLNodeElement) { hierarchyError(); } checkParentHasAnotherChildOfType(HTMLNodeDocumentType); @@ -461,7 +461,7 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin - (id)copyWithZone:(NSZone *)zone { - HTMLNode *copy = [[self.class alloc] initWithName:self.name type:self.type]; + HTMLNode *copy = [[self.class alloc] initWithName:self.name type:self.nodeType]; return copy; } diff --git a/HTMLKit/HTMLParser.m b/HTMLKit/HTMLParser.m index f5f0ed5..539ce36 100644 --- a/HTMLKit/HTMLParser.m +++ b/HTMLKit/HTMLParser.m @@ -12,7 +12,7 @@ #import "HTMLStackOfOpenElements.h" #import "HTMLListOfActiveFormattingElements.h" #import "HTMLParserInsertionModes.h" -#import "HTMLNodes.h" +#import "HTMLDOM.h" #import "HTMLElementTypes.h" #import "HTMLElementAdjustment.h" #import "HTMLMarker.h" @@ -452,10 +452,10 @@ HTMLElement *child = nil; HTMLNode *adjustedInsertionLocation = [self appropriatePlaceForInsertingANodeWithOverrideTarget:nil beforeChildNode:&child]; - if (adjustedInsertionLocation.type != HTMLNodeDocument) { - if (child != nil && child.previousSibling.type == HTMLNodeText) { + if (adjustedInsertionLocation.nodeType != HTMLNodeDocument) { + if (child != nil && child.previousSibling.nodeType == HTMLNodeText) { [(HTMLText *)child.previousSibling appendString:data]; - } else if (adjustedInsertionLocation.lastChildNode.type == HTMLNodeText) { + } else if (adjustedInsertionLocation.lastChildNode.nodeType == HTMLNodeText) { [(HTMLText *)adjustedInsertionLocation.lastChildNode appendString:data]; } else { HTMLText *text = [[HTMLText alloc] initWithData:data]; diff --git a/HTMLKitTests/HTMLKitNodesTests.m b/HTMLKitTests/HTMLKitNodesTests.m index 5bb051a..8e499de 100644 --- a/HTMLKitTests/HTMLKitNodesTests.m +++ b/HTMLKitTests/HTMLKitNodesTests.m @@ -30,7 +30,7 @@ HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement]; XCTAssertNotNil(node); XCTAssertEqualObjects(node.name, @"name"); - XCTAssertEqual(node.type, HTMLNodeElement); + XCTAssertEqual(node.nodeType, HTMLNodeElement); XCTAssertNotNil(node.childNodes); XCTAssertEqual(node.childNodes.count, 0); diff --git a/HTMLKitTests/HTMLKitTreeConstructionTests.m b/HTMLKitTests/HTMLKitTreeConstructionTests.m index cfb7430..ca1f223 100644 --- a/HTMLKitTests/HTMLKitTreeConstructionTests.m +++ b/HTMLKitTests/HTMLKitTreeConstructionTests.m @@ -9,7 +9,7 @@ #import #import "HTML5LibTreeConstructionTest.h" -#import "HTMLNodes.h" +#import "HTMLDOM.h" #import "HTMLParser.h" @@ -121,14 +121,14 @@ { XCTAssertEqualObjects(actual.name, expected.name, @"Node name mismatch [%@ should be %@]:\n%@", actual.name, expected.name, message); - XCTAssert(actual.type == expected.type, @"Node type mismatch [%hd should be %hd]:\n%@", - actual.type, expected.type, message); + XCTAssert(actual.nodeType == expected.nodeType, @"Node type mismatch [%hd should be %hd]:\n%@", + actual.nodeType, expected.nodeType, message); - if (actual.type != expected.type) { + if (actual.nodeType != expected.nodeType) { return; } - switch (actual.type) { + switch (actual.nodeType) { case HTMLNodeDocumentType: XCTAssertEqualObjects([(HTMLDocumentType *)actual publicIdentifier], [(HTMLDocumentType *)expected publicIdentifier], @"%@", message); XCTAssertEqualObjects([(HTMLDocumentType *)actual systemIdentifier], [(HTMLDocumentType *)expected systemIdentifier], @"%@", message); From 915f4cc064904fa9f3fa92998d6689f081027ddd Mon Sep 17 00:00:00 2001 From: iska Date: Wed, 27 May 2015 00:38:07 +0200 Subject: [PATCH 06/40] Remove baseURI property from HTMLNode Proper support will be implemented when needed. --- HTMLKit/HTMLNode.h | 2 -- HTMLKit/HTMLNode.m | 6 ------ HTMLKitTests/HTMLKitNodesTests.m | 3 +-- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/HTMLKit/HTMLNode.h b/HTMLKit/HTMLNode.h index 3c60f57..916ed3e 100644 --- a/HTMLKit/HTMLNode.h +++ b/HTMLKit/HTMLNode.h @@ -35,8 +35,6 @@ typedef NS_ENUM(short, HTMLNodeType) @property (nonatomic, weak, readonly) HTMLDocument *ownerDocument; -@property (nonatomic, strong, readonly) NSString *baseURI; - @property (nonatomic, weak, readonly) HTMLNode *parentNode; @property (nonatomic, weak, readonly) HTMLElement *parentElement; diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index f0060f5..363424d 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -55,12 +55,6 @@ [self.childNodes.array makeObjectsPerformSelector:@selector(setOwnerDocument:) withObject:ownerDocument]; } -- (void)setBaseURI:(NSString *)baseURI -{ - _baseURI = [baseURI copy]; - [self.childNodes.array makeObjectsPerformSelector:@selector(setBaseURI:) withObject:baseURI]; -} - - (void)setParentNode:(HTMLNode *)parentNode { _parentNode = parentNode; diff --git a/HTMLKitTests/HTMLKitNodesTests.m b/HTMLKitTests/HTMLKitNodesTests.m index 8e499de..524a25c 100644 --- a/HTMLKitTests/HTMLKitNodesTests.m +++ b/HTMLKitTests/HTMLKitNodesTests.m @@ -7,7 +7,7 @@ // #import -#import "HTMLNodes.h" +#import "HTMLDOM.h" @interface HTMLKitNodesTests : XCTestCase @@ -35,7 +35,6 @@ XCTAssertEqual(node.childNodes.count, 0); XCTAssertNil(node.ownerDocument); - XCTAssertNil(node.baseURI); XCTAssertNil(node.parentNode); XCTAssertNil(node.parentElement); XCTAssertNil(node.firstChiledNode); From 470b9b8d3739be4b846a08691e4ff7a981106590 Mon Sep 17 00:00:00 2001 From: iska Date: Wed, 27 May 2015 00:39:39 +0200 Subject: [PATCH 07/40] Change arguments order in HTML Element initializer for convenience Dictionary argument moved to last position. --- HTMLKit/HTMLElement.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HTMLKit/HTMLElement.h b/HTMLKit/HTMLElement.h index 1085162..6343516 100644 --- a/HTMLKit/HTMLElement.h +++ b/HTMLKit/HTMLElement.h @@ -24,7 +24,7 @@ - (instancetype)initWithTagName:(NSString *)tagName; - (instancetype)initWithTagName:(NSString *)tagName attributes:(NSDictionary *)attributes; -- (instancetype)initWithTagName:(NSString *)tagName attributes:(NSDictionary *)attributes namespace:(HTMLNamespace)htmlNamespace; +- (instancetype)initWithTagName:(NSString *)tagName namespace:(HTMLNamespace)htmlNamespace attributes:(NSDictionary *)attributes; - (BOOL)hasAttribute:(NSString *)name; - (NSString *)objectForKeyedSubscript:(NSString *)name; From de597a51a40810eea28971417dd2c6e3877336a8 Mon Sep 17 00:00:00 2001 From: iska Date: Wed, 27 May 2015 00:42:29 +0200 Subject: [PATCH 08/40] Reorganize HTML DOM classes --- HTMLKit.xcodeproj/project.pbxproj | 30 +++++++++---------- HTMLKit/HTMLDocument.m | 2 +- ...KitExceptions.h => HTMLKitDOMExceptions.h} | 0 ...KitExceptions.m => HTMLKitDOMExceptions.m} | 2 +- HTMLKit/HTMLNode.h | 2 ++ HTMLKit/HTMLNode.m | 15 +++++++++- 6 files changed, 33 insertions(+), 18 deletions(-) rename HTMLKit/{HTMLKitExceptions.h => HTMLKitDOMExceptions.h} (100%) rename HTMLKit/{HTMLKitExceptions.m => HTMLKitDOMExceptions.m} (91%) diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index 8490df7..408e504 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -49,9 +49,9 @@ 6238579B1A9E8934003A45D9 /* HTMLComment.h in Headers */ = {isa = PBXBuildFile; fileRef = 623857991A9E8934003A45D9 /* HTMLComment.h */; }; 6238579C1A9E8934003A45D9 /* HTMLComment.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238579A1A9E8934003A45D9 /* HTMLComment.m */; }; 6238579D1A9E8934003A45D9 /* HTMLComment.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238579A1A9E8934003A45D9 /* HTMLComment.m */; }; - 6238C9851AB8D6330006512E /* HTMLKitExceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 6238C9831AB8D6330006512E /* HTMLKitExceptions.h */; }; - 6238C9861AB8D6330006512E /* HTMLKitExceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238C9841AB8D6330006512E /* HTMLKitExceptions.m */; }; - 6238C9871AB8D6330006512E /* HTMLKitExceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238C9841AB8D6330006512E /* HTMLKitExceptions.m */; }; + 6238C9851AB8D6330006512E /* HTMLKitDOMExceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */; }; + 6238C9861AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */; }; + 6238C9871AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */; }; 623916C31AC707250066B4FE /* HTMLNodeTreeEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */; }; 623916C41AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */; }; 623916C51AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */; }; @@ -198,8 +198,8 @@ 623857951A9E8606003A45D9 /* HTMLDocumentType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLDocumentType.m; sourceTree = ""; }; 623857991A9E8934003A45D9 /* HTMLComment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLComment.h; sourceTree = ""; }; 6238579A1A9E8934003A45D9 /* HTMLComment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLComment.m; sourceTree = ""; }; - 6238C9831AB8D6330006512E /* HTMLKitExceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLKitExceptions.h; sourceTree = ""; }; - 6238C9841AB8D6330006512E /* HTMLKitExceptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitExceptions.m; sourceTree = ""; }; + 6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLKitDOMExceptions.h; sourceTree = ""; }; + 6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitDOMExceptions.m; sourceTree = ""; }; 623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeTreeEnumerator.h; sourceTree = ""; }; 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeTreeEnumerator.m; sourceTree = ""; }; 623916C61AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitNodeTreeEnumratorTests.m; sourceTree = ""; }; @@ -319,22 +319,25 @@ 62362A3F1A9FDE8A00301989 /* HTMLDOM.h */, 6234584C1A9D2FA4009BD491 /* HTMLNode.h */, 6234584D1A9D2FA4009BD491 /* HTMLNode.m */, - 6279F87219E1808D00F12EE5 /* HTMLElement.h */, - 6279F87319E1808D00F12EE5 /* HTMLElement.m */, 6238578F1A9E772B003A45D9 /* HTMLDocument.h */, 623857901A9E772B003A45D9 /* HTMLDocument.m */, 623857941A9E8606003A45D9 /* HTMLDocumentType.h */, 623857951A9E8606003A45D9 /* HTMLDocumentType.m */, + 623406E41ADB05AD004677A3 /* HTMLDocumentFragment.h */, + 623406E51ADB05AD004677A3 /* HTMLDocumentFragment.m */, + 6279F87219E1808D00F12EE5 /* HTMLElement.h */, + 6279F87319E1808D00F12EE5 /* HTMLElement.m */, 623857991A9E8934003A45D9 /* HTMLComment.h */, 6238579A1A9E8934003A45D9 /* HTMLComment.m */, 62362A3A1A9FA70400301989 /* HTMLText.h */, 62362A3B1A9FA70400301989 /* HTMLText.m */, 623406DF1ADB04F9004677A3 /* HTMLTemplate.h */, 623406E01ADB04F9004677A3 /* HTMLTemplate.m */, - 623406E41ADB05AD004677A3 /* HTMLDocumentFragment.h */, - 623406E51ADB05AD004677A3 /* HTMLDocumentFragment.m */, 623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */, 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */, + 6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */, + 6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */, + 628B7CE61A080E1000602C87 /* HTMLNamespaces.h */, 623719431AA12EE8002E03C8 /* HTMLQuirksMode.h */, ); name = DOM; @@ -417,8 +420,6 @@ children = ( 625A14BC19C7829400AD0C32 /* HTMLKit.h */, 625A14BD19C7829400AD0C32 /* HTMLKit.m */, - 6238C9831AB8D6330006512E /* HTMLKitExceptions.h */, - 6238C9841AB8D6330006512E /* HTMLKitExceptions.m */, 62AE593219F97CCA0043F069 /* Tokenizing */, 628E16EC1ADAE71700B15A06 /* Parsing */, 623719441AA1472B002E03C8 /* DOM */, @@ -473,7 +474,6 @@ 6234BEED1AABBF1400DEB15F /* HTMLStackOfOpenElements.m */, 62363C3B1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h */, 62363C3C1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m */, - 628B7CE61A080E1000602C87 /* HTMLNamespaces.h */, 6223211D1A969B9300BACED5 /* HTMLElementTypes.h */, 6234C3361AB3BF710046F527 /* HTMLElementAdjustment.h */, 6279F87119E17DC700F12EE5 /* HTMLParserInsertionModes.h */, @@ -556,7 +556,7 @@ 62F31FDD19E9DCCF007F0657 /* HTMLTokenizerEntities.h in Headers */, 623406E11ADB04F9004677A3 /* HTMLTemplate.h in Headers */, 6234BEEE1AABBF1400DEB15F /* HTMLStackOfOpenElements.h in Headers */, - 6238C9851AB8D6330006512E /* HTMLKitExceptions.h in Headers */, + 6238C9851AB8D6330006512E /* HTMLKitDOMExceptions.h in Headers */, 6238039F1AB63A8C008A53D0 /* HTMLEOFToken.h in Headers */, 6279F87419E1808D00F12EE5 /* HTMLElement.h in Headers */, 62AE593F19F9907C0043F069 /* HTMLTagToken.h in Headers */, @@ -736,7 +736,7 @@ 623916C51AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */, 62AE593C19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */, 623406E31ADB04F9004677A3 /* HTMLTemplate.m in Sources */, - 6238C9871AB8D6330006512E /* HTMLKitExceptions.m in Sources */, + 6238C9871AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */, 62F873ED19E088C90062683C /* HTMLParser.m in Sources */, 623803A11AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */, 6279F87619E1808D00F12EE5 /* HTMLElement.m in Sources */, @@ -788,7 +788,7 @@ 623916C41AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */, 62AE593B19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */, 623406E21ADB04F9004677A3 /* HTMLTemplate.m in Sources */, - 6238C9861AB8D6330006512E /* HTMLKitExceptions.m in Sources */, + 6238C9861AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */, 62F873EC19E088C90062683C /* HTMLParser.m in Sources */, 623803A01AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */, 6279F87519E1808D00F12EE5 /* HTMLElement.m in Sources */, diff --git a/HTMLKit/HTMLDocument.m b/HTMLKit/HTMLDocument.m index 7ae4e68..c910f50 100644 --- a/HTMLKit/HTMLDocument.m +++ b/HTMLKit/HTMLDocument.m @@ -8,7 +8,7 @@ #import "HTMLDocument.h" #import "HTMLParser.h" -#import "HTMLKitExceptions.h" +#import "HTMLKitDOMExceptions.h" @interface HTMLNode (Private) @property (nonatomic, weak) HTMLDocument *ownerDocument; diff --git a/HTMLKit/HTMLKitExceptions.h b/HTMLKit/HTMLKitDOMExceptions.h similarity index 100% rename from HTMLKit/HTMLKitExceptions.h rename to HTMLKit/HTMLKitDOMExceptions.h diff --git a/HTMLKit/HTMLKitExceptions.m b/HTMLKit/HTMLKitDOMExceptions.m similarity index 91% rename from HTMLKit/HTMLKitExceptions.m rename to HTMLKit/HTMLKitDOMExceptions.m index 8234e00..f7fcacc 100644 --- a/HTMLKit/HTMLKitExceptions.m +++ b/HTMLKit/HTMLKitDOMExceptions.m @@ -6,7 +6,7 @@ // Copyright (c) 2015 BrainCookie. All rights reserved. // -#import "HTMLKitExceptions.h" +#import "HTMLKitDOMExceptions.h" NSString * const HTMLKitHierarchyRequestError = @"HierarchyRequestError"; NSString * const HTMLKitNotFoundError = @"NotFoundError"; diff --git a/HTMLKit/HTMLNode.h b/HTMLKit/HTMLNode.h index 916ed3e..3ef90cf 100644 --- a/HTMLKit/HTMLNode.h +++ b/HTMLKit/HTMLNode.h @@ -97,6 +97,8 @@ typedef NS_ENUM(short, HTMLNodeType) - (void)enumerateChildNodesUsingBlock:(void (^)(HTMLNode *node, NSUInteger idx, BOOL *stop))block; +- (void)enumerateChildElementsUsingBlock:(void (^)(HTMLElement *element, NSUInteger idx, BOOL *stop))block; + - (NSEnumerator *)treeEnumerator; - (NSEnumerator *)reverseTreeEnumerator; diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index 363424d..0babcf9 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -12,7 +12,7 @@ #import "HTMLElement.h" #import "HTMLText.h" #import "HTMLComment.h" -#import "HTMLKitExceptions.h" +#import "HTMLKitDOMExceptions.h" #import "HTMLNodeTreeEnumerator.h" @interface HTMLNode () @@ -263,6 +263,19 @@ }]; } +- (void)enumerateChildElementsUsingBlock:(void (^)(HTMLElement *element, NSUInteger idx, BOOL *stop))block +{ + if (block == nil) { + return; + } + + [self.childNodes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if ([obj isKindOfClass:[HTMLElement class]]) { + block([obj asElement], idx, stop); + } + }]; +} + - (NSEnumerator *)treeEnumerator { return [[HTMLNodeTreeEnumerator alloc] initWithNode:self reverse:NO]; From f8ee4a38b4cc7d8b5a96e5a8d38891f16fdb147f Mon Sep 17 00:00:00 2001 From: iska Date: Wed, 27 May 2015 00:59:10 +0200 Subject: [PATCH 09/40] Add HTML Node Filter protocol --- HTMLKit.xcodeproj/project.pbxproj | 4 ++++ HTMLKit/HTMLNodeFilter.h | 36 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 HTMLKit/HTMLNodeFilter.h diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index 408e504..d906780 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -69,6 +69,7 @@ 624493AC19CD0CBE00BCDDF4 /* HTMLToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 624493AA19CD0CBE00BCDDF4 /* HTMLToken.h */; }; 624493AD19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */; }; 624493AE19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */; }; + 6247A9471B152F8C00CCF25C /* HTMLNodeFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */; }; 624AC8FF19FBF59800BD3C4A /* HTMLTokens.h in Headers */ = {isa = PBXBuildFile; fileRef = 624AC8FE19FBF4F700BD3C4A /* HTMLTokens.h */; }; 624AC90119FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AC90019FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m */; }; 624AC90219FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AC90019FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m */; }; @@ -212,6 +213,7 @@ 624493A919CCE84A00BCDDF4 /* HTMLTokenizerStates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLTokenizerStates.h; sourceTree = ""; }; 624493AA19CD0CBE00BCDDF4 /* HTMLToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLToken.h; sourceTree = ""; }; 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLToken.m; sourceTree = ""; }; + 6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeFilter.h; sourceTree = ""; }; 624AC8FE19FBF4F700BD3C4A /* HTMLTokens.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLTokens.h; sourceTree = ""; }; 624AC90019FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTokenizerTests.m; sourceTree = ""; }; 624AC90419FBFE8A00BD3C4A /* html5lib-tests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "html5lib-tests"; sourceTree = ""; }; @@ -333,6 +335,7 @@ 62362A3B1A9FA70400301989 /* HTMLText.m */, 623406DF1ADB04F9004677A3 /* HTMLTemplate.h */, 623406E01ADB04F9004677A3 /* HTMLTemplate.m */, + 6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */, 623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */, 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */, 6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */, @@ -563,6 +566,7 @@ 623857911A9E772B003A45D9 /* HTMLDocument.h in Headers */, 624493A619CCC54100BCDDF4 /* HTMLTokenizer.h in Headers */, 62AE593A19F97E1C0043F069 /* HTMLDOCTYPEToken.h in Headers */, + 6247A9471B152F8C00CCF25C /* HTMLNodeFilter.h in Headers */, 623424881AB467B200726190 /* HTMLOrderedDictionary.h in Headers */, 625A150419C783EB00AD0C32 /* HTMLKit.h in Headers */, 625A150819C78ABA00AD0C32 /* HTMLInputStreamReader.h in Headers */, diff --git a/HTMLKit/HTMLNodeFilter.h b/HTMLKit/HTMLNodeFilter.h new file mode 100644 index 0000000..2f302f2 --- /dev/null +++ b/HTMLKit/HTMLNodeFilter.h @@ -0,0 +1,36 @@ +// +// HTMLNodeFilter.h +// HTMLKit +// +// Created by Iska on 27/05/15. +// Copyright (c) 2015 BrainCookie. All rights reserved. +// + +#import + +typedef NS_ENUM(unsigned short, HTMLNodeFilterValue) +{ + HTMLNodeFilterAccept = 1, + HTMLNodeFilterReject = 2, + HTMLNodeFilterSkip = 3 +} HTMLNodeFilterValue; + +typedef NS_ENUM(unsigned long, HTMLNodeFilterShowOptions) +{ + HTMLNodeFilterShowAll = 0xFFFFFFFF; + HTMLNodeFilterShowElement = 0x1; + HTMLNodeFilterShowText = 0x4; + HTMLNodeFilterShowProcessingInstruction = 0x40; + HTMLNodeFilterShowComment = 0x80; + HTMLNodeFilterShowDocument = 0x100; + HTMLNodeFilterShowDocumentType = 0x200; + HTMLNodeFilterShowDocumentFragment = 0x400; +} HTMLNodeFilterShowOptions; + +@class HTMLNode; + +@protocol HTMLNodeFilter + +- (HTMLNodeFilterValue)acceptNode:(HTMLNode *)node; + +@end From 7892a925c8f75fae735632867084e2ac3deef60f Mon Sep 17 00:00:00 2001 From: iska Date: Wed, 27 May 2015 00:59:37 +0200 Subject: [PATCH 10/40] Fix Element initializer after reordering the arguments --- HTMLKit/HTMLElement.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HTMLKit/HTMLElement.m b/HTMLKit/HTMLElement.m index 8e9a18f..47df5f9 100644 --- a/HTMLKit/HTMLElement.m +++ b/HTMLKit/HTMLElement.m @@ -36,10 +36,10 @@ - (instancetype)initWithTagName:(NSString *)tagName attributes:(NSDictionary *)attributes { - return [self initWithTagName:tagName attributes:attributes namespace:HTMLNamespaceHTML]; + return [self initWithTagName:tagName namespace:HTMLNamespaceHTML attributes:attributes]; } -- (instancetype)initWithTagName:(NSString *)tagName attributes:(NSDictionary *)attributes namespace:(HTMLNamespace)htmlNamespace +- (instancetype)initWithTagName:(NSString *)tagName namespace:(HTMLNamespace)htmlNamespace attributes:(NSDictionary *)attributes { self = [super initWithName:tagName type:HTMLNodeElement]; if (self) { From 45156d98fd9690ca339e81db6f9ca70c03b94a0f Mon Sep 17 00:00:00 2001 From: iska Date: Thu, 28 May 2015 00:34:17 +0200 Subject: [PATCH 11/40] Add implementation for HTML Node Iterator This, along with Tree Walker, will replace the Tree Enumerator. https://dom.spec.whatwg.org/#interface-nodeiterator --- HTMLKit.xcodeproj/project.pbxproj | 10 +++ HTMLKit/HTMLNodeFilter.h | 20 ++--- HTMLKit/HTMLNodeIterator.h | 27 ++++++ HTMLKit/HTMLNodeIterator.m | 131 ++++++++++++++++++++++++++++++ 4 files changed, 178 insertions(+), 10 deletions(-) create mode 100644 HTMLKit/HTMLNodeIterator.h create mode 100644 HTMLKit/HTMLNodeIterator.m diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index d906780..88ae430 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -69,6 +69,9 @@ 624493AC19CD0CBE00BCDDF4 /* HTMLToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 624493AA19CD0CBE00BCDDF4 /* HTMLToken.h */; }; 624493AD19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */; }; 624493AE19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */; }; + 6247A9431B152F4F00CCF25C /* HTMLNodeIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */; }; + 6247A9441B152F4F00CCF25C /* HTMLNodeIterator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */; }; + 6247A9451B152F4F00CCF25C /* HTMLNodeIterator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */; }; 6247A9471B152F8C00CCF25C /* HTMLNodeFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */; }; 624AC8FF19FBF59800BD3C4A /* HTMLTokens.h in Headers */ = {isa = PBXBuildFile; fileRef = 624AC8FE19FBF4F700BD3C4A /* HTMLTokens.h */; }; 624AC90119FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AC90019FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m */; }; @@ -213,6 +216,8 @@ 624493A919CCE84A00BCDDF4 /* HTMLTokenizerStates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLTokenizerStates.h; sourceTree = ""; }; 624493AA19CD0CBE00BCDDF4 /* HTMLToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLToken.h; sourceTree = ""; }; 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLToken.m; sourceTree = ""; }; + 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeIterator.h; sourceTree = ""; }; + 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeIterator.m; sourceTree = ""; }; 6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeFilter.h; sourceTree = ""; }; 624AC8FE19FBF4F700BD3C4A /* HTMLTokens.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLTokens.h; sourceTree = ""; }; 624AC90019FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTokenizerTests.m; sourceTree = ""; }; @@ -335,6 +340,8 @@ 62362A3B1A9FA70400301989 /* HTMLText.m */, 623406DF1ADB04F9004677A3 /* HTMLTemplate.h */, 623406E01ADB04F9004677A3 /* HTMLTemplate.m */, + 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */, + 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */, 6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */, 623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */, 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */, @@ -568,6 +575,7 @@ 62AE593A19F97E1C0043F069 /* HTMLDOCTYPEToken.h in Headers */, 6247A9471B152F8C00CCF25C /* HTMLNodeFilter.h in Headers */, 623424881AB467B200726190 /* HTMLOrderedDictionary.h in Headers */, + 6247A9431B152F4F00CCF25C /* HTMLNodeIterator.h in Headers */, 625A150419C783EB00AD0C32 /* HTMLKit.h in Headers */, 625A150819C78ABA00AD0C32 /* HTMLInputStreamReader.h in Headers */, 6238579B1A9E8934003A45D9 /* HTMLComment.h in Headers */, @@ -729,6 +737,7 @@ files = ( 62362A3E1A9FA70400301989 /* HTMLText.m in Sources */, 6235CE9D1AA509430026937B /* NSString+HTMLKit.m in Sources */, + 6247A9451B152F4F00CCF25C /* HTMLNodeIterator.m in Sources */, 6238579D1A9E8934003A45D9 /* HTMLComment.m in Sources */, 6234BEF01AABBF1400DEB15F /* HTMLStackOfOpenElements.m in Sources */, 624493AE19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */, @@ -781,6 +790,7 @@ files = ( 62362A3D1A9FA70400301989 /* HTMLText.m in Sources */, 6235CE9C1AA509430026937B /* NSString+HTMLKit.m in Sources */, + 6247A9441B152F4F00CCF25C /* HTMLNodeIterator.m in Sources */, 6238579C1A9E8934003A45D9 /* HTMLComment.m in Sources */, 6234BEEF1AABBF1400DEB15F /* HTMLStackOfOpenElements.m in Sources */, 624493AD19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */, diff --git a/HTMLKit/HTMLNodeFilter.h b/HTMLKit/HTMLNodeFilter.h index 2f302f2..31cbdfa 100644 --- a/HTMLKit/HTMLNodeFilter.h +++ b/HTMLKit/HTMLNodeFilter.h @@ -13,19 +13,19 @@ typedef NS_ENUM(unsigned short, HTMLNodeFilterValue) HTMLNodeFilterAccept = 1, HTMLNodeFilterReject = 2, HTMLNodeFilterSkip = 3 -} HTMLNodeFilterValue; +}; typedef NS_ENUM(unsigned long, HTMLNodeFilterShowOptions) { - HTMLNodeFilterShowAll = 0xFFFFFFFF; - HTMLNodeFilterShowElement = 0x1; - HTMLNodeFilterShowText = 0x4; - HTMLNodeFilterShowProcessingInstruction = 0x40; - HTMLNodeFilterShowComment = 0x80; - HTMLNodeFilterShowDocument = 0x100; - HTMLNodeFilterShowDocumentType = 0x200; - HTMLNodeFilterShowDocumentFragment = 0x400; -} HTMLNodeFilterShowOptions; + HTMLNodeFilterShowAll = 0xFFFFFFFF, + HTMLNodeFilterShowElement = 0x1, + HTMLNodeFilterShowText = 0x4, + HTMLNodeFilterShowProcessingInstruction = 0x40, + HTMLNodeFilterShowComment = 0x80, + HTMLNodeFilterShowDocument = 0x100, + HTMLNodeFilterShowDocumentType = 0x200, + HTMLNodeFilterShowDocumentFragment = 0x400 +}; @class HTMLNode; diff --git a/HTMLKit/HTMLNodeIterator.h b/HTMLKit/HTMLNodeIterator.h new file mode 100644 index 0000000..f082809 --- /dev/null +++ b/HTMLKit/HTMLNodeIterator.h @@ -0,0 +1,27 @@ +// +// HTMLNodeIterator.h +// HTMLKit +// +// Created by Iska on 27/05/15. +// Copyright (c) 2015 BrainCookie. All rights reserved. +// + +#import +#import "HTMLNodeFilter.h" + +@class HTMLNode; + +@interface HTMLNodeIterator : NSEnumerator + +@property (nonatomic, strong, readonly) HTMLNode *root; +@property (nonatomic, strong, readonly) HTMLNode *referenceNode; +@property (nonatomic, assign, readonly) BOOL pointerBeforeReferenceNode; +@property (nonatomic, assign, readonly) HTMLNodeFilterShowOptions whatToShow; +@property (nonatomic, strong, readonly) id filter; + +- (instancetype)initWithNode:(HTMLNode *)node; + +- (HTMLNode *)nextNode; +- (HTMLNode *)previousNode; + +@end diff --git a/HTMLKit/HTMLNodeIterator.m b/HTMLKit/HTMLNodeIterator.m new file mode 100644 index 0000000..1439bdb --- /dev/null +++ b/HTMLKit/HTMLNodeIterator.m @@ -0,0 +1,131 @@ +// +// HTMLNodeIterator.m +// HTMLKit +// +// Created by Iska on 27/05/15. +// Copyright (c) 2015 BrainCookie. All rights reserved. +// + +#import "HTMLNodeIterator.h" +#import "HTMLNode.h" + +typedef NS_ENUM(short, TraverseDirection) +{ + TraverseDirectionNext, + TraverseDirectionPrevious +}; + +@interface HTMLNodeIterator () +{ + HTMLNode *_root; +} +@end + +@implementation HTMLNodeIterator + +- (instancetype)initWithNode:(HTMLNode *)node +{ + self = [super init]; + if (self) { + _root = node; + _whatToShow = HTMLNodeFilterShowAll; + } + return self; +} + +- (HTMLNode *)traverseInDirection:(TraverseDirection)direction +{ + HTMLNode *node = self.referenceNode; + BOOL beforeNode = self.pointerBeforeReferenceNode; + + do { + if (direction == TraverseDirectionNext) { + if (!beforeNode) { + node = FollowingNode(node, self.root); + if (node == nil) { + return nil; + } + beforeNode = NO; + } + } else { + if (beforeNode) { + node = PrecedingNode(node, self.root); + if (node == nil) { + return nil; + } + beforeNode = YES; + } + } + } while (FilterNode(self, node) != HTMLNodeFilterAccept); + + _referenceNode = node; + _pointerBeforeReferenceNode = beforeNode; + return node; +} + +NS_INLINE HTMLNode * PrecedingNode(HTMLNode *node, HTMLNode *root) +{ + HTMLNode *previous = node.previousSibling; + if (previous != nil) { + while (node.lastChildNode != nil) { + node = node.lastChildNode; + } + return node; + } + + if (node == root) { + return nil; + } + + return node.parentNode; +} + +NS_INLINE HTMLNode * FollowingNode(HTMLNode *node, HTMLNode *root) +{ + if (node.firstChiledNode != nil) { + return node.firstChiledNode; + } + + do { + if (node == root) { + return nil; + } + if (node.nextSibling != nil) { + return node.nextSibling; + } + node = node.parentNode; + } while (node != nil); + + return nil; +} + +NS_INLINE HTMLNodeFilterValue FilterNode(HTMLNodeIterator *iterator, HTMLNode *node) +{ + unsigned long nthBit = (1 << (node.nodeType - 1)) & iterator.whatToShow; + if (!nthBit) { + return HTMLNodeFilterSkip; + } + + if (iterator.filter == nil) { + return HTMLNodeFilterAccept; + } + + return [iterator.filter acceptNode:node]; +} + +- (id)nextObject +{ + return self.nextNode; +} + +- (HTMLNode *)nextNode +{ + return [self traverseInDirection:TraverseDirectionNext]; +} + +- (HTMLNode *)previousNode +{ + return [self traverseInDirection:TraverseDirectionPrevious]; +} + +@end From aece7138a41839278d57b6db5366b0b64e90b60a Mon Sep 17 00:00:00 2001 From: iska Date: Thu, 28 May 2015 00:42:20 +0200 Subject: [PATCH 12/40] Rename Tree Enumeration Tests to Node Iterator Tests --- HTMLKit.xcodeproj/project.pbxproj | 12 +++--- ...atorTests.m => HTMLKitNodeIteratorTests.m} | 39 +++++++++---------- 2 files changed, 25 insertions(+), 26 deletions(-) rename HTMLKitTests/{HTMLKitNodeTreeEnumratorTests.m => HTMLKitNodeIteratorTests.m} (68%) diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index 88ae430..f01e630 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -55,8 +55,8 @@ 623916C31AC707250066B4FE /* HTMLNodeTreeEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */; }; 623916C41AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */; }; 623916C51AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */; }; - 623916C71AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C61AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m */; }; - 623916C81AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C61AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m */; }; + 623916C71AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */; }; + 623916C81AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */; }; 6239755A1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623975591AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m */; }; 6239755B1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623975591AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m */; }; 6239755E1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6239755D1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.m */; }; @@ -206,7 +206,7 @@ 6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitDOMExceptions.m; sourceTree = ""; }; 623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeTreeEnumerator.h; sourceTree = ""; }; 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeTreeEnumerator.m; sourceTree = ""; }; - 623916C61AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitNodeTreeEnumratorTests.m; sourceTree = ""; }; + 623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitNodeIteratorTests.m; sourceTree = ""; }; 623975591AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTreeConstructionTests.m; sourceTree = ""; }; 6239755C1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTML5LibTreeConstructionTest.h; sourceTree = ""; }; 6239755D1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTML5LibTreeConstructionTest.m; sourceTree = ""; }; @@ -367,7 +367,7 @@ 624B9FB71AE072CB00646C4C /* Nodes */ = { isa = PBXGroup; children = ( - 623916C61AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m */, + 623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */, 624B9FB41AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m */, 624FC3791AE591D80015DDF9 /* HTMLKitNodesTests.m */, 62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */, @@ -777,7 +777,7 @@ 6236738F1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m in Sources */, 624AC90219FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m in Sources */, 624B9FB31AE0313300646C4C /* HTMLKitStringCategoryTests.m in Sources */, - 623916C81AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m in Sources */, + 623916C81AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m in Sources */, 62D8345A19FB1AC4009205A9 /* HTML5LibTokenizerTest.m in Sources */, 6239755F1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.m in Sources */, 624FC37B1AE591D80015DDF9 /* HTMLKitNodesTests.m in Sources */, @@ -830,7 +830,7 @@ 6236738E1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m in Sources */, 624AC90119FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m in Sources */, 624B9FB21AE0313300646C4C /* HTMLKitStringCategoryTests.m in Sources */, - 623916C71AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m in Sources */, + 623916C71AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m in Sources */, 62D8345919FB1AC4009205A9 /* HTML5LibTokenizerTest.m in Sources */, 6239755E1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.m in Sources */, 624FC37A1AE591D80015DDF9 /* HTMLKitNodesTests.m in Sources */, diff --git a/HTMLKitTests/HTMLKitNodeTreeEnumratorTests.m b/HTMLKitTests/HTMLKitNodeIteratorTests.m similarity index 68% rename from HTMLKitTests/HTMLKitNodeTreeEnumratorTests.m rename to HTMLKitTests/HTMLKitNodeIteratorTests.m index 654fbcf..27a699a 100644 --- a/HTMLKitTests/HTMLKitNodeTreeEnumratorTests.m +++ b/HTMLKitTests/HTMLKitNodeIteratorTests.m @@ -7,14 +7,13 @@ // #import +#import "HTMLDOM.h" -#import "HTMLNodes.h" - -@interface HTMLKitNodeTreeEnumratorTests : XCTestCase +@interface HTMLKitNodeIteratorTests : XCTestCase @end -@implementation HTMLKitNodeTreeEnumratorTests +@implementation HTMLKitNodeIteratorTests #pragma mark - Elements @@ -92,7 +91,7 @@ - (void)testSingle { HTMLElement *div = self.div; - NSArray *result = div.treeEnumerator.allObjects; + NSArray *result = div.nodeIterator.allObjects; NSArray *expected = @[@"div"]; XCTAssertEqualObjects([result valueForKey:@"name"], expected); } @@ -100,49 +99,49 @@ - (void)testSimpleTree { HTMLElement *tree = self.simpleTree; - NSArray *result = tree.treeEnumerator.allObjects; + NSArray *result = tree.nodeIterator.allObjects; NSArray *expected = @[@"div", @"a", @"b", @"c"]; XCTAssertEqualObjects([result valueForKey:@"name"], expected); } - (void)testSimpleTreeReversed { - HTMLElement *tree = self.simpleTree; - NSArray *result = tree.reverseTreeEnumerator.allObjects; - NSArray *expected = @[@"div", @"c", @"b", @"a"]; - XCTAssertEqualObjects([result valueForKey:@"name"], expected); +// HTMLElement *tree = self.simpleTree; +// NSArray *result = tree.reverseTreeEnumerator.allObjects; +// NSArray *expected = @[@"div", @"c", @"b", @"a"]; +// XCTAssertEqualObjects([result valueForKey:@"name"], expected); } - (void)testNestedSimpleTree { HTMLElement *tree = self.nestedSimpleTree; - NSArray *result = tree.treeEnumerator.allObjects; + NSArray *result = tree.nodeIterator.allObjects; NSArray *expected = @[@"div", @"div", @"a", @"b", @"c", @"div", @"a", @"b", @"c"]; XCTAssertEqualObjects([result valueForKey:@"name"], expected); } - (void)testNestedSimpleTreeReversed { - HTMLElement *tree = self.nestedSimpleTree; - NSArray *result = tree.reverseTreeEnumerator.allObjects; - NSArray *expected = @[@"div", @"div", @"c", @"b", @"a", @"div", @"c", @"b", @"a"]; - XCTAssertEqualObjects([result valueForKey:@"name"], expected); +// HTMLElement *tree = self.nestedSimpleTree; +// NSArray *result = tree.reverseTreeEnumerator.allObjects; +// NSArray *expected = @[@"div", @"div", @"c", @"b", @"a", @"div", @"c", @"b", @"a"]; +// XCTAssertEqualObjects([result valueForKey:@"name"], expected); } - (void)testComplexSimpleTree { HTMLElement *tree = self.complexTree; - NSArray *result = tree.treeEnumerator.allObjects; + NSArray *result = tree.nodeIterator.allObjects; NSArray *expected = @[@"div", @"div",@"div", @"a", @"b", @"c", @"e", @"f", @"div", @"a", @"b", @"c"]; XCTAssertEqualObjects([result valueForKey:@"name"], expected); } - (void)testComplexSimpleTreeReversed { - HTMLElement *tree = self.complexTree; - NSArray *result = tree.reverseTreeEnumerator.allObjects; - NSArray *expected = @[@"div", @"div", @"c", @"b", @"a", @"e", @"f", @"div", @"div", @"c", @"b", @"a"]; - XCTAssertEqualObjects([result valueForKey:@"name"], expected); +// HTMLElement *tree = self.complexTree; +// NSArray *result = tree.reverseTreeEnumerator.allObjects; +// NSArray *expected = @[@"div", @"div", @"c", @"b", @"a", @"e", @"f", @"div", @"div", @"c", @"b", @"a"]; +// XCTAssertEqualObjects([result valueForKey:@"name"], expected); } @end From 165cdb5a75543c1f0de95f2dc05fdb3b04b0525c Mon Sep 17 00:00:00 2001 From: iska Date: Thu, 28 May 2015 00:42:59 +0200 Subject: [PATCH 13/40] Fix HTML Element initializer usage after arguments reordering --- HTMLKit/HTMLParser.m | 4 ++-- HTMLKitTests/HTML5LibTreeConstructionTest.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/HTMLKit/HTMLParser.m b/HTMLKit/HTMLParser.m index 539ce36..d561e59 100644 --- a/HTMLKit/HTMLParser.m +++ b/HTMLKit/HTMLParser.m @@ -421,8 +421,8 @@ - (HTMLElement *)createElementForToken:(HTMLTagToken *)token inNamespace:(HTMLNamespace)htmlNamespace { HTMLElement *element = [[HTMLElement alloc] initWithTagName:token.tagName - attributes:token.attributes - namespace:htmlNamespace]; + namespace:htmlNamespace + attributes:token.attributes]; return element; } diff --git a/HTMLKitTests/HTML5LibTreeConstructionTest.m b/HTMLKitTests/HTML5LibTreeConstructionTest.m index 1e8ac4d..37bea03 100644 --- a/HTMLKitTests/HTML5LibTreeConstructionTest.m +++ b/HTMLKitTests/HTML5LibTreeConstructionTest.m @@ -111,7 +111,7 @@ static NSString * const TreeConstruction = @"tree-construction"; fragment = [fragment substringFromIndex:@"svg ".length]; namespace = HTMLNamespaceSVG; } - test.documentFragment = [[HTMLElement alloc] initWithTagName:fragment attributes:nil namespace:namespace]; + test.documentFragment = [[HTMLElement alloc] initWithTagName:fragment namespace:namespace attributes:nil]; } else if ([match hasPrefix:@"#document\n"]) { NSArray *parts = [[match substringFromIndex:@"#document\n".length] componentsSeparatedByString:@"| "]; NSArray *nodes = [HTML5LibTreeConstructionTest parseDocument:parts]; @@ -245,7 +245,7 @@ NS_INLINE HTMLElement * parseTag(NSString *str) NSString *tagName = parts.count == 2 ? parts[1] : parts[0]; HTMLNamespace namespace = parts.count == 1 ? HTMLNamespaceHTML : ([parts[0] isEqualToString:@"math"] ? HTMLNamespaceMathML : HTMLNamespaceSVG); - HTMLElement *element = [[HTMLElement alloc] initWithTagName:tagName attributes:nil namespace:namespace]; + HTMLElement *element = [[HTMLElement alloc] initWithTagName:tagName namespace:namespace attributes:nil]; return element; } From ac561570f3ee288ca6ecd6f706fd580f5d14f3c9 Mon Sep 17 00:00:00 2001 From: iska Date: Thu, 28 May 2015 00:43:27 +0200 Subject: [PATCH 14/40] Use correct DOM import in test classes --- HTMLKitTests/HTMLKitMutationAlgorithmsTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HTMLKitTests/HTMLKitMutationAlgorithmsTests.m b/HTMLKitTests/HTMLKitMutationAlgorithmsTests.m index 990d574..421065b 100644 --- a/HTMLKitTests/HTMLKitMutationAlgorithmsTests.m +++ b/HTMLKitTests/HTMLKitMutationAlgorithmsTests.m @@ -7,7 +7,7 @@ // #import -#import "HTMLNodes.h" +#import "HTMLDOM.h" #import "NSString+HTMLKit.h" extern uint64_t dispatch_benchmark(size_t count, void (^block)(void)); From 13ed63017eb1216314744f95a2e601e318a74a83 Mon Sep 17 00:00:00 2001 From: iska Date: Thu, 28 May 2015 00:55:45 +0200 Subject: [PATCH 15/40] Fix initial Node Iterator values --- HTMLKit/HTMLNodeIterator.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HTMLKit/HTMLNodeIterator.m b/HTMLKit/HTMLNodeIterator.m index 1439bdb..0c14127 100644 --- a/HTMLKit/HTMLNodeIterator.m +++ b/HTMLKit/HTMLNodeIterator.m @@ -28,6 +28,8 @@ typedef NS_ENUM(short, TraverseDirection) self = [super init]; if (self) { _root = node; + _referenceNode = _root; + _pointerBeforeReferenceNode = YES; _whatToShow = HTMLNodeFilterShowAll; } return self; From 0fa394b911124658e0ed11e2de62ca49fb42597f Mon Sep 17 00:00:00 2001 From: iska Date: Thu, 28 May 2015 00:56:09 +0200 Subject: [PATCH 16/40] Fix traversing method in Node Iterator --- HTMLKit/HTMLNodeIterator.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/HTMLKit/HTMLNodeIterator.m b/HTMLKit/HTMLNodeIterator.m index 0c14127..8da7de0 100644 --- a/HTMLKit/HTMLNodeIterator.m +++ b/HTMLKit/HTMLNodeIterator.m @@ -47,16 +47,16 @@ typedef NS_ENUM(short, TraverseDirection) if (node == nil) { return nil; } - beforeNode = NO; } + beforeNode = NO; } else { if (beforeNode) { node = PrecedingNode(node, self.root); if (node == nil) { return nil; } - beforeNode = YES; } + beforeNode = YES; } } while (FilterNode(self, node) != HTMLNodeFilterAccept); @@ -69,10 +69,10 @@ NS_INLINE HTMLNode * PrecedingNode(HTMLNode *node, HTMLNode *root) { HTMLNode *previous = node.previousSibling; if (previous != nil) { - while (node.lastChildNode != nil) { - node = node.lastChildNode; + while (previous.lastChildNode != nil) { + previous = previous.lastChildNode; } - return node; + return previous; } if (node == root) { From cd6e8bf4fc7e78ec338e81b81eebdd2b617f1427 Mon Sep 17 00:00:00 2001 From: iska Date: Thu, 28 May 2015 01:22:29 +0200 Subject: [PATCH 17/40] Remove Tree Enumerator since it was superseded by the Node Iterator implementation --- HTMLKit.xcodeproj/project.pbxproj | 10 ----- HTMLKit/HTMLElement.m | 2 +- HTMLKit/HTMLNode.h | 5 +-- HTMLKit/HTMLNode.m | 22 +--------- HTMLKit/HTMLNodeTreeEnumerator.h | 17 -------- HTMLKit/HTMLNodeTreeEnumerator.m | 54 ------------------------- HTMLKitTests/HTMLKitNodeIteratorTests.m | 38 ++++++++--------- 7 files changed, 22 insertions(+), 126 deletions(-) delete mode 100644 HTMLKit/HTMLNodeTreeEnumerator.h delete mode 100644 HTMLKit/HTMLNodeTreeEnumerator.m diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index f01e630..06880b2 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -52,9 +52,6 @@ 6238C9851AB8D6330006512E /* HTMLKitDOMExceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */; }; 6238C9861AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */; }; 6238C9871AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */; }; - 623916C31AC707250066B4FE /* HTMLNodeTreeEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */; }; - 623916C41AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */; }; - 623916C51AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */; }; 623916C71AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */; }; 623916C81AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */; }; 6239755A1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623975591AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m */; }; @@ -204,8 +201,6 @@ 6238579A1A9E8934003A45D9 /* HTMLComment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLComment.m; sourceTree = ""; }; 6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLKitDOMExceptions.h; sourceTree = ""; }; 6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitDOMExceptions.m; sourceTree = ""; }; - 623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeTreeEnumerator.h; sourceTree = ""; }; - 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeTreeEnumerator.m; sourceTree = ""; }; 623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitNodeIteratorTests.m; sourceTree = ""; }; 623975591AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTreeConstructionTests.m; sourceTree = ""; }; 6239755C1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTML5LibTreeConstructionTest.h; sourceTree = ""; }; @@ -343,8 +338,6 @@ 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */, 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */, 6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */, - 623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */, - 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */, 6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */, 6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */, 628B7CE61A080E1000602C87 /* HTMLNamespaces.h */, @@ -559,7 +552,6 @@ 62D89DB01AE7080300B6243D /* HTMLDOM.h in Headers */, 62F873EB19E088C90062683C /* HTMLParser.h in Headers */, 624AC8FF19FBF59800BD3C4A /* HTMLTokens.h in Headers */, - 623916C31AC707250066B4FE /* HTMLNodeTreeEnumerator.h in Headers */, 62AE594419F992F30043F069 /* HTMLCommentToken.h in Headers */, 624493AC19CD0CBE00BCDDF4 /* HTMLToken.h in Headers */, 6235CEA01AA5170A0026937B /* HTMLMarker.h in Headers */, @@ -746,7 +738,6 @@ 62AE594119F9907C0043F069 /* HTMLTagToken.m in Sources */, 62AE594619F992F30043F069 /* HTMLCommentToken.m in Sources */, 62363C3F1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m in Sources */, - 623916C51AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */, 62AE593C19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */, 623406E31ADB04F9004677A3 /* HTMLTemplate.m in Sources */, 6238C9871AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */, @@ -799,7 +790,6 @@ 62AE594019F9907C0043F069 /* HTMLTagToken.m in Sources */, 62AE594519F992F30043F069 /* HTMLCommentToken.m in Sources */, 62363C3E1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m in Sources */, - 623916C41AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */, 62AE593B19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */, 623406E21ADB04F9004677A3 /* HTMLTemplate.m in Sources */, 6238C9861AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */, diff --git a/HTMLKit/HTMLElement.m b/HTMLKit/HTMLElement.m index 47df5f9..1c018da 100644 --- a/HTMLKit/HTMLElement.m +++ b/HTMLKit/HTMLElement.m @@ -88,7 +88,7 @@ - (NSString *)textContent { NSMutableString *content = [NSMutableString string]; - for (HTMLNode *node in self.treeEnumerator) { + for (HTMLNode *node in self.nodeIterator) { if (node.nodeType == HTMLNodeText) { [content appendString:[(HTMLText *)node data]]; } diff --git a/HTMLKit/HTMLNode.h b/HTMLKit/HTMLNode.h index 3ef90cf..a2820f4 100644 --- a/HTMLKit/HTMLNode.h +++ b/HTMLKit/HTMLNode.h @@ -7,6 +7,7 @@ // #import +#import "HTMLNodeIterator.h" typedef NS_ENUM(short, HTMLNodeType) { @@ -99,9 +100,7 @@ typedef NS_ENUM(short, HTMLNodeType) - (void)enumerateChildElementsUsingBlock:(void (^)(HTMLElement *element, NSUInteger idx, BOOL *stop))block; -- (NSEnumerator *)treeEnumerator; - -- (NSEnumerator *)reverseTreeEnumerator; +- (HTMLNodeIterator *)nodeIterator; - (NSString *)treeDescription; diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index 0babcf9..bb8bbf7 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -13,7 +13,6 @@ #import "HTMLText.h" #import "HTMLComment.h" #import "HTMLKitDOMExceptions.h" -#import "HTMLNodeTreeEnumerator.h" @interface HTMLNode () { @@ -276,28 +275,11 @@ }]; } -- (NSEnumerator *)treeEnumerator +- (HTMLNodeIterator *)nodeIterator { - return [[HTMLNodeTreeEnumerator alloc] initWithNode:self reverse:NO]; + return [[HTMLNodeIterator alloc] initWithNode:self]; } -- (NSEnumerator *)reverseTreeEnumerator -{ - return [[HTMLNodeTreeEnumerator alloc] initWithNode:self reverse:YES]; -} - -- (void)doInsertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child -{ - NSArray *nodes = node.nodeType == HTMLNodeDocumentFragment ? node.childNodes.array : @[node]; - - NSUInteger index = [self indexOfChildNode:child]; - if (index != NSNotFound) { - NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, nodes.count)]; - [(NSMutableOrderedSet *)self.childNodes insertObjects:nodes atIndexes:indexes]; - } else { - [(NSMutableOrderedSet *)self.childNodes addObjectsFromArray:nodes]; - } -} #ifndef HTMLKIT_NO_DOM_CHECKS diff --git a/HTMLKit/HTMLNodeTreeEnumerator.h b/HTMLKit/HTMLNodeTreeEnumerator.h deleted file mode 100644 index baf7243..0000000 --- a/HTMLKit/HTMLNodeTreeEnumerator.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// HTMLNodeTreeEnumerator.h -// HTMLKit -// -// Created by Iska on 28/03/15. -// Copyright (c) 2015 BrainCookie. All rights reserved. -// - -#import - -@class HTMLNode; - -@interface HTMLNodeTreeEnumerator : NSEnumerator - -- (instancetype)initWithNode:(HTMLNode *)node reverse:(BOOL)reverse; - -@end diff --git a/HTMLKit/HTMLNodeTreeEnumerator.m b/HTMLKit/HTMLNodeTreeEnumerator.m deleted file mode 100644 index 8f82972..0000000 --- a/HTMLKit/HTMLNodeTreeEnumerator.m +++ /dev/null @@ -1,54 +0,0 @@ -// -// HTMLNodeTreeEnumerator.m -// HTMLKit -// -// Created by Iska on 28/03/15. -// Copyright (c) 2015 BrainCookie. All rights reserved. -// - -#import "HTMLNodeTreeEnumerator.h" -#import "HTMLNode.h" - -@interface HTMLNodeTreeEnumerator () -{ - BOOL _reverse; - NSMutableArray *_stack; -} -@end - -@implementation HTMLNodeTreeEnumerator - -- (instancetype)initWithNode:(HTMLNode *)node reverse:(BOOL)reverse -{ - self = [super init]; - if (self) { - _reverse = reverse; - _stack = [[NSMutableArray alloc] initWithObjects:node, nil]; - } - return self; -} - -- (id)nextObject -{ - if (_stack.count == 0) { - return nil; - } - - HTMLNode *node = _stack.lastObject; - [_stack removeLastObject]; - - NSArray *childNodes = node.childNodes.array; - if (childNodes != nil && childNodes.count > 0) { - if (childNodes.count > 1) { - NSRange range = NSMakeRange(_reverse ? 0 : 1, childNodes.count - 1); - NSArray *rest = [childNodes subarrayWithRange:range]; - - [_stack addObjectsFromArray:_reverse ? rest : rest.reverseObjectEnumerator.allObjects]; - } - [_stack addObject:_reverse ? childNodes.lastObject : childNodes.firstObject]; - } - - return node; -} - -@end diff --git a/HTMLKitTests/HTMLKitNodeIteratorTests.m b/HTMLKitTests/HTMLKitNodeIteratorTests.m index 27a699a..ecea4bf 100644 --- a/HTMLKitTests/HTMLKitNodeIteratorTests.m +++ b/HTMLKitTests/HTMLKitNodeIteratorTests.m @@ -104,14 +104,6 @@ XCTAssertEqualObjects([result valueForKey:@"name"], expected); } -- (void)testSimpleTreeReversed -{ -// HTMLElement *tree = self.simpleTree; -// NSArray *result = tree.reverseTreeEnumerator.allObjects; -// NSArray *expected = @[@"div", @"c", @"b", @"a"]; -// XCTAssertEqualObjects([result valueForKey:@"name"], expected); -} - - (void)testNestedSimpleTree { HTMLElement *tree = self.nestedSimpleTree; @@ -120,14 +112,6 @@ XCTAssertEqualObjects([result valueForKey:@"name"], expected); } -- (void)testNestedSimpleTreeReversed -{ -// HTMLElement *tree = self.nestedSimpleTree; -// NSArray *result = tree.reverseTreeEnumerator.allObjects; -// NSArray *expected = @[@"div", @"div", @"c", @"b", @"a", @"div", @"c", @"b", @"a"]; -// XCTAssertEqualObjects([result valueForKey:@"name"], expected); -} - - (void)testComplexSimpleTree { HTMLElement *tree = self.complexTree; @@ -136,12 +120,24 @@ XCTAssertEqualObjects([result valueForKey:@"name"], expected); } -- (void)testComplexSimpleTreeReversed +- (void)testNextPreviousIteration { -// HTMLElement *tree = self.complexTree; -// NSArray *result = tree.reverseTreeEnumerator.allObjects; -// NSArray *expected = @[@"div", @"div", @"c", @"b", @"a", @"e", @"f", @"div", @"div", @"c", @"b", @"a"]; -// XCTAssertEqualObjects([result valueForKey:@"name"], expected); + HTMLElement *tree = self.simpleTree; + HTMLNodeIterator *iterator = tree.nodeIterator; + + XCTAssertEqualObjects(iterator.previousNode, nil); + XCTAssertEqualObjects(iterator.nextNode.name, @"div"); + XCTAssertEqualObjects(iterator.nextNode.name, @"a"); + XCTAssertEqualObjects(iterator.previousNode.name, @"a"); + XCTAssertEqualObjects(iterator.previousNode.name, @"div"); + XCTAssertEqualObjects(iterator.nextNode.name, @"div"); + XCTAssertEqualObjects(iterator.nextNode.name, @"a"); + XCTAssertEqualObjects(iterator.nextNode.name, @"b"); + XCTAssertEqualObjects(iterator.nextNode.name, @"c"); + XCTAssertEqualObjects(iterator.previousNode.name, @"c"); + XCTAssertEqualObjects(iterator.previousNode.name, @"b"); + XCTAssertEqualObjects(iterator.previousNode.name, @"a"); + XCTAssertEqualObjects(iterator.previousNode.name, @"div"); } @end From dfeebc7f7f685cef58db2bc93bed2fe1887b916d Mon Sep 17 00:00:00 2001 From: iska Date: Thu, 28 May 2015 22:56:49 +0200 Subject: [PATCH 18/40] Remove frameworks search path entry causing an ignored warning on build --- HTMLKit.xcodeproj/project.pbxproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index 06880b2..1c13dba 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -970,7 +970,6 @@ FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", - "$(SDKROOT)/Developer/Library/Frameworks", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "HTMLKit/HTMLKit-Prefix.pch"; @@ -993,7 +992,6 @@ FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", - "$(SDKROOT)/Developer/Library/Frameworks", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "HTMLKit/HTMLKit-Prefix.pch"; @@ -1042,7 +1040,6 @@ buildSettings = { BUNDLE_LOADER = ""; FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", "$(DEVELOPER_FRAMEWORKS_DIR)", ); @@ -1066,7 +1063,6 @@ buildSettings = { BUNDLE_LOADER = ""; FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", "$(DEVELOPER_FRAMEWORKS_DIR)", ); From e1c3533a1c4ff3044b2314207885513c5f4f42f4 Mon Sep 17 00:00:00 2001 From: iska Date: Thu, 28 May 2015 22:57:31 +0200 Subject: [PATCH 19/40] Remove unused import in Tree Construction test class --- HTMLKitTests/HTML5LibTreeConstructionTest.m | 1 - 1 file changed, 1 deletion(-) diff --git a/HTMLKitTests/HTML5LibTreeConstructionTest.m b/HTMLKitTests/HTML5LibTreeConstructionTest.m index 37bea03..9d0a45c 100644 --- a/HTMLKitTests/HTML5LibTreeConstructionTest.m +++ b/HTMLKitTests/HTML5LibTreeConstructionTest.m @@ -13,7 +13,6 @@ #import "HTMLElement.h" #import "HTMLText.h" #import "HTMLComment.h" -#import "HTMLNodeTreeEnumerator.h" static NSString * const HTML5LibTests = @"html5lib-tests"; static NSString * const TreeConstruction = @"tree-construction"; From 3df5a219e162e2338189b05d85ed2dbbd9f7519b Mon Sep 17 00:00:00 2001 From: iska Date: Thu, 28 May 2015 23:26:08 +0200 Subject: [PATCH 20/40] Add Node Iterator initializers with filter and show-options arguments --- HTMLKit/HTMLNode.h | 3 ++- HTMLKit/HTMLNode.m | 7 ++++++- HTMLKit/HTMLNodeFilter.h | 1 - HTMLKit/HTMLNodeIterator.h | 6 ++++++ HTMLKit/HTMLNodeIterator.m | 16 +++++++++++++++- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/HTMLKit/HTMLNode.h b/HTMLKit/HTMLNode.h index a2820f4..d9078f2 100644 --- a/HTMLKit/HTMLNode.h +++ b/HTMLKit/HTMLNode.h @@ -101,7 +101,8 @@ typedef NS_ENUM(short, HTMLNodeType) - (void)enumerateChildElementsUsingBlock:(void (^)(HTMLElement *element, NSUInteger idx, BOOL *stop))block; - (HTMLNodeIterator *)nodeIterator; - +- (HTMLNodeIterator *)nodeIteratorWithFilter:(id)filter + showOptions:(HTMLNodeFilterShowOptions)showOptions; - (NSString *)treeDescription; @end diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index bb8bbf7..f65cf9b 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -277,9 +277,14 @@ - (HTMLNodeIterator *)nodeIterator { - return [[HTMLNodeIterator alloc] initWithNode:self]; + return [self nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowAll]; } +- (HTMLNodeIterator *)nodeIteratorWithFilter:(id)filter + showOptions:(HTMLNodeFilterShowOptions)showOptions +{ + return [[HTMLNodeIterator alloc] initWithNode:self filter:filter showOptions:showOptions]; +} #ifndef HTMLKIT_NO_DOM_CHECKS diff --git a/HTMLKit/HTMLNodeFilter.h b/HTMLKit/HTMLNodeFilter.h index 31cbdfa..021fe5a 100644 --- a/HTMLKit/HTMLNodeFilter.h +++ b/HTMLKit/HTMLNodeFilter.h @@ -20,7 +20,6 @@ typedef NS_ENUM(unsigned long, HTMLNodeFilterShowOptions) HTMLNodeFilterShowAll = 0xFFFFFFFF, HTMLNodeFilterShowElement = 0x1, HTMLNodeFilterShowText = 0x4, - HTMLNodeFilterShowProcessingInstruction = 0x40, HTMLNodeFilterShowComment = 0x80, HTMLNodeFilterShowDocument = 0x100, HTMLNodeFilterShowDocumentType = 0x200, diff --git a/HTMLKit/HTMLNodeIterator.h b/HTMLKit/HTMLNodeIterator.h index f082809..d6c0cb7 100644 --- a/HTMLKit/HTMLNodeIterator.h +++ b/HTMLKit/HTMLNodeIterator.h @@ -20,6 +20,12 @@ @property (nonatomic, strong, readonly) id filter; - (instancetype)initWithNode:(HTMLNode *)node; +- (instancetype)initWithNode:(HTMLNode *)node + filter:(id)filter; +- (instancetype)initWithNode:(HTMLNode *)node + filter:(id)filter + showOptions:(HTMLNodeFilterShowOptions)showOptions; + - (HTMLNode *)nextNode; - (HTMLNode *)previousNode; diff --git a/HTMLKit/HTMLNodeIterator.m b/HTMLKit/HTMLNodeIterator.m index 8da7de0..370155e 100644 --- a/HTMLKit/HTMLNodeIterator.m +++ b/HTMLKit/HTMLNodeIterator.m @@ -24,13 +24,27 @@ typedef NS_ENUM(short, TraverseDirection) @implementation HTMLNodeIterator - (instancetype)initWithNode:(HTMLNode *)node +{ + return [self initWithNode:node filter:nil]; +} + +- (instancetype)initWithNode:(HTMLNode *)node + filter:(id)filter +{ + return [self initWithNode:node filter:nil showOptions:HTMLNodeFilterShowAll]; +} + +- (instancetype)initWithNode:(HTMLNode *)node + filter:(id)filter + showOptions:(HTMLNodeFilterShowOptions)showOptions { self = [super init]; if (self) { _root = node; + _filter = filter; + _whatToShow = showOptions; _referenceNode = _root; _pointerBeforeReferenceNode = YES; - _whatToShow = HTMLNodeFilterShowAll; } return self; } From 066bdeffa82ed57fd6c01ed87589a47b41ececa5 Mon Sep 17 00:00:00 2001 From: iska Date: Fri, 29 May 2015 00:39:52 +0200 Subject: [PATCH 21/40] Add Node Iterator test cases for iteration and filtering logic --- HTMLKitTests/HTMLKitNodeIteratorTests.m | 219 +++++++++++++++++++++--- 1 file changed, 197 insertions(+), 22 deletions(-) diff --git a/HTMLKitTests/HTMLKitNodeIteratorTests.m b/HTMLKitTests/HTMLKitNodeIteratorTests.m index ecea4bf..9eb9c7f 100644 --- a/HTMLKitTests/HTMLKitNodeIteratorTests.m +++ b/HTMLKitTests/HTMLKitNodeIteratorTests.m @@ -9,6 +9,23 @@ #import #import "HTMLDOM.h" +@interface CommentNodeFilter : NSObject +@end + +@implementation CommentNodeFilter + +- (HTMLNodeFilterValue)acceptNode:(HTMLNode *)node +{ + if (node.nodeType == HTMLNodeComment) { + if ([[(HTMLComment *)node data] rangeOfString:@"second"].location != NSNotFound) { + return HTMLNodeFilterAccept; + } + } + return HTMLNodeFilterReject; +} + +@end + @interface HTMLKitNodeIteratorTests : XCTestCase @end @@ -86,38 +103,77 @@ return root; } +- (HTMLDocument *)mixedTree +{ + + /* + | doctype + | #comment + | #comment + | html + | #text "This is a Text" + | div + */ + HTMLDocument *document = [HTMLDocument new]; + document.documentType = [HTMLDocumentType new];; + + HTMLComment *comment = [[HTMLComment alloc] initWithData:@"This is a Comment"]; + [document appendNode:comment]; + + HTMLComment *secondCommnet = [[HTMLComment alloc] initWithData:@"This is a second Comment"]; + [document appendNode:secondCommnet]; + + HTMLElement *root = [[HTMLElement alloc] initWithTagName:@"html"]; + [document appendNode:root]; + + [root appendNode:[[HTMLText alloc] initWithData:@"This is a Text"]]; + + [root appendNode:[[HTMLElement alloc] initWithTagName:@"div"]]; + + return document; +} + #pragma mark - Tests -- (void)testSingle -{ - HTMLElement *div = self.div; - NSArray *result = div.nodeIterator.allObjects; - NSArray *expected = @[@"div"]; - XCTAssertEqualObjects([result valueForKey:@"name"], expected); -} - -- (void)testSimpleTree +- (void)testNodeIteratorInit { HTMLElement *tree = self.simpleTree; - NSArray *result = tree.nodeIterator.allObjects; - NSArray *expected = @[@"div", @"a", @"b", @"c"]; - XCTAssertEqualObjects([result valueForKey:@"name"], expected); + HTMLNodeIterator *iterator = tree.nodeIterator; + + XCTAssertEqualObjects(iterator.root, tree); + XCTAssertEqualObjects(iterator.referenceNode, tree); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES); + XCTAssertEqualObjects(iterator.filter, nil); + XCTAssertEqual(iterator.whatToShow, HTMLNodeFilterShowAll); } -- (void)testNestedSimpleTree +- (void)testNewIteratorNextNodeShouldBeRoot { - HTMLElement *tree = self.nestedSimpleTree; - NSArray *result = tree.nodeIterator.allObjects; - NSArray *expected = @[@"div", @"div", @"a", @"b", @"c", @"div", @"a", @"b", @"c"]; - XCTAssertEqualObjects([result valueForKey:@"name"], expected); + HTMLElement *tree = self.simpleTree; + HTMLNodeIterator *iterator = tree.nodeIterator; + + XCTAssertEqualObjects(iterator.nextNode, tree); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO); } -- (void)testComplexSimpleTree +- (void)testNewIteratorPreviousNodeShouldBeNil { - HTMLElement *tree = self.complexTree; - NSArray *result = tree.nodeIterator.allObjects; - NSArray *expected = @[@"div", @"div",@"div", @"a", @"b", @"c", @"e", @"f", @"div", @"a", @"b", @"c"]; - XCTAssertEqualObjects([result valueForKey:@"name"], expected); + HTMLElement *tree = self.simpleTree; + HTMLNodeIterator *iterator = tree.nodeIterator; + + XCTAssertEqualObjects(iterator.previousNode, nil); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES); +} + +- (void)testNewIteratorPreviousNodeShouldBeNextNode +{ + HTMLElement *tree = self.simpleTree; + HTMLNodeIterator *iterator = tree.nodeIterator; + + HTMLNode *node = iterator.nextNode; + + XCTAssertEqualObjects(iterator.previousNode, node); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES); } - (void)testNextPreviousIteration @@ -140,4 +196,123 @@ XCTAssertEqualObjects(iterator.previousNode.name, @"div"); } +- (void)testSingleNodeIteration +{ + HTMLElement *div = self.div; + NSArray *result = div.nodeIterator.allObjects; + NSArray *expected = @[@"div"]; + XCTAssertEqualObjects([result valueForKey:@"name"], expected); +} + +- (void)testSimpleTreeIteration +{ + HTMLElement *tree = self.simpleTree; + NSArray *result = tree.nodeIterator.allObjects; + NSArray *expected = @[@"div", @"a", @"b", @"c"]; + XCTAssertEqualObjects([result valueForKey:@"name"], expected); +} + +- (void)testNestedSimpleTreeIteration +{ + HTMLElement *tree = self.nestedSimpleTree; + NSArray *result = tree.nodeIterator.allObjects; + NSArray *expected = @[@"div", @"div", @"a", @"b", @"c", @"div", @"a", @"b", @"c"]; + XCTAssertEqualObjects([result valueForKey:@"name"], expected); +} + +- (void)testComplexTreeIteration +{ + HTMLElement *tree = self.complexTree; + NSArray *result = tree.nodeIterator.allObjects; + NSArray *expected = @[@"div", @"div",@"div", @"a", @"b", @"c", @"e", @"f", @"div", @"a", @"b", @"c"]; + XCTAssertEqualObjects([result valueForKey:@"name"], expected); +} + +- (void)testShowDocument +{ + HTMLDocument *document = self.mixedTree; + + HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowDocument]; + NSArray *result = iterator.allObjects; + NSArray *expected = @[@"#document"]; + XCTAssertEqual(result.count, 1); + XCTAssertEqual([result.firstObject class], [HTMLDocument class]); + XCTAssertEqualObjects([result valueForKey:@"name"], expected); +} + +- (void)testShowDocumentType +{ + HTMLDocument *document = self.mixedTree; + + HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowDocumentType]; + NSArray *result = iterator.allObjects; + NSArray *expected = @[@"html"]; + XCTAssertEqual(result.count, 1); + XCTAssertEqual([result.firstObject class], [HTMLDocumentType class]); + XCTAssertEqualObjects([result valueForKey:@"name"], expected); +} + +- (void)testShowComment +{ + HTMLDocument *document = self.mixedTree; + + HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowComment]; + NSArray *result = iterator.allObjects; + NSArray *expected = @[@"#comment", @"#comment"]; + XCTAssertEqual(result.count, 2); + XCTAssertEqual([result[0] class], [HTMLComment class]); + XCTAssertEqual([result[1] class], [HTMLComment class]); + XCTAssertEqualObjects([result valueForKey:@"name"], expected); +} + +- (void)testShowText +{ + HTMLDocument *document = self.mixedTree; + + HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowText]; + NSArray *result = iterator.allObjects; + NSArray *expected = @[@"#text"]; + XCTAssertEqual(result.count, 1); + XCTAssertEqual([result.firstObject class], [HTMLText class]); + XCTAssertEqualObjects([result valueForKey:@"name"], expected); +} + +- (void)testShowElement +{ + HTMLDocument *document = self.mixedTree; + + HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowElement]; + NSArray *result = iterator.allObjects; + NSArray *expected = @[@"html", @"div"]; + XCTAssertEqual(result.count, 2); + XCTAssertEqual([result.firstObject class], [HTMLElement class]); + XCTAssertEqualObjects([result valueForKey:@"name"], expected); +} + +- (void)testShowBitmask +{ + HTMLDocument *document = self.mixedTree; + + HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:nil + showOptions:HTMLNodeFilterShowElement | HTMLNodeFilterShowText]; + NSArray *result = iterator.allObjects; + NSArray *expected = @[@"html", @"#text", @"div"]; + XCTAssertEqual(result.count, 3); + XCTAssertEqualObjects([result valueForKey:@"name"], expected); +} + +- (void)testNodeFilter +{ + HTMLDocument *document = self.mixedTree; + + HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:[CommentNodeFilter new] + showOptions:HTMLNodeFilterShowAll]; + + NSArray *result = iterator.allObjects; + NSArray *expected = @[@"#comment"]; + XCTAssertEqual(result.count, 1); + XCTAssertEqualObjects([result[0] data], @"This is a second Comment"); + XCTAssertEqualObjects([result valueForKey:@"name"], expected); +} + @end From 71fefa2fa95561dd4d62bcf96746290084a8a6b2 Mon Sep 17 00:00:00 2001 From: iska Date: Fri, 29 May 2015 20:16:17 +0200 Subject: [PATCH 22/40] Add methods to attach Node Iterators to the owner document node of the iterator's root This is a prerequisite to implement the iterator's removing steps. https://dom.spec.whatwg.org/#interface-nodeiterator --- HTMLKit/HTMLDocument.m | 14 ++++++++++++++ HTMLKit/HTMLNodeIterator.m | 28 +++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/HTMLKit/HTMLDocument.m b/HTMLKit/HTMLDocument.m index c910f50..1837124 100644 --- a/HTMLKit/HTMLDocument.m +++ b/HTMLKit/HTMLDocument.m @@ -18,6 +18,7 @@ @interface HTMLDocument () { HTMLDocument *_inertTemplateDocument; + NSMutableArray *_nodeIterators; } @property (nonatomic, assign) HTMLDocumentReadyState readyState; @end @@ -37,6 +38,7 @@ self = [super initWithName:@"#document" type:HTMLNodeDocument]; if (self) { _readyState = HTMLDocumentLoading; + _nodeIterators = [NSMutableArray new]; } return self; } @@ -64,6 +66,18 @@ } } +#pragma mark - Node Iterators + +- (void)attachNodeIterator:(HTMLNodeIterator *)iterator +{ + [_nodeIterators addObject:iterator]; +} + +- (void)detachNodeIterator:(HTMLNodeIterator *)iterator +{ + [_nodeIterators removeObject:iterator]; +} + #pragma mark - Mutation Algorithms - (HTMLNode *)adoptNode:(HTMLNode *)node diff --git a/HTMLKit/HTMLNodeIterator.m b/HTMLKit/HTMLNodeIterator.m index 370155e..7b8314e 100644 --- a/HTMLKit/HTMLNodeIterator.m +++ b/HTMLKit/HTMLNodeIterator.m @@ -7,6 +7,7 @@ // #import "HTMLNodeIterator.h" +#import "HTMLDocument.h" #import "HTMLNode.h" typedef NS_ENUM(short, TraverseDirection) @@ -15,6 +16,11 @@ typedef NS_ENUM(short, TraverseDirection) TraverseDirectionPrevious }; +@interface HTMLDocument (Private) +- (void)attachNodeIterator:(HTMLNodeIterator *)iterator; +- (void)detachNodeIterator:(HTMLNodeIterator *)iterator; +@end + @interface HTMLNodeIterator () { HTMLNode *_root; @@ -23,6 +29,8 @@ typedef NS_ENUM(short, TraverseDirection) @implementation HTMLNodeIterator +#pragma mark - Lifecycle + - (instancetype)initWithNode:(HTMLNode *)node { return [self initWithNode:node filter:nil]; @@ -45,10 +53,18 @@ typedef NS_ENUM(short, TraverseDirection) _whatToShow = showOptions; _referenceNode = _root; _pointerBeforeReferenceNode = YES; + [_root.ownerDocument attachNodeIterator:self]; } return self; } +- (void)dealloc +{ + [_root.ownerDocument detachNodeIterator:self]; +} + +#pragma mark - Traversal + - (HTMLNode *)traverseInDirection:(TraverseDirection)direction { HTMLNode *node = self.referenceNode; @@ -129,11 +145,6 @@ NS_INLINE HTMLNodeFilterValue FilterNode(HTMLNodeIterator *iterator, HTMLNode *n return [iterator.filter acceptNode:node]; } -- (id)nextObject -{ - return self.nextNode; -} - - (HTMLNode *)nextNode { return [self traverseInDirection:TraverseDirectionNext]; @@ -144,4 +155,11 @@ NS_INLINE HTMLNodeFilterValue FilterNode(HTMLNodeIterator *iterator, HTMLNode *n return [self traverseInDirection:TraverseDirectionPrevious]; } +#pragma mark - NSEnumerator + +- (id)nextObject +{ + return self.nextNode; +} + @end From d002c6cedd215c98c04c931964074b97fb6faf39 Mon Sep 17 00:00:00 2001 From: iska Date: Sun, 31 May 2015 16:53:54 +0200 Subject: [PATCH 23/40] Add HTML Node methods for comparing node positions in a tree https://dom.spec.whatwg.org/#dom-node-comparedocumentpositionother --- HTMLKit/HTMLNode.h | 15 +++++++++ HTMLKit/HTMLNode.m | 80 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/HTMLKit/HTMLNode.h b/HTMLKit/HTMLNode.h index d9078f2..27ece82 100644 --- a/HTMLKit/HTMLNode.h +++ b/HTMLKit/HTMLNode.h @@ -25,6 +25,17 @@ typedef NS_ENUM(short, HTMLNodeType) HTMLNodeNotation = 12 // historical }; +typedef NS_ENUM(unsigned short, HTMLDocumentPosition) +{ + HTMLDocumentPositionEquivalent = 0x0, + HTMLDocumentPositionDisconnected = 0x01, + HTMLDocumentPositionPreceding = 0x02, + HTMLDocumentPositionFollowing = 0x04, + HTMLDocumentPositionContains = 0x08, + HTMLDocumentPositionContainedBy = 0x10, + HTMLDocumentPositionImplementationSpecific = 0x20 +}; + @class HTMLDocument; @class HTMLElement; @@ -96,6 +107,10 @@ typedef NS_ENUM(short, HTMLNodeType) - (void)removeAllChildNodes; +- (HTMLDocumentPosition)compareDocumentPositionWithNode:(HTMLNode *)node; +- (BOOL)isDescendantOfNode:(HTMLNode *)node; +- (BOOL)containsNode:(HTMLNode *)node; + - (void)enumerateChildNodesUsingBlock:(void (^)(HTMLNode *node, NSUInteger idx, BOOL *stop))block; - (void)enumerateChildElementsUsingBlock:(void (^)(HTMLElement *element, NSUInteger idx, BOOL *stop))block; diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index f65cf9b..ba8cc9a 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -249,6 +249,86 @@ [(NSMutableOrderedSet *)self.childNodes removeAllObjects]; } +- (HTMLDocumentPosition)compareDocumentPositionWithNode:(HTMLNode *)otherNode +{ + if (otherNode == nil) { + return HTMLDocumentPositionDisconnected; + } + + if (self == otherNode) { + return HTMLDocumentPositionEquivalent; + } + + NSArray * (^ ancestorNodes) (HTMLNode *) = ^ NSArray * (HTMLNode *node) { + NSMutableArray *ancestors = [NSMutableArray array]; + for (HTMLNode *node = self; node; node = node.parentNode) { + [ancestors addObject:node]; + } + return ancestors; + }; + + NSArray *ancestors1 = ancestorNodes(self); + NSArray *ancestors2 = ancestorNodes(otherNode); + + if (ancestors1.lastObject != ancestors2.lastObject) { + return HTMLDocumentPositionDisconnected | + HTMLDocumentPositionImplementationSpecific | + HTMLDocumentPositionFollowing; + } + + for (NSUInteger i = MIN(ancestors1.count - 1, ancestors2.count - 1); i; --i) { + HTMLNode *child1 = ancestors1[i]; + HTMLNode *child2 = ancestors2[i]; + + if (child1 != child2) { + for (HTMLNode *sibling = child1.nextSibling; sibling; sibling = sibling.nextSibling) { + if (sibling == child2) { + return HTMLDocumentPositionFollowing; + } + } + return HTMLDocumentPositionPreceding; + } + } + + if (ancestors1.count < ancestors2.count) { + return HTMLDocumentPositionContainedBy | HTMLDocumentPositionFollowing; + } else { + return HTMLDocumentPositionContains | HTMLDocumentPositionPreceding; + } +} + +- (BOOL)isDescendantOfNode:(HTMLNode *)otherNode +{ + if (otherNode == nil) { + return NO; + } + + if (self.ownerDocument != otherNode.ownerDocument) { + return NO; + } + + if (!otherNode.hasChildNodes) { + return NO; + } + + if (otherNode.nodeType == HTMLNodeDocument) { + return self.nodeType != HTMLNodeDocument && self.ownerDocument == otherNode; + } + + for (HTMLNode *parentNode = self.parentNode; parentNode; parentNode = parentNode.parentNode) { + if (parentNode == otherNode) { + return YES; + } + } + + return NO; +} + +- (BOOL)containsNode:(HTMLNode *)otherNode +{ + return self == otherNode || [otherNode isDescendantOfNode:self]; +} + #pragma mark - Enumeration - (void)enumerateChildNodesUsingBlock:(void (^)(HTMLNode *node, NSUInteger idx, BOOL *stop))block From a0fd89f417f52d2493e4eab922b219e0bf474ab6 Mon Sep 17 00:00:00 2001 From: iska Date: Tue, 2 Jun 2015 01:05:44 +0200 Subject: [PATCH 24/40] Move test class for Ordered Dictionary into own group --- HTMLKit.xcodeproj/project.pbxproj | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index 1c13dba..18382a7 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -361,7 +361,6 @@ isa = PBXGroup; children = ( 623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */, - 624B9FB41AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m */, 624FC3791AE591D80015DDF9 /* HTMLKitNodesTests.m */, 62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */, ); @@ -376,6 +375,14 @@ name = Categories; sourceTree = ""; }; + 624E1A2D1B1D1C8A00E66AAC /* Structures */ = { + isa = PBXGroup; + children = ( + 624B9FB41AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m */, + ); + name = Structures; + sourceTree = ""; + }; 625A14A219C7829400AD0C32 = { isa = PBXGroup; children = ( @@ -451,6 +458,7 @@ 623975581AC362A5007E26F1 /* Tree Construction */, 624B9FB71AE072CB00646C4C /* Nodes */, 624B9FB81AE072D500646C4C /* Categories */, + 624E1A2D1B1D1C8A00E66AAC /* Structures */, 625A14CB19C7829400AD0C32 /* Supporting Files */, ); name = Tests; From 2f1555e93d9970c6f9cbd67b3d4dfac91a67c372 Mon Sep 17 00:00:00 2001 From: iska Date: Tue, 2 Jun 2015 01:06:13 +0200 Subject: [PATCH 25/40] Rename group for DOM tests --- HTMLKit.xcodeproj/project.pbxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index 18382a7..4f4907f 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -357,14 +357,14 @@ name = "Tree Construction"; sourceTree = ""; }; - 624B9FB71AE072CB00646C4C /* Nodes */ = { + 624B9FB71AE072CB00646C4C /* DOM */ = { isa = PBXGroup; children = ( 623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */, 624FC3791AE591D80015DDF9 /* HTMLKitNodesTests.m */, 62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */, ); - name = Nodes; + name = DOM; sourceTree = ""; }; 624B9FB81AE072D500646C4C /* Categories */ = { @@ -456,7 +456,7 @@ children = ( 6236738C1AC0CD2400FF89B3 /* Tokenizer */, 623975581AC362A5007E26F1 /* Tree Construction */, - 624B9FB71AE072CB00646C4C /* Nodes */, + 624B9FB71AE072CB00646C4C /* DOM */, 624B9FB81AE072D500646C4C /* Categories */, 624E1A2D1B1D1C8A00E66AAC /* Structures */, 625A14CB19C7829400AD0C32 /* Supporting Files */, From 0baa343e95677bf843e2d405faf4c34536e86be1 Mon Sep 17 00:00:00 2001 From: iska Date: Fri, 5 Jun 2015 16:46:36 +0200 Subject: [PATCH 26/40] Add Document methods to access the root, head & body elements The implementation will be changed/adapted later when the CSS Selectors are ready. --- HTMLKit/HTMLDocument.h | 6 ++++++ HTMLKit/HTMLDocument.m | 48 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/HTMLKit/HTMLDocument.h b/HTMLKit/HTMLDocument.h index 7c0655f..222ea81 100644 --- a/HTMLKit/HTMLDocument.h +++ b/HTMLKit/HTMLDocument.h @@ -27,6 +27,12 @@ typedef NS_ENUM(short, HTMLDocumentReadyState) @property (nonatomic, assign, readonly) HTMLDocumentReadyState readyState; +@property (nonatomic, strong) HTMLElement *rootElement; + +@property (nonatomic, strong) HTMLElement *head; + +@property (nonatomic, strong) HTMLElement *body; + + (instancetype)documentWithString:(NSString *)string; - (HTMLNode *)adoptNode:(HTMLNode *)node; diff --git a/HTMLKit/HTMLDocument.m b/HTMLKit/HTMLDocument.m index 1837124..912f269 100644 --- a/HTMLKit/HTMLDocument.m +++ b/HTMLKit/HTMLDocument.m @@ -8,6 +8,7 @@ #import "HTMLDocument.h" #import "HTMLParser.h" +#import "HTMLNodeIterator.h" #import "HTMLKitDOMExceptions.h" @interface HTMLNode (Private) @@ -66,6 +67,53 @@ } } +#pragma mark - + +- (HTMLElement *)rootElement +{ + for (HTMLNode *node = self.firstChiledNode; node; node = node.nextSibling) { + if (node.nodeType == HTMLNodeElement) { + return node.asElement; + } + } + return nil; +} + +- (void)setRootElement:(HTMLElement *)rootElement +{ + [self replaceChildNode:self.rootElement withNode:rootElement]; +} + +- (HTMLElement *)head +{ + for (HTMLNode *node in [self nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowElement]) { + if ([node.asElement.tagName isEqualToString:@"head"]) { + return node.asElement; + } + } + return nil; +} + +- (void)setHead:(HTMLElement *)head +{ + [self replaceChildNode:self.head withNode:head]; +} + +- (HTMLElement *)body +{ + for (HTMLNode *node in [self nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowElement]) { + if ([node.asElement.tagName isEqualToString:@"body"]) { + return node.asElement; + } + } + return nil; +} + +- (void)setBody:(HTMLElement *)body +{ + [self replaceChildNode:self.body withNode:body]; +} + #pragma mark - Node Iterators - (void)attachNodeIterator:(HTMLNodeIterator *)iterator From d4bb3c6636df003a4ee203a35fbb86b37360683d Mon Sep 17 00:00:00 2001 From: iska Date: Fri, 5 Jun 2015 16:47:37 +0200 Subject: [PATCH 27/40] Add implementation for the removing steps of the HTML Node Iterator https://dom.spec.whatwg.org/#interface-nodeiterator --- HTMLKit/HTMLDocument.m | 17 ++ HTMLKit/HTMLNode.m | 14 ++ HTMLKit/HTMLNodeIterator.m | 40 ++++ HTMLKitTests/HTMLKitNodeIteratorTests.m | 264 +++++++++++++++++++++++- 4 files changed, 333 insertions(+), 2 deletions(-) diff --git a/HTMLKit/HTMLDocument.m b/HTMLKit/HTMLDocument.m index 912f269..9b8d2b3 100644 --- a/HTMLKit/HTMLDocument.m +++ b/HTMLKit/HTMLDocument.m @@ -16,6 +16,12 @@ @property (nonatomic, weak) HTMLNode *parentNode; @end +@interface HTMLNodeIterator (Private) +- (void)runRemovingStepsForNode:(HTMLNode *)oldNode + withOldParent:(HTMLNode *)oldParent + andOldPreviousSibling:(HTMLNode *)oldPreviousSibling; +@end + @interface HTMLDocument () { HTMLDocument *_inertTemplateDocument; @@ -126,6 +132,17 @@ [_nodeIterators removeObject:iterator]; } +- (void)runRemovingStepsForNode:(HTMLNode *)oldNode + withOldParent:(HTMLNode *)oldParent + andOldPreviousSibling:(HTMLNode *)oldPreviousSibling +{ + for (HTMLNodeIterator *iterator in _nodeIterators) { + [iterator runRemovingStepsForNode:oldNode + withOldParent:oldParent + andOldPreviousSibling:oldPreviousSibling]; + } +} + #pragma mark - Mutation Algorithms - (HTMLNode *)adoptNode:(HTMLNode *)node diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index ba8cc9a..bb75fe1 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -14,6 +14,12 @@ #import "HTMLComment.h" #import "HTMLKitDOMExceptions.h" +@interface HTMLDocument (Private) +- (void)runRemovingStepsForNode:(HTMLNode *)oldNode + withOldParent:(HTMLNode *)oldParent + andOldPreviousSibling:(HTMLNode *)oldPreviousSibling; +@end + @interface HTMLNode () { NSMutableOrderedSet *_childNodes; @@ -224,8 +230,16 @@ NSStringFromSelector(_cmd), child]; } + HTMLNode *oldNode = child; + HTMLNode *oldParent = child.parentNode; + HTMLNode *oldPreviousSibling = child.previousSibling; + [(NSMutableOrderedSet *)self.childNodes removeObject:child]; child.parentNode = nil; + + [self.ownerDocument runRemovingStepsForNode:oldNode + withOldParent:oldParent + andOldPreviousSibling:oldPreviousSibling]; return child; } diff --git a/HTMLKit/HTMLNodeIterator.m b/HTMLKit/HTMLNodeIterator.m index 7b8314e..4f93445 100644 --- a/HTMLKit/HTMLNodeIterator.m +++ b/HTMLKit/HTMLNodeIterator.m @@ -63,6 +63,46 @@ typedef NS_ENUM(short, TraverseDirection) [_root.ownerDocument detachNodeIterator:self]; } +#pragma mark - Removing Steps + +- (void)runRemovingStepsForNode:(HTMLNode *)oldNode + withOldParent:(HTMLNode *)oldParent + andOldPreviousSibling:(HTMLNode *)oldPreviousSibling +{ + if ([oldNode containsNode:_root]) { + return; + } + + if (![oldNode containsNode:_referenceNode]) { + return; + } + + if (_pointerBeforeReferenceNode) { + HTMLNode *nextSibling = oldPreviousSibling != nil ? oldPreviousSibling.nextSibling : oldParent.firstChiledNode; + if (nextSibling != nil) { + _referenceNode = nextSibling; + return; + } + + HTMLNode *next = FollowingNode(oldParent, _root); + if ([_root containsNode:next]) { + _referenceNode = next; + return; + } + + _pointerBeforeReferenceNode = NO; + } + + HTMLNode * (^ lastInclusiveDescendant) (HTMLNode *) = ^ HTMLNode * (HTMLNode *node) { + while (node.lastChildNode) { + node = node.lastChildNode; + } + return node; + }; + + _referenceNode = oldPreviousSibling != nil ? lastInclusiveDescendant(oldPreviousSibling) : oldParent; +} + #pragma mark - Traversal - (HTMLNode *)traverseInDirection:(TraverseDirection)direction diff --git a/HTMLKitTests/HTMLKitNodeIteratorTests.m b/HTMLKitTests/HTMLKitNodeIteratorTests.m index 9eb9c7f..c702e6f 100644 --- a/HTMLKitTests/HTMLKitNodeIteratorTests.m +++ b/HTMLKitTests/HTMLKitNodeIteratorTests.m @@ -32,7 +32,7 @@ @implementation HTMLKitNodeIteratorTests -#pragma mark - Elements +#pragma mark - Test DOM - (HTMLElement *)div { @@ -133,7 +133,25 @@ return document; } -#pragma mark - Tests +- (HTMLDocument *)document +{ + NSString *htmlString = + @"" + @"" + @"" + @"Title" + @"" + @"" + @"HelloWorld!HTML Kit" + @"

This is an Important paragraph

" + @"" + @""; + + HTMLDocument *document = [HTMLDocument documentWithString:htmlString]; + return document; +} + +#pragma mark - Test Iterator - (void)testNodeIteratorInit { @@ -228,6 +246,8 @@ XCTAssertEqualObjects([result valueForKey:@"name"], expected); } +#pragma mark - Test Iterator ShowOptions (WhatToShow) + - (void)testShowDocument { HTMLDocument *document = self.mixedTree; @@ -301,6 +321,8 @@ XCTAssertEqualObjects([result valueForKey:@"name"], expected); } +#pragma mark - Test Iterator Filter + - (void)testNodeFilter { HTMLDocument *document = self.mixedTree; @@ -315,4 +337,242 @@ XCTAssertEqualObjects([result valueForKey:@"name"], expected); } +#pragma mark - Test Removing Steps + +/* + Test cases for the Removing Steps + https://dom.spec.whatwg.org/#interface-nodeiterator + + Following DOM is used: + +| +| +| +| "Title" +| <body> +| <span> +| "Hello" +| <strong> +| "World!" +| <strong> +| "HTML " +| <!-- This is a Comment! --> +| " Kit" +| <p> +| "This is an " +| <em> +| "Important" +| " paragraph" +*/ + +static void (^ RemoveThenInsertNode)(HTMLNode *) = ^ (HTMLNode *node) { + HTMLNode *parent = node.parentNode; + HTMLNode *nextSibling = node.nextSibling; + [parent removeChildNode:node]; + [parent insertNode:node beforeChildNode:nextSibling]; +}; + +static void (^ IterateUpToNode)(HTMLNodeIterator *, HTMLNode *) = ^ (HTMLNodeIterator *iterator, HTMLNode *target) { + for(HTMLNode *node = iterator.referenceNode; node && (node != target); node = iterator.nextNode); +}; + +static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node) { + while (node.lastChildNode) { + node = node.lastChildNode; + } + return node; +}; + +- (void)testThatRemovingRootNodeShouldNotAffectIterator +{ + HTMLDocument *document = self.document; + HTMLNode *node = document.body.firstChiledNode; // <span> + + HTMLNodeIterator *iterator = node.nodeIterator; + + [document.body removeChildNode:node]; + + XCTAssertEqualObjects(iterator.root, node); + XCTAssertEqualObjects(iterator.referenceNode, node); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES); + XCTAssertEqualObjects(iterator.referenceNode.parentNode, nil); +} + +- (void)testThatRemovingANonInclusiveAnscestorOfReferenceShouldNotAffectIterator +{ + HTMLDocument *document = self.document; + HTMLNode *body = document.body; + + HTMLNodeIterator *iterator = body.nodeIterator; + + [iterator nextNode]; // Reference node: <body> + [iterator nextNode]; // Reference node: <span> + + RemoveThenInsertNode(iterator.root.childNodes[1]); // Remove <p> + + XCTAssertEqualObjects(iterator.root, body); + XCTAssertEqualObjects(iterator.referenceNode, body.firstChiledNode); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO); +} + +- (void)testThatRemovingReferenceNodeShouldUpdateIterator_NilOldPreviousSibling +{ + HTMLDocument *document = self.document; + + HTMLNodeIterator *iterator = document.body.nodeIterator; + + [iterator nextNode]; // Reference node: <body> + + HTMLNode *node = iterator.nextNode; // Reference node: <span> + RemoveThenInsertNode(node); // Remove <span> with old previos sibling being nil + + XCTAssertEqualObjects(iterator.referenceNode, iterator.root); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO); + + HTMLNode *next = iterator.nextNode; // "Hello" + XCTAssertEqualObjects(next, iterator.root.firstChiledNode); +} + +- (void)testThatRemovingReferenceNodeShouldUpdateIterator_NonNilOldPreviousSibling_NotBeforeReference +{ + HTMLDocument *document = self.document; + HTMLNode *body = document.body; + + HTMLNodeIterator *iterator = body.nodeIterator; + + HTMLNode *node = iterator.root.childNodes[1]; // <p> + IterateUpToNode(iterator, node); // Reference node: <p>, pointer-before-reference: NO + RemoveThenInsertNode(node); // Remove <p> with old previos sibling being <span> + + XCTAssertEqualObjects(iterator.referenceNode, LastDescendant(body.firstChiledNode)); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO); +} + +- (void)testThatRemovingReferenceNodeShouldUpdateIterator_NonNilOldPreviousSibling_BeforeReference +{ + HTMLDocument *document = self.document; + HTMLNode *body = document.body; + + HTMLNodeIterator *iterator = body.nodeIterator; + + HTMLNode *node = iterator.root.childNodes[1]; // <p> + IterateUpToNode(iterator, node); // Reference node: <p>, pointer-before-reference: NO + [iterator previousNode]; // pointer-before-reference: YES + RemoveThenInsertNode(node); // Remove <p> with old previos sibling being <span> + + XCTAssertEqualObjects(iterator.referenceNode, body.firstChiledNode); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES); +} + +- (void)testThatRemovingThenReinsertingReferenceNodeAfterNextShouldReturnItAgain +{ + HTMLDocument *document = self.document; + HTMLNodeIterator *iterator = document.body.nodeIterator; + + [iterator nextNode]; // Reference node: <body> + + HTMLNode *node = iterator.nextNode; // <span> + RemoveThenInsertNode(node); + + XCTAssertEqualObjects(iterator.referenceNode, iterator.root); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO); + + HTMLNode *next = iterator.nextNode; + XCTAssertEqualObjects(next, node); +} + +- (void)testThatRemovingThenReinsertingReferenceNodeAfterPreviousShouldReturnItAgain +{ + HTMLDocument *document = self.document; + HTMLNodeIterator *iterator = document.body.nodeIterator; + + [iterator nextNode]; // Reference node: <body> + [iterator nextNode]; // Reference node: <span> + + HTMLNode *node = iterator.previousNode; // Reference node: <span>, pointer-before-reference: YES + HTMLNode *next = node.nextSibling; // <p> + RemoveThenInsertNode(node); + + XCTAssertEqualObjects(iterator.referenceNode, next); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES); + + HTMLNode *previous = iterator.previousNode; + XCTAssertEqualObjects(previous, LastDescendant(node)); +} + +- (void)testThatRemovingParentOfReferenceNodeShouldUpdateIterator_NotBeforeReference +{ + HTMLDocument *document = self.document; + HTMLNode *body = document.body; + + HTMLNodeIterator *iterator = body.nodeIterator; + HTMLNode *parent = body.childNodes[1]; + + IterateUpToNode(iterator, parent); // Reference node: <p>, pointer-before-reference: NO + [iterator nextNode]; // Reference node: "This is an " + RemoveThenInsertNode(parent); + + XCTAssertEqualObjects(iterator.referenceNode, LastDescendant(body.firstChiledNode)); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO); +} + +- (void)testThatRemovingParentOfReferenceNodeShouldUpdateIterator_BeforeReference +{ + HTMLDocument *document = self.document; + HTMLNode *body = document.body; + + HTMLNodeIterator *iterator = body.nodeIterator; + HTMLNode *parent = body.childNodes[1]; + + IterateUpToNode(iterator, parent); // Reference node: <p>, pointer-before-reference: NO + [iterator nextNode]; // Reference node: "This is an " + [iterator previousNode]; // pointer-before-reference: YES + RemoveThenInsertNode(parent); + + XCTAssertEqualObjects(iterator.referenceNode, body.firstChiledNode); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES); +} + +- (void)testRemoveReferenceNode_NilPreviousSibling_NonNilParentFirstChild +{ + HTMLDocument *document = self.document; + HTMLNode *body = document.body; + + HTMLNodeIterator *iterator = body.nodeIterator; + + [iterator nextNode]; // Reference node: <body> + [iterator nextNode]; // Reference node: <span> + + HTMLNode *node = iterator.previousNode; // Reference node: <span>, pointer-before-reference: YES + XCTAssertNil(node.previousSibling); + XCTAssertNotNil(node.nextSibling); + + HTMLNode *nextSibling = node.nextSibling; // <p> + RemoveThenInsertNode(node); + + XCTAssertEqualObjects(iterator.referenceNode, nextSibling); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES); + + HTMLNode *next = iterator.nextNode; // <p> + XCTAssertNotEqualObjects(next, node); + XCTAssertEqualObjects(next, nextSibling); +} + +- (void)testRemoveReferenceNode_NodeAfterOldParentIsOutsideRoot_BeforeReference +{ + HTMLDocument *document = self.document; + HTMLNode *body = document.body; + + body.innerHTML = @"<div><p><a></a></p></div><div></div>"; + + HTMLNodeIterator *iterator = body.firstChiledNode.nodeIterator; + + IterateUpToNode(iterator, LastDescendant(body.firstChiledNode)); // Referecne node: <a> + HTMLNode *node = [iterator previousNode]; // pointer-before-reference: YES + RemoveThenInsertNode(node); + + XCTAssertEqualObjects(iterator.referenceNode, iterator.root.firstChiledNode); + XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO); +} + @end From c1b18f527cf1757721970e7fed70f3191aa535bd Mon Sep 17 00:00:00 2001 From: iska <iska.gp@gmail.com> Date: Fri, 5 Jun 2015 16:53:06 +0200 Subject: [PATCH 28/40] Refactor Node Iterator's initializers so that the filter argument is last --- HTMLKit/HTMLDocument.m | 4 ++-- HTMLKit/HTMLNode.h | 4 ++-- HTMLKit/HTMLNode.m | 8 ++++---- HTMLKit/HTMLNodeIterator.h | 5 ++--- HTMLKit/HTMLNodeIterator.m | 4 ++-- HTMLKitTests/HTMLKitNodeIteratorTests.m | 18 +++++++++--------- 6 files changed, 21 insertions(+), 22 deletions(-) diff --git a/HTMLKit/HTMLDocument.m b/HTMLKit/HTMLDocument.m index 9b8d2b3..a4990dc 100644 --- a/HTMLKit/HTMLDocument.m +++ b/HTMLKit/HTMLDocument.m @@ -92,7 +92,7 @@ - (HTMLElement *)head { - for (HTMLNode *node in [self nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowElement]) { + for (HTMLNode *node in [self nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]) { if ([node.asElement.tagName isEqualToString:@"head"]) { return node.asElement; } @@ -107,7 +107,7 @@ - (HTMLElement *)body { - for (HTMLNode *node in [self nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowElement]) { + for (HTMLNode *node in [self nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]) { if ([node.asElement.tagName isEqualToString:@"body"]) { return node.asElement; } diff --git a/HTMLKit/HTMLNode.h b/HTMLKit/HTMLNode.h index 27ece82..c681825 100644 --- a/HTMLKit/HTMLNode.h +++ b/HTMLKit/HTMLNode.h @@ -116,8 +116,8 @@ typedef NS_ENUM(unsigned short, HTMLDocumentPosition) - (void)enumerateChildElementsUsingBlock:(void (^)(HTMLElement *element, NSUInteger idx, BOOL *stop))block; - (HTMLNodeIterator *)nodeIterator; -- (HTMLNodeIterator *)nodeIteratorWithFilter:(id<HTMLNodeFilter>)filter - showOptions:(HTMLNodeFilterShowOptions)showOptions; +- (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions + filter:(id<HTMLNodeFilter>)filter; - (NSString *)treeDescription; @end diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index bb75fe1..c4d166f 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -371,13 +371,13 @@ - (HTMLNodeIterator *)nodeIterator { - return [self nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowAll]; + return [self nodeIteratorWithShowOptions:HTMLNodeFilterShowAll filter:nil]; } -- (HTMLNodeIterator *)nodeIteratorWithFilter:(id<HTMLNodeFilter>)filter - showOptions:(HTMLNodeFilterShowOptions)showOptions +- (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions + filter:(id<HTMLNodeFilter>)filter { - return [[HTMLNodeIterator alloc] initWithNode:self filter:filter showOptions:showOptions]; + return [[HTMLNodeIterator alloc] initWithNode:self showOptions:showOptions filter:filter]; } #ifndef HTMLKIT_NO_DOM_CHECKS diff --git a/HTMLKit/HTMLNodeIterator.h b/HTMLKit/HTMLNodeIterator.h index d6c0cb7..ed8bd2b 100644 --- a/HTMLKit/HTMLNodeIterator.h +++ b/HTMLKit/HTMLNodeIterator.h @@ -23,9 +23,8 @@ - (instancetype)initWithNode:(HTMLNode *)node filter:(id<HTMLNodeFilter>)filter; - (instancetype)initWithNode:(HTMLNode *)node - filter:(id<HTMLNodeFilter>)filter - showOptions:(HTMLNodeFilterShowOptions)showOptions; - + showOptions:(HTMLNodeFilterShowOptions)showOptions + filter:(id<HTMLNodeFilter>)filter; - (HTMLNode *)nextNode; - (HTMLNode *)previousNode; diff --git a/HTMLKit/HTMLNodeIterator.m b/HTMLKit/HTMLNodeIterator.m index 4f93445..a79ae6d 100644 --- a/HTMLKit/HTMLNodeIterator.m +++ b/HTMLKit/HTMLNodeIterator.m @@ -39,12 +39,12 @@ typedef NS_ENUM(short, TraverseDirection) - (instancetype)initWithNode:(HTMLNode *)node filter:(id<HTMLNodeFilter>)filter { - return [self initWithNode:node filter:nil showOptions:HTMLNodeFilterShowAll]; + return [self initWithNode:node showOptions:HTMLNodeFilterShowAll filter:filter]; } - (instancetype)initWithNode:(HTMLNode *)node - filter:(id<HTMLNodeFilter>)filter showOptions:(HTMLNodeFilterShowOptions)showOptions + filter:(id<HTMLNodeFilter>)filter { self = [super init]; if (self) { diff --git a/HTMLKitTests/HTMLKitNodeIteratorTests.m b/HTMLKitTests/HTMLKitNodeIteratorTests.m index c702e6f..4fadae1 100644 --- a/HTMLKitTests/HTMLKitNodeIteratorTests.m +++ b/HTMLKitTests/HTMLKitNodeIteratorTests.m @@ -252,7 +252,7 @@ { HTMLDocument *document = self.mixedTree; - HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowDocument]; + HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowDocument filter:nil]; NSArray *result = iterator.allObjects; NSArray *expected = @[@"#document"]; XCTAssertEqual(result.count, 1); @@ -264,7 +264,7 @@ { HTMLDocument *document = self.mixedTree; - HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowDocumentType]; + HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowDocumentType filter:nil]; NSArray *result = iterator.allObjects; NSArray *expected = @[@"html"]; XCTAssertEqual(result.count, 1); @@ -276,7 +276,7 @@ { HTMLDocument *document = self.mixedTree; - HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowComment]; + HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowComment filter:nil]; NSArray *result = iterator.allObjects; NSArray *expected = @[@"#comment", @"#comment"]; XCTAssertEqual(result.count, 2); @@ -289,7 +289,7 @@ { HTMLDocument *document = self.mixedTree; - HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowText]; + HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowText filter:nil]; NSArray *result = iterator.allObjects; NSArray *expected = @[@"#text"]; XCTAssertEqual(result.count, 1); @@ -301,7 +301,7 @@ { HTMLDocument *document = self.mixedTree; - HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:nil showOptions:HTMLNodeFilterShowElement]; + HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]; NSArray *result = iterator.allObjects; NSArray *expected = @[@"html", @"div"]; XCTAssertEqual(result.count, 2); @@ -313,8 +313,8 @@ { HTMLDocument *document = self.mixedTree; - HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:nil - showOptions:HTMLNodeFilterShowElement | HTMLNodeFilterShowText]; + HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowElement | HTMLNodeFilterShowText + filter:nil]; NSArray *result = iterator.allObjects; NSArray *expected = @[@"html", @"#text", @"div"]; XCTAssertEqual(result.count, 3); @@ -327,8 +327,8 @@ { HTMLDocument *document = self.mixedTree; - HTMLNodeIterator *iterator = [document nodeIteratorWithFilter:[CommentNodeFilter new] - showOptions:HTMLNodeFilterShowAll]; + HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowAll + filter:[CommentNodeFilter new]]; NSArray *result = iterator.allObjects; NSArray *expected = @[@"#comment"]; From dc3de7a47091d6f865690e063d2bde488ad45a75 Mon Sep 17 00:00:00 2001 From: iska <iska.gp@gmail.com> Date: Fri, 5 Jun 2015 17:05:22 +0200 Subject: [PATCH 29/40] Remove the HTMLNodeFilterValue enum since Reject and Skip are semantically equivalent --- HTMLKit/HTMLNodeFilter.h | 9 +-------- HTMLKit/HTMLNodeIterator.m | 8 ++++---- HTMLKitTests/HTMLKitNodeIteratorTests.m | 6 +++--- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/HTMLKit/HTMLNodeFilter.h b/HTMLKit/HTMLNodeFilter.h index 021fe5a..40785a3 100644 --- a/HTMLKit/HTMLNodeFilter.h +++ b/HTMLKit/HTMLNodeFilter.h @@ -8,13 +8,6 @@ #import <Foundation/Foundation.h> -typedef NS_ENUM(unsigned short, HTMLNodeFilterValue) -{ - HTMLNodeFilterAccept = 1, - HTMLNodeFilterReject = 2, - HTMLNodeFilterSkip = 3 -}; - typedef NS_ENUM(unsigned long, HTMLNodeFilterShowOptions) { HTMLNodeFilterShowAll = 0xFFFFFFFF, @@ -30,6 +23,6 @@ typedef NS_ENUM(unsigned long, HTMLNodeFilterShowOptions) @protocol HTMLNodeFilter <NSObject> -- (HTMLNodeFilterValue)acceptNode:(HTMLNode *)node; +- (BOOL)acceptNode:(HTMLNode *)node; @end diff --git a/HTMLKit/HTMLNodeIterator.m b/HTMLKit/HTMLNodeIterator.m index a79ae6d..a23de3d 100644 --- a/HTMLKit/HTMLNodeIterator.m +++ b/HTMLKit/HTMLNodeIterator.m @@ -128,7 +128,7 @@ typedef NS_ENUM(short, TraverseDirection) } beforeNode = YES; } - } while (FilterNode(self, node) != HTMLNodeFilterAccept); + } while (!FilterNode(self, node)); _referenceNode = node; _pointerBeforeReferenceNode = beforeNode; @@ -171,15 +171,15 @@ NS_INLINE HTMLNode * FollowingNode(HTMLNode *node, HTMLNode *root) return nil; } -NS_INLINE HTMLNodeFilterValue FilterNode(HTMLNodeIterator *iterator, HTMLNode *node) +NS_INLINE BOOL FilterNode(HTMLNodeIterator *iterator, HTMLNode *node) { unsigned long nthBit = (1 << (node.nodeType - 1)) & iterator.whatToShow; if (!nthBit) { - return HTMLNodeFilterSkip; + return NO; } if (iterator.filter == nil) { - return HTMLNodeFilterAccept; + return YES; } return [iterator.filter acceptNode:node]; diff --git a/HTMLKitTests/HTMLKitNodeIteratorTests.m b/HTMLKitTests/HTMLKitNodeIteratorTests.m index 4fadae1..a9b05f2 100644 --- a/HTMLKitTests/HTMLKitNodeIteratorTests.m +++ b/HTMLKitTests/HTMLKitNodeIteratorTests.m @@ -14,14 +14,14 @@ @implementation CommentNodeFilter -- (HTMLNodeFilterValue)acceptNode:(HTMLNode *)node +- (BOOL)acceptNode:(HTMLNode *)node { if (node.nodeType == HTMLNodeComment) { if ([[(HTMLComment *)node data] rangeOfString:@"second"].location != NSNotFound) { - return HTMLNodeFilterAccept; + return YES; } } - return HTMLNodeFilterReject; + return NO; } @end From 40400864d8dae48c5933894e895c5e33a00b467b Mon Sep 17 00:00:00 2001 From: iska <iska.gp@gmail.com> Date: Fri, 5 Jun 2015 18:06:23 +0200 Subject: [PATCH 30/40] Add block-based API for Node Filter - HTMLNodeFilterBlock is a block-based class implementation conforming to HTMLNodeFilter - HTMLNode & NodeIterator get block-based initializers --- HTMLKit.xcodeproj/project.pbxproj | 6 ++++ HTMLKit/HTMLNode.h | 3 ++ HTMLKit/HTMLNode.m | 6 ++++ HTMLKit/HTMLNodeFilter.h | 6 ++++ HTMLKit/HTMLNodeFilter.m | 42 +++++++++++++++++++++++++ HTMLKit/HTMLNodeIterator.h | 4 +++ HTMLKit/HTMLNodeIterator.m | 11 +++++++ HTMLKitTests/HTMLKitNodeIteratorTests.m | 27 +++++----------- 8 files changed, 86 insertions(+), 19 deletions(-) create mode 100644 HTMLKit/HTMLNodeFilter.m diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index 4f4907f..350eb6c 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -66,6 +66,8 @@ 624493AC19CD0CBE00BCDDF4 /* HTMLToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 624493AA19CD0CBE00BCDDF4 /* HTMLToken.h */; }; 624493AD19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */; }; 624493AE19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */; }; + 624717B81B21FE5400B38302 /* HTMLNodeFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */; }; + 624717B91B21FE5400B38302 /* HTMLNodeFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */; }; 6247A9431B152F4F00CCF25C /* HTMLNodeIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */; }; 6247A9441B152F4F00CCF25C /* HTMLNodeIterator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */; }; 6247A9451B152F4F00CCF25C /* HTMLNodeIterator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */; }; @@ -211,6 +213,7 @@ 624493A919CCE84A00BCDDF4 /* HTMLTokenizerStates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLTokenizerStates.h; sourceTree = "<group>"; }; 624493AA19CD0CBE00BCDDF4 /* HTMLToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLToken.h; sourceTree = "<group>"; }; 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLToken.m; sourceTree = "<group>"; }; + 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeFilter.m; sourceTree = "<group>"; }; 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeIterator.h; sourceTree = "<group>"; }; 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeIterator.m; sourceTree = "<group>"; }; 6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeFilter.h; sourceTree = "<group>"; }; @@ -338,6 +341,7 @@ 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */, 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */, 6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */, + 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */, 6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */, 6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */, 628B7CE61A080E1000602C87 /* HTMLNamespaces.h */, @@ -755,6 +759,7 @@ 625A150A19C78ABA00AD0C32 /* HTMLInputStreamReader.m in Sources */, 623857931A9E772B003A45D9 /* HTMLDocument.m in Sources */, 623406E81ADB05AD004677A3 /* HTMLDocumentFragment.m in Sources */, + 624717B91B21FE5400B38302 /* HTMLNodeFilter.m in Sources */, 624493A819CCC54100BCDDF4 /* HTMLTokenizer.m in Sources */, 625A14BE19C7829400AD0C32 /* HTMLKit.m in Sources */, 623857981A9E8606003A45D9 /* HTMLDocumentType.m in Sources */, @@ -807,6 +812,7 @@ 625A150919C78ABA00AD0C32 /* HTMLInputStreamReader.m in Sources */, 623857921A9E772B003A45D9 /* HTMLDocument.m in Sources */, 623406E71ADB05AD004677A3 /* HTMLDocumentFragment.m in Sources */, + 624717B81B21FE5400B38302 /* HTMLNodeFilter.m in Sources */, 624493A719CCC54100BCDDF4 /* HTMLTokenizer.m in Sources */, 625A150219C783DE00AD0C32 /* HTMLKit.m in Sources */, 623857971A9E8606003A45D9 /* HTMLDocumentType.m in Sources */, diff --git a/HTMLKit/HTMLNode.h b/HTMLKit/HTMLNode.h index c681825..ac4a20c 100644 --- a/HTMLKit/HTMLNode.h +++ b/HTMLKit/HTMLNode.h @@ -118,6 +118,9 @@ typedef NS_ENUM(unsigned short, HTMLDocumentPosition) - (HTMLNodeIterator *)nodeIterator; - (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions filter:(id<HTMLNodeFilter>)filter; +- (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions + filterBlock:(BOOL (^)(HTMLNode *node))filter; + - (NSString *)treeDescription; @end diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index c4d166f..6f4a221 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -380,6 +380,12 @@ return [[HTMLNodeIterator alloc] initWithNode:self showOptions:showOptions filter:filter]; } +- (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions + filterBlock:(BOOL (^)(HTMLNode *node))filter +{ + return [HTMLNodeIterator iteratorWithNode:self showOptions:showOptions filter:filter]; +} + #ifndef HTMLKIT_NO_DOM_CHECKS #pragma mark - Validity Checks diff --git a/HTMLKit/HTMLNodeFilter.h b/HTMLKit/HTMLNodeFilter.h index 40785a3..84c4c57 100644 --- a/HTMLKit/HTMLNodeFilter.h +++ b/HTMLKit/HTMLNodeFilter.h @@ -26,3 +26,9 @@ typedef NS_ENUM(unsigned long, HTMLNodeFilterShowOptions) - (BOOL)acceptNode:(HTMLNode *)node; @end + +@interface HTMLNodeFilterBlock : NSObject <HTMLNodeFilter> + ++ (instancetype)filterWithBlock:(BOOL (^)(HTMLNode *node))block; + +@end \ No newline at end of file diff --git a/HTMLKit/HTMLNodeFilter.m b/HTMLKit/HTMLNodeFilter.m new file mode 100644 index 0000000..914ee72 --- /dev/null +++ b/HTMLKit/HTMLNodeFilter.m @@ -0,0 +1,42 @@ +// +// HTMLNodeFilter.m +// HTMLKit +// +// Created by Iska on 05/06/15. +// Copyright (c) 2015 BrainCookie. All rights reserved. +// + +#import "HTMLNodeFilter.h" + +@interface HTMLNodeFilterBlock () +{ + BOOL (^ _block)(HTMLNode *); +} +@end + +@implementation HTMLNodeFilterBlock + ++ (instancetype)filterWithBlock:(BOOL (^)(HTMLNode *))block +{ + return [[self alloc] initWithBlock:block]; +} + +- (instancetype)initWithBlock:(BOOL (^)(HTMLNode *))block +{ + self = [super init]; + if (self) { + _block = [block copy]; + } + return self; +} + +- (BOOL)acceptNode:(HTMLNode *)node +{ + if (!_block) { + return NO; + } + + return _block(node); +} + +@end diff --git a/HTMLKit/HTMLNodeIterator.h b/HTMLKit/HTMLNodeIterator.h index ed8bd2b..803f55e 100644 --- a/HTMLKit/HTMLNodeIterator.h +++ b/HTMLKit/HTMLNodeIterator.h @@ -19,6 +19,10 @@ @property (nonatomic, assign, readonly) HTMLNodeFilterShowOptions whatToShow; @property (nonatomic, strong, readonly) id<HTMLNodeFilter> filter; ++ (instancetype)iteratorWithNode:(HTMLNode *)node + showOptions:(HTMLNodeFilterShowOptions)showOptions + filter:(BOOL (^)(HTMLNode *node))filter; + - (instancetype)initWithNode:(HTMLNode *)node; - (instancetype)initWithNode:(HTMLNode *)node filter:(id<HTMLNodeFilter>)filter; diff --git a/HTMLKit/HTMLNodeIterator.m b/HTMLKit/HTMLNodeIterator.m index a23de3d..1f72bed 100644 --- a/HTMLKit/HTMLNodeIterator.m +++ b/HTMLKit/HTMLNodeIterator.m @@ -10,6 +10,8 @@ #import "HTMLDocument.h" #import "HTMLNode.h" +#import <objc/runtime.h> + typedef NS_ENUM(short, TraverseDirection) { TraverseDirectionNext, @@ -31,6 +33,15 @@ typedef NS_ENUM(short, TraverseDirection) #pragma mark - Lifecycle ++ (instancetype)iteratorWithNode:(HTMLNode *)node + showOptions:(HTMLNodeFilterShowOptions)showOptions + filter:(BOOL (^)(HTMLNode *))filter +{ + return [[self alloc] initWithNode:node + showOptions:showOptions + filter:[HTMLNodeFilterBlock filterWithBlock:filter]]; +} + - (instancetype)initWithNode:(HTMLNode *)node { return [self initWithNode:node filter:nil]; diff --git a/HTMLKitTests/HTMLKitNodeIteratorTests.m b/HTMLKitTests/HTMLKitNodeIteratorTests.m index a9b05f2..a6411f3 100644 --- a/HTMLKitTests/HTMLKitNodeIteratorTests.m +++ b/HTMLKitTests/HTMLKitNodeIteratorTests.m @@ -9,23 +9,6 @@ #import <XCTest/XCTest.h> #import "HTMLDOM.h" -@interface CommentNodeFilter : NSObject <HTMLNodeFilter> -@end - -@implementation CommentNodeFilter - -- (BOOL)acceptNode:(HTMLNode *)node -{ - if (node.nodeType == HTMLNodeComment) { - if ([[(HTMLComment *)node data] rangeOfString:@"second"].location != NSNotFound) { - return YES; - } - } - return NO; -} - -@end - @interface HTMLKitNodeIteratorTests : XCTestCase @end @@ -327,8 +310,14 @@ { HTMLDocument *document = self.mixedTree; - HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowAll - filter:[CommentNodeFilter new]]; + HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowAll filterBlock:^BOOL(HTMLNode *node) { + if (node.nodeType == HTMLNodeComment) { + if ([[(HTMLComment *)node data] rangeOfString:@"second"].location != NSNotFound) { + return YES; + } + } + return NO; + }]; NSArray *result = iterator.allObjects; NSArray *expected = @[@"#comment"]; From 0d7c57d75506d75f0c4c2b1a67bd90e31fcf9537 Mon Sep 17 00:00:00 2001 From: iska <iska.gp@gmail.com> Date: Fri, 5 Jun 2015 22:09:02 +0200 Subject: [PATCH 31/40] Refactor common node traversal methods into separate class These will be used in the Tree Walker https://dom.spec.whatwg.org/#interface-treewalker --- HTMLKit.xcodeproj/project.pbxproj | 10 +++++ HTMLKit/HTMLNodeIterator.m | 56 ++-------------------------- HTMLKit/HTMLNodeTraversal.h | 16 ++++++++ HTMLKit/HTMLNodeTraversal.m | 61 +++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 53 deletions(-) create mode 100644 HTMLKit/HTMLNodeTraversal.h create mode 100644 HTMLKit/HTMLNodeTraversal.m diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index 350eb6c..4e109d3 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -66,6 +66,9 @@ 624493AC19CD0CBE00BCDDF4 /* HTMLToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 624493AA19CD0CBE00BCDDF4 /* HTMLToken.h */; }; 624493AD19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */; }; 624493AE19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */; }; + 624717181B22333200C11912 /* HTMLNodeTraversal.h in Headers */ = {isa = PBXBuildFile; fileRef = 624717161B22333200C11912 /* HTMLNodeTraversal.h */; }; + 624717191B22333200C11912 /* HTMLNodeTraversal.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717171B22333200C11912 /* HTMLNodeTraversal.m */; }; + 6247171A1B22333200C11912 /* HTMLNodeTraversal.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717171B22333200C11912 /* HTMLNodeTraversal.m */; }; 624717B81B21FE5400B38302 /* HTMLNodeFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */; }; 624717B91B21FE5400B38302 /* HTMLNodeFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */; }; 6247A9431B152F4F00CCF25C /* HTMLNodeIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */; }; @@ -213,6 +216,8 @@ 624493A919CCE84A00BCDDF4 /* HTMLTokenizerStates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLTokenizerStates.h; sourceTree = "<group>"; }; 624493AA19CD0CBE00BCDDF4 /* HTMLToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLToken.h; sourceTree = "<group>"; }; 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLToken.m; sourceTree = "<group>"; }; + 624717161B22333200C11912 /* HTMLNodeTraversal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeTraversal.h; sourceTree = "<group>"; }; + 624717171B22333200C11912 /* HTMLNodeTraversal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeTraversal.m; sourceTree = "<group>"; }; 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeFilter.m; sourceTree = "<group>"; }; 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeIterator.h; sourceTree = "<group>"; }; 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeIterator.m; sourceTree = "<group>"; }; @@ -340,6 +345,8 @@ 623406E01ADB04F9004677A3 /* HTMLTemplate.m */, 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */, 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */, + 624717161B22333200C11912 /* HTMLNodeTraversal.h */, + 624717171B22333200C11912 /* HTMLNodeTraversal.m */, 6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */, 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */, 6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */, @@ -553,6 +560,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 624717181B22333200C11912 /* HTMLNodeTraversal.h in Headers */, 6235CE9B1AA509430026937B /* NSString+HTMLKit.h in Headers */, 62D89DB11AE7081600B6243D /* HTMLTokenizerStates.h in Headers */, 62D89DB21AE7081600B6243D /* HTMLTokenizerCharacters.h in Headers */, @@ -753,6 +761,7 @@ 62AE593C19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */, 623406E31ADB04F9004677A3 /* HTMLTemplate.m in Sources */, 6238C9871AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */, + 6247171A1B22333200C11912 /* HTMLNodeTraversal.m in Sources */, 62F873ED19E088C90062683C /* HTMLParser.m in Sources */, 623803A11AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */, 6279F87619E1808D00F12EE5 /* HTMLElement.m in Sources */, @@ -806,6 +815,7 @@ 62AE593B19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */, 623406E21ADB04F9004677A3 /* HTMLTemplate.m in Sources */, 6238C9861AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */, + 624717191B22333200C11912 /* HTMLNodeTraversal.m in Sources */, 62F873EC19E088C90062683C /* HTMLParser.m in Sources */, 623803A01AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */, 6279F87519E1808D00F12EE5 /* HTMLElement.m in Sources */, diff --git a/HTMLKit/HTMLNodeIterator.m b/HTMLKit/HTMLNodeIterator.m index 1f72bed..2927ac0 100644 --- a/HTMLKit/HTMLNodeIterator.m +++ b/HTMLKit/HTMLNodeIterator.m @@ -9,8 +9,8 @@ #import "HTMLNodeIterator.h" #import "HTMLDocument.h" #import "HTMLNode.h" - -#import <objc/runtime.h> +#import "HTMLNodeFilter.h" +#import "HTMLNodeTraversal.h" typedef NS_ENUM(short, TraverseDirection) { @@ -139,63 +139,13 @@ typedef NS_ENUM(short, TraverseDirection) } beforeNode = YES; } - } while (!FilterNode(self, node)); + } while (!FilterNode(self.filter, self.whatToShow, node)); _referenceNode = node; _pointerBeforeReferenceNode = beforeNode; return node; } -NS_INLINE HTMLNode * PrecedingNode(HTMLNode *node, HTMLNode *root) -{ - HTMLNode *previous = node.previousSibling; - if (previous != nil) { - while (previous.lastChildNode != nil) { - previous = previous.lastChildNode; - } - return previous; - } - - if (node == root) { - return nil; - } - - return node.parentNode; -} - -NS_INLINE HTMLNode * FollowingNode(HTMLNode *node, HTMLNode *root) -{ - if (node.firstChiledNode != nil) { - return node.firstChiledNode; - } - - do { - if (node == root) { - return nil; - } - if (node.nextSibling != nil) { - return node.nextSibling; - } - node = node.parentNode; - } while (node != nil); - - return nil; -} - -NS_INLINE BOOL FilterNode(HTMLNodeIterator *iterator, HTMLNode *node) -{ - unsigned long nthBit = (1 << (node.nodeType - 1)) & iterator.whatToShow; - if (!nthBit) { - return NO; - } - - if (iterator.filter == nil) { - return YES; - } - - return [iterator.filter acceptNode:node]; -} - - (HTMLNode *)nextNode { return [self traverseInDirection:TraverseDirectionNext]; diff --git a/HTMLKit/HTMLNodeTraversal.h b/HTMLKit/HTMLNodeTraversal.h new file mode 100644 index 0000000..b3fe2f6 --- /dev/null +++ b/HTMLKit/HTMLNodeTraversal.h @@ -0,0 +1,16 @@ +// +// HTMLNodeTraversal.h +// HTMLKit +// +// Created by Iska on 05/06/15. +// Copyright (c) 2015 BrainCookie. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import "HTMLNodeFilter.h" + +@class HTMLNode; + +extern HTMLNode * PrecedingNode(HTMLNode *node, HTMLNode *root); +extern HTMLNode * FollowingNode(HTMLNode *node, HTMLNode *root); +extern BOOL FilterNode(id<HTMLNodeFilter> filter, HTMLNodeFilterShowOptions whatToShow, HTMLNode *node); diff --git a/HTMLKit/HTMLNodeTraversal.m b/HTMLKit/HTMLNodeTraversal.m new file mode 100644 index 0000000..6f8b5eb --- /dev/null +++ b/HTMLKit/HTMLNodeTraversal.m @@ -0,0 +1,61 @@ +// +// HTMLNodeTraversal.m +// HTMLKit +// +// Created by Iska on 05/06/15. +// Copyright (c) 2015 BrainCookie. All rights reserved. +// + +#import "HTMLNodeTraversal.h" +#import "HTMLNode.h" +#import "HTMLNodeFilter.h" + +HTMLNode * PrecedingNode(HTMLNode *node, HTMLNode *root) +{ + HTMLNode *previous = node.previousSibling; + if (previous != nil) { + while (previous.lastChildNode != nil) { + previous = previous.lastChildNode; + } + return previous; + } + + if (node == root) { + return nil; + } + + return node.parentNode; +} + +HTMLNode * FollowingNode(HTMLNode *node, HTMLNode *root) +{ + if (node.firstChiledNode != nil) { + return node.firstChiledNode; + } + + do { + if (node == root) { + return nil; + } + if (node.nextSibling != nil) { + return node.nextSibling; + } + node = node.parentNode; + } while (node != nil); + + return nil; +} + +extern BOOL FilterNode(id<HTMLNodeFilter> filter, HTMLNodeFilterShowOptions whatToShow, HTMLNode *node) +{ + unsigned long nthBit = (1 << (node.nodeType - 1)) & whatToShow; + if (!nthBit) { + return NO; + } + + if (filter == nil) { + return YES; + } + + return [filter acceptNode:node]; +} From 0c82f6891b3d56cf2d09d7a2162c2f548bfb6e99 Mon Sep 17 00:00:00 2001 From: iska <iska.gp@gmail.com> Date: Fri, 5 Jun 2015 22:46:41 +0200 Subject: [PATCH 32/40] Add implementation for the Tree Walker https://dom.spec.whatwg.org/#interface-treewalker --- HTMLKit.xcodeproj/project.pbxproj | 10 ++ HTMLKit/HTMLNodeTraversal.h | 1 + HTMLKit/HTMLNodeTraversal.m | 17 ++- HTMLKit/HTMLTreeWalker.h | 29 ++++ HTMLKit/HTMLTreeWalker.m | 222 ++++++++++++++++++++++++++++++ 5 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 HTMLKit/HTMLTreeWalker.h create mode 100644 HTMLKit/HTMLTreeWalker.m diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index 4e109d3..ff7ddb5 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -71,6 +71,9 @@ 6247171A1B22333200C11912 /* HTMLNodeTraversal.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717171B22333200C11912 /* HTMLNodeTraversal.m */; }; 624717B81B21FE5400B38302 /* HTMLNodeFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */; }; 624717B91B21FE5400B38302 /* HTMLNodeFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */; }; + 624717BC1B22009200B38302 /* HTMLTreeWalker.h in Headers */ = {isa = PBXBuildFile; fileRef = 624717BA1B22009200B38302 /* HTMLTreeWalker.h */; }; + 624717BD1B22009200B38302 /* HTMLTreeWalker.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717BB1B22009200B38302 /* HTMLTreeWalker.m */; }; + 624717BE1B22009200B38302 /* HTMLTreeWalker.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717BB1B22009200B38302 /* HTMLTreeWalker.m */; }; 6247A9431B152F4F00CCF25C /* HTMLNodeIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */; }; 6247A9441B152F4F00CCF25C /* HTMLNodeIterator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */; }; 6247A9451B152F4F00CCF25C /* HTMLNodeIterator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */; }; @@ -219,6 +222,8 @@ 624717161B22333200C11912 /* HTMLNodeTraversal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeTraversal.h; sourceTree = "<group>"; }; 624717171B22333200C11912 /* HTMLNodeTraversal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeTraversal.m; sourceTree = "<group>"; }; 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeFilter.m; sourceTree = "<group>"; }; + 624717BA1B22009200B38302 /* HTMLTreeWalker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLTreeWalker.h; sourceTree = "<group>"; }; + 624717BB1B22009200B38302 /* HTMLTreeWalker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLTreeWalker.m; sourceTree = "<group>"; }; 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeIterator.h; sourceTree = "<group>"; }; 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeIterator.m; sourceTree = "<group>"; }; 6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeFilter.h; sourceTree = "<group>"; }; @@ -345,6 +350,8 @@ 623406E01ADB04F9004677A3 /* HTMLTemplate.m */, 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */, 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */, + 624717BA1B22009200B38302 /* HTMLTreeWalker.h */, + 624717BB1B22009200B38302 /* HTMLTreeWalker.m */, 624717161B22333200C11912 /* HTMLNodeTraversal.h */, 624717171B22333200C11912 /* HTMLNodeTraversal.m */, 6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */, @@ -596,6 +603,7 @@ 623857961A9E8606003A45D9 /* HTMLDocumentType.h in Headers */, 623406E61ADB05AD004677A3 /* HTMLDocumentFragment.h in Headers */, 62363C3D1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h in Headers */, + 624717BC1B22009200B38302 /* HTMLTreeWalker.h in Headers */, 62362A3C1A9FA70400301989 /* HTMLText.h in Headers */, 6234584E1A9D2FA4009BD491 /* HTMLNode.h in Headers */, ); @@ -755,6 +763,7 @@ 624493AE19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */, 6235CEA21AA5170A0026937B /* HTMLMarker.m in Sources */, 6234248A1AB467B200726190 /* HTMLOrderedDictionary.m in Sources */, + 624717BE1B22009200B38302 /* HTMLTreeWalker.m in Sources */, 62AE594119F9907C0043F069 /* HTMLTagToken.m in Sources */, 62AE594619F992F30043F069 /* HTMLCommentToken.m in Sources */, 62363C3F1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m in Sources */, @@ -809,6 +818,7 @@ 624493AD19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */, 6235CEA11AA5170A0026937B /* HTMLMarker.m in Sources */, 623424891AB467B200726190 /* HTMLOrderedDictionary.m in Sources */, + 624717BD1B22009200B38302 /* HTMLTreeWalker.m in Sources */, 62AE594019F9907C0043F069 /* HTMLTagToken.m in Sources */, 62AE594519F992F30043F069 /* HTMLCommentToken.m in Sources */, 62363C3E1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m in Sources */, diff --git a/HTMLKit/HTMLNodeTraversal.h b/HTMLKit/HTMLNodeTraversal.h index b3fe2f6..610700f 100644 --- a/HTMLKit/HTMLNodeTraversal.h +++ b/HTMLKit/HTMLNodeTraversal.h @@ -13,4 +13,5 @@ extern HTMLNode * PrecedingNode(HTMLNode *node, HTMLNode *root); extern HTMLNode * FollowingNode(HTMLNode *node, HTMLNode *root); +extern HTMLNode * FollowingNodeSkippingChildren(HTMLNode *node, HTMLNode *root); extern BOOL FilterNode(id<HTMLNodeFilter> filter, HTMLNodeFilterShowOptions whatToShow, HTMLNode *node); diff --git a/HTMLKit/HTMLNodeTraversal.m b/HTMLKit/HTMLNodeTraversal.m index 6f8b5eb..1ef2de8 100644 --- a/HTMLKit/HTMLNodeTraversal.m +++ b/HTMLKit/HTMLNodeTraversal.m @@ -46,7 +46,22 @@ HTMLNode * FollowingNode(HTMLNode *node, HTMLNode *root) return nil; } -extern BOOL FilterNode(id<HTMLNodeFilter> filter, HTMLNodeFilterShowOptions whatToShow, HTMLNode *node) +HTMLNode * FollowingNodeSkippingChildren(HTMLNode *node, HTMLNode *root) +{ + do { + if (node == root) { + return nil; + } + if (node.nextSibling != nil) { + return node.nextSibling; + } + node = node.parentNode; + } while (node != nil); + + return nil; +} + +BOOL FilterNode(id<HTMLNodeFilter> filter, HTMLNodeFilterShowOptions whatToShow, HTMLNode *node) { unsigned long nthBit = (1 << (node.nodeType - 1)) & whatToShow; if (!nthBit) { diff --git a/HTMLKit/HTMLTreeWalker.h b/HTMLKit/HTMLTreeWalker.h new file mode 100644 index 0000000..8b05394 --- /dev/null +++ b/HTMLKit/HTMLTreeWalker.h @@ -0,0 +1,29 @@ +// +// HTMLTreeWalker.h +// HTMLKit +// +// Created by Iska on 05/06/15. +// Copyright (c) 2015 BrainCookie. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import "HTMLNodeFilter.h" + +@class HTMLNode; + +@interface HTMLTreeWalker : NSObject + +@property (nonatomic, strong, readonly) HTMLNode *root; +@property (nonatomic, assign, readonly) HTMLNodeFilterShowOptions whatToShow; +@property (nonatomic, strong, readonly) id<HTMLNodeFilter> filter; +@property (nonatomic, strong) HTMLNode *currentNode; + +- (HTMLNode *)parentNode; +- (HTMLNode *)firstChild; +- (HTMLNode *)lastChild; +- (HTMLNode *)previousSibling; +- (HTMLNode *)nextSibling; +- (HTMLNode *)previousNode; +- (HTMLNode *)nextNode; + +@end diff --git a/HTMLKit/HTMLTreeWalker.m b/HTMLKit/HTMLTreeWalker.m new file mode 100644 index 0000000..d4a90c5 --- /dev/null +++ b/HTMLKit/HTMLTreeWalker.m @@ -0,0 +1,222 @@ +// +// HTMLTreeWalker.m +// HTMLKit +// +// Created by Iska on 05/06/15. +// Copyright (c) 2015 BrainCookie. All rights reserved. +// + +#import "HTMLTreeWalker.h" +#import "HTMLNode.h" +#import "HTMLNodeFilter.h" +#import "HTMLNodeTraversal.h" + +typedef NS_ENUM(short, HTMLTreeWalkerChildrenType) +{ + HTMLTreeWalkerChildrenTypeFirst, + HTMLTreeWalkerChildrenTypeLast +}; + +typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) +{ + HTMLTreeWalkerSiblingsTypeNext, + HTMLTreeWalkerSiblingsTypePrevious +}; + +@implementation HTMLTreeWalker + +#pragma mark - Lifecycle + +- (instancetype)initWithNode:(HTMLNode *)node + showOptions:(HTMLNodeFilterShowOptions)showOptions + filter:(id<HTMLNodeFilter>)filter +{ + self = [super init]; + if (self) { + _root = node; + _filter = filter; + _whatToShow = showOptions; + _currentNode = _root; + } + return self; +} + +#pragma mark - Traversal + +- (HTMLNode *)traverseChildrenOfType:(HTMLTreeWalkerChildrenType)type +{ + HTMLNode *node = _currentNode; + + node = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.firstChiledNode : node.lastChildNode; + + while (node != nil) { + BOOL result = FilterNode(self.filter, self.whatToShow, node); + if (result) { + _currentNode = node; + return node; + } + + HTMLNode *child = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.firstChiledNode : node.lastChildNode; + if (child != nil) { + node = child; + continue; + } + + while (node != nil) { + HTMLNode *sibling = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.nextSibling : node.previousSibling; + if (sibling != nil) { + node = sibling; + continue; + } + + HTMLNode *parent = node.parentNode; + if (parent == nil || parent == _root || parent == _currentNode) { + return nil; + } + node = parent; + } + } + + return nil; +} + +- (HTMLNode *)parentNode +{ + HTMLNode *node = _currentNode; + + while (node != nil && node != _root) { + node = node.parentNode; + if (node != nil && FilterNode(self.filter, self.whatToShow, node)) { + _currentNode = node; + return node; + } + } + return nil; +} + +- (HTMLNode *)firstChild +{ + return [self traverseChildrenOfType:HTMLTreeWalkerChildrenTypeFirst]; +} + +- (HTMLNode *)lastChild +{ + return [self traverseChildrenOfType:HTMLTreeWalkerChildrenTypeLast]; +} + +- (HTMLNode *)traverseSiblingsOfType:(HTMLTreeWalkerSiblingsType)type +{ + HTMLNode *node = _currentNode; + + if (node == _root) { + return nil; + } + + while (YES) { + HTMLNode *sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.nextSibling : node.previousSibling; + while (sibling != nil) { + node = sibling; + BOOL result = FilterNode(self.filter, self.whatToShow, node); + if (result) { + _currentNode = node; + return node; + } + + HTMLNode *sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.firstChiledNode : node.lastChildNode; + if (sibling == nil) { + sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.nextSibling : node.previousSibling; + } + } + + node = node.parentNode; + if (node == nil || node == _root) { + return nil; + } + + if (FilterNode(self.filter, self.whatToShow, node)) { + return nil; + } + } + return nil; +} + +- (HTMLNode *)previousSibling +{ + return [self traverseSiblingsOfType:HTMLTreeWalkerSiblingsTypePrevious]; +} + +- (HTMLNode *)nextSibling +{ + return [self traverseSiblingsOfType:HTMLTreeWalkerSiblingsTypeNext]; +} + +- (HTMLNode *)previousNode +{ + HTMLNode *node = _currentNode; + + while (node != _root) { + HTMLNode *sibling = node.previousSibling; + + while (sibling != nil) { + node = sibling; + + BOOL result = FilterNode(self.filter, self.whatToShow, node); + while (result && node.hasChildNodes) { + node = node.lastChildNode; + result = FilterNode(self.filter, self.whatToShow, node); + } + + if (result) { + _currentNode = node; + return node; + } + + sibling = node.previousSibling; + } + + if (node == _root || node.parentNode == nil) { + return nil; + } + + node = node.parentNode; + if (FilterNode(self.filter, self.whatToShow, node)) { + _currentNode = node; + return node; + } + } + + return nil; +} + +- (HTMLNode *)nextNode +{ + HTMLNode *node = _currentNode; + + BOOL result = YES; + + while (YES) { + while (!result && node.hasChildNodes) { + node = node.firstChiledNode; + result = FilterNode(self.filter, self.whatToShow, node); + if (result) { + _currentNode = node; + return node; + } + } + + HTMLNode *nextSibling; + while ((nextSibling = FollowingNodeSkippingChildren(node, _root)) != nil) { + node = nextSibling; + result = FilterNode(self.filter, self.whatToShow, node); + if (result) { + _currentNode = node; + return node; + } + break; + } + } + + return nil; +} + +@end From a390edf59979290237d6fa6b4e14ad3eaeff2463 Mon Sep 17 00:00:00 2001 From: iska <iska.gp@gmail.com> Date: Fri, 5 Jun 2015 22:54:37 +0200 Subject: [PATCH 33/40] Reintroduce the HTMLNodeFilterValue for Tree Walker implementation While the Node Iterator treats skip & reject the same way, the Tree Walker can skip over a node and all its children if rejected. This reverses dc3de7a47091d6f865690e063d2bde488ad45a75 --- HTMLKit/HTMLNode.h | 2 +- HTMLKit/HTMLNode.m | 2 +- HTMLKit/HTMLNodeFilter.h | 13 +++-- HTMLKit/HTMLNodeFilter.m | 8 +-- HTMLKit/HTMLNodeIterator.h | 2 +- HTMLKit/HTMLNodeIterator.m | 4 +- HTMLKit/HTMLNodeTraversal.h | 2 +- HTMLKit/HTMLNodeTraversal.m | 6 +-- HTMLKit/HTMLTreeWalker.m | 65 +++++++++++++------------ HTMLKitTests/HTMLKitNodeIteratorTests.m | 7 +-- 10 files changed, 61 insertions(+), 50 deletions(-) diff --git a/HTMLKit/HTMLNode.h b/HTMLKit/HTMLNode.h index ac4a20c..a488dcd 100644 --- a/HTMLKit/HTMLNode.h +++ b/HTMLKit/HTMLNode.h @@ -119,7 +119,7 @@ typedef NS_ENUM(unsigned short, HTMLDocumentPosition) - (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions filter:(id<HTMLNodeFilter>)filter; - (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions - filterBlock:(BOOL (^)(HTMLNode *node))filter; + filterBlock:(HTMLNodeFilterValue (^)(HTMLNode *node))filter; - (NSString *)treeDescription; diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index 6f4a221..f6cedbc 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -381,7 +381,7 @@ } - (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions - filterBlock:(BOOL (^)(HTMLNode *node))filter + filterBlock:(HTMLNodeFilterValue (^)(HTMLNode *node))filter { return [HTMLNodeIterator iteratorWithNode:self showOptions:showOptions filter:filter]; } diff --git a/HTMLKit/HTMLNodeFilter.h b/HTMLKit/HTMLNodeFilter.h index 84c4c57..9df0e74 100644 --- a/HTMLKit/HTMLNodeFilter.h +++ b/HTMLKit/HTMLNodeFilter.h @@ -8,6 +8,13 @@ #import <Foundation/Foundation.h> +typedef NS_ENUM(unsigned short, HTMLNodeFilterValue) +{ + HTMLNodeFilterAccept = 1, + HTMLNodeFilterReject = 2, + HTMLNodeFilterSkip = 3 +}; + typedef NS_ENUM(unsigned long, HTMLNodeFilterShowOptions) { HTMLNodeFilterShowAll = 0xFFFFFFFF, @@ -23,12 +30,12 @@ typedef NS_ENUM(unsigned long, HTMLNodeFilterShowOptions) @protocol HTMLNodeFilter <NSObject> -- (BOOL)acceptNode:(HTMLNode *)node; +- (HTMLNodeFilterValue)acceptNode:(HTMLNode *)node; @end @interface HTMLNodeFilterBlock : NSObject <HTMLNodeFilter> -+ (instancetype)filterWithBlock:(BOOL (^)(HTMLNode *node))block; ++ (instancetype)filterWithBlock:(HTMLNodeFilterValue (^)(HTMLNode *node))block; -@end \ No newline at end of file +@end diff --git a/HTMLKit/HTMLNodeFilter.m b/HTMLKit/HTMLNodeFilter.m index 914ee72..96e4843 100644 --- a/HTMLKit/HTMLNodeFilter.m +++ b/HTMLKit/HTMLNodeFilter.m @@ -16,12 +16,12 @@ @implementation HTMLNodeFilterBlock -+ (instancetype)filterWithBlock:(BOOL (^)(HTMLNode *))block ++ (instancetype)filterWithBlock:(HTMLNodeFilterValue (^)(HTMLNode *))block { return [[self alloc] initWithBlock:block]; } -- (instancetype)initWithBlock:(BOOL (^)(HTMLNode *))block +- (instancetype)initWithBlock:(HTMLNodeFilterValue (^)(HTMLNode *))block { self = [super init]; if (self) { @@ -30,10 +30,10 @@ return self; } -- (BOOL)acceptNode:(HTMLNode *)node +- (HTMLNodeFilterValue)acceptNode:(HTMLNode *)node { if (!_block) { - return NO; + return HTMLNodeFilterSkip; } return _block(node); diff --git a/HTMLKit/HTMLNodeIterator.h b/HTMLKit/HTMLNodeIterator.h index 803f55e..6dd269e 100644 --- a/HTMLKit/HTMLNodeIterator.h +++ b/HTMLKit/HTMLNodeIterator.h @@ -21,7 +21,7 @@ + (instancetype)iteratorWithNode:(HTMLNode *)node showOptions:(HTMLNodeFilterShowOptions)showOptions - filter:(BOOL (^)(HTMLNode *node))filter; + filter:(HTMLNodeFilterValue (^)(HTMLNode *node))filter; - (instancetype)initWithNode:(HTMLNode *)node; - (instancetype)initWithNode:(HTMLNode *)node diff --git a/HTMLKit/HTMLNodeIterator.m b/HTMLKit/HTMLNodeIterator.m index 2927ac0..c5e85d1 100644 --- a/HTMLKit/HTMLNodeIterator.m +++ b/HTMLKit/HTMLNodeIterator.m @@ -35,7 +35,7 @@ typedef NS_ENUM(short, TraverseDirection) + (instancetype)iteratorWithNode:(HTMLNode *)node showOptions:(HTMLNodeFilterShowOptions)showOptions - filter:(BOOL (^)(HTMLNode *))filter + filter:(HTMLNodeFilterValue (^)(HTMLNode *))filter { return [[self alloc] initWithNode:node showOptions:showOptions @@ -139,7 +139,7 @@ typedef NS_ENUM(short, TraverseDirection) } beforeNode = YES; } - } while (!FilterNode(self.filter, self.whatToShow, node)); + } while (FilterNode(self.filter, self.whatToShow, node) != HTMLNodeFilterAccept); _referenceNode = node; _pointerBeforeReferenceNode = beforeNode; diff --git a/HTMLKit/HTMLNodeTraversal.h b/HTMLKit/HTMLNodeTraversal.h index 610700f..ee2bf7e 100644 --- a/HTMLKit/HTMLNodeTraversal.h +++ b/HTMLKit/HTMLNodeTraversal.h @@ -14,4 +14,4 @@ extern HTMLNode * PrecedingNode(HTMLNode *node, HTMLNode *root); extern HTMLNode * FollowingNode(HTMLNode *node, HTMLNode *root); extern HTMLNode * FollowingNodeSkippingChildren(HTMLNode *node, HTMLNode *root); -extern BOOL FilterNode(id<HTMLNodeFilter> filter, HTMLNodeFilterShowOptions whatToShow, HTMLNode *node); +extern HTMLNodeFilterValue FilterNode(id<HTMLNodeFilter> filter, HTMLNodeFilterShowOptions whatToShow, HTMLNode *node); diff --git a/HTMLKit/HTMLNodeTraversal.m b/HTMLKit/HTMLNodeTraversal.m index 1ef2de8..1c646df 100644 --- a/HTMLKit/HTMLNodeTraversal.m +++ b/HTMLKit/HTMLNodeTraversal.m @@ -61,15 +61,15 @@ HTMLNode * FollowingNodeSkippingChildren(HTMLNode *node, HTMLNode *root) return nil; } -BOOL FilterNode(id<HTMLNodeFilter> filter, HTMLNodeFilterShowOptions whatToShow, HTMLNode *node) +HTMLNodeFilterValue FilterNode(id<HTMLNodeFilter> filter, HTMLNodeFilterShowOptions whatToShow, HTMLNode *node) { unsigned long nthBit = (1 << (node.nodeType - 1)) & whatToShow; if (!nthBit) { - return NO; + return HTMLNodeFilterSkip; } if (filter == nil) { - return YES; + return HTMLNodeFilterAccept; } return [filter acceptNode:node]; diff --git a/HTMLKit/HTMLTreeWalker.m b/HTMLKit/HTMLTreeWalker.m index d4a90c5..b76c119 100644 --- a/HTMLKit/HTMLTreeWalker.m +++ b/HTMLKit/HTMLTreeWalker.m @@ -43,6 +43,20 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) #pragma mark - Traversal +- (HTMLNode *)parentNode +{ + HTMLNode *node = _currentNode; + + while (node != nil && node != _root) { + node = node.parentNode; + if (node != nil && FilterNode(self.filter, self.whatToShow, node) == HTMLNodeFilterAccept) { + _currentNode = node; + return node; + } + } + return nil; +} + - (HTMLNode *)traverseChildrenOfType:(HTMLTreeWalkerChildrenType)type { HTMLNode *node = _currentNode; @@ -50,16 +64,18 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) node = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.firstChiledNode : node.lastChildNode; while (node != nil) { - BOOL result = FilterNode(self.filter, self.whatToShow, node); - if (result) { + HTMLNodeFilterValue result = FilterNode(self.filter, self.whatToShow, node); + if (result == HTMLNodeFilterAccept) { _currentNode = node; return node; } - HTMLNode *child = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.firstChiledNode : node.lastChildNode; - if (child != nil) { - node = child; - continue; + if (result == HTMLNodeFilterSkip) { + HTMLNode *child = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.firstChiledNode : node.lastChildNode; + if (child != nil) { + node = child; + continue; + } } while (node != nil) { @@ -80,20 +96,6 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) return nil; } -- (HTMLNode *)parentNode -{ - HTMLNode *node = _currentNode; - - while (node != nil && node != _root) { - node = node.parentNode; - if (node != nil && FilterNode(self.filter, self.whatToShow, node)) { - _currentNode = node; - return node; - } - } - return nil; -} - - (HTMLNode *)firstChild { return [self traverseChildrenOfType:HTMLTreeWalkerChildrenTypeFirst]; @@ -116,8 +118,8 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) HTMLNode *sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.nextSibling : node.previousSibling; while (sibling != nil) { node = sibling; - BOOL result = FilterNode(self.filter, self.whatToShow, node); - if (result) { + HTMLNodeFilterValue result = FilterNode(self.filter, self.whatToShow, node); + if (result == HTMLNodeFilterAccept) { _currentNode = node; return node; } @@ -133,10 +135,11 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) return nil; } - if (FilterNode(self.filter, self.whatToShow, node)) { + if (FilterNode(self.filter, self.whatToShow, node) == HTMLNodeFilterAccept) { return nil; } } + return nil; } @@ -160,13 +163,13 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) while (sibling != nil) { node = sibling; - BOOL result = FilterNode(self.filter, self.whatToShow, node); - while (result && node.hasChildNodes) { + HTMLNodeFilterValue result = FilterNode(self.filter, self.whatToShow, node); + while (result != HTMLNodeFilterReject && node.hasChildNodes) { node = node.lastChildNode; result = FilterNode(self.filter, self.whatToShow, node); } - if (result) { + if (result == HTMLNodeFilterAccept) { _currentNode = node; return node; } @@ -179,7 +182,7 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) } node = node.parentNode; - if (FilterNode(self.filter, self.whatToShow, node)) { + if (FilterNode(self.filter, self.whatToShow, node) == HTMLNodeFilterAccept) { _currentNode = node; return node; } @@ -192,13 +195,13 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) { HTMLNode *node = _currentNode; - BOOL result = YES; + HTMLNodeFilterValue result = YES; while (YES) { - while (!result && node.hasChildNodes) { + while (result != HTMLNodeFilterReject && node.hasChildNodes) { node = node.firstChiledNode; result = FilterNode(self.filter, self.whatToShow, node); - if (result) { + if (result == HTMLNodeFilterAccept) { _currentNode = node; return node; } @@ -208,7 +211,7 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) while ((nextSibling = FollowingNodeSkippingChildren(node, _root)) != nil) { node = nextSibling; result = FilterNode(self.filter, self.whatToShow, node); - if (result) { + if (result == HTMLNodeFilterAccept) { _currentNode = node; return node; } diff --git a/HTMLKitTests/HTMLKitNodeIteratorTests.m b/HTMLKitTests/HTMLKitNodeIteratorTests.m index a6411f3..118b5c6 100644 --- a/HTMLKitTests/HTMLKitNodeIteratorTests.m +++ b/HTMLKitTests/HTMLKitNodeIteratorTests.m @@ -310,13 +310,14 @@ { HTMLDocument *document = self.mixedTree; - HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowAll filterBlock:^BOOL(HTMLNode *node) { + HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowAll + filterBlock:^HTMLNodeFilterValue(HTMLNode *node) { if (node.nodeType == HTMLNodeComment) { if ([[(HTMLComment *)node data] rangeOfString:@"second"].location != NSNotFound) { - return YES; + return HTMLNodeFilterAccept; } } - return NO; + return HTMLNodeFilterSkip; }]; NSArray *result = iterator.allObjects; From fd516c67ef5c89938146d20662d52a14af27bebd Mon Sep 17 00:00:00 2001 From: iska <iska.gp@gmail.com> Date: Fri, 5 Jun 2015 23:01:55 +0200 Subject: [PATCH 34/40] Change Node Filter's show options enum to NS_OPTIONS --- HTMLKit/HTMLNodeFilter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HTMLKit/HTMLNodeFilter.h b/HTMLKit/HTMLNodeFilter.h index 9df0e74..a32a2ea 100644 --- a/HTMLKit/HTMLNodeFilter.h +++ b/HTMLKit/HTMLNodeFilter.h @@ -15,7 +15,7 @@ typedef NS_ENUM(unsigned short, HTMLNodeFilterValue) HTMLNodeFilterSkip = 3 }; -typedef NS_ENUM(unsigned long, HTMLNodeFilterShowOptions) +typedef NS_OPTIONS(unsigned long, HTMLNodeFilterShowOptions) { HTMLNodeFilterShowAll = 0xFFFFFFFF, HTMLNodeFilterShowElement = 0x1, From a39890e6e933003b0efd856cb9269ed2f709fc51 Mon Sep 17 00:00:00 2001 From: iska <iska.gp@gmail.com> Date: Sat, 6 Jun 2015 18:58:45 +0200 Subject: [PATCH 35/40] Add documentElement property for the HTML Document The documentElement is the <html> element --- HTMLKit/HTMLDocument.h | 2 ++ HTMLKit/HTMLDocument.m | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/HTMLKit/HTMLDocument.h b/HTMLKit/HTMLDocument.h index 222ea81..f8a0485 100644 --- a/HTMLKit/HTMLDocument.h +++ b/HTMLKit/HTMLDocument.h @@ -29,6 +29,8 @@ typedef NS_ENUM(short, HTMLDocumentReadyState) @property (nonatomic, strong) HTMLElement *rootElement; +@property (nonatomic, strong) HTMLElement *documentElement; + @property (nonatomic, strong) HTMLElement *head; @property (nonatomic, strong) HTMLElement *body; diff --git a/HTMLKit/HTMLDocument.m b/HTMLKit/HTMLDocument.m index a4990dc..86d36c3 100644 --- a/HTMLKit/HTMLDocument.m +++ b/HTMLKit/HTMLDocument.m @@ -90,6 +90,21 @@ [self replaceChildNode:self.rootElement withNode:rootElement]; } +- (HTMLElement *)documentElement +{ + for (HTMLNode *node in [self nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]) { + if ([node.asElement.tagName isEqualToString:@"html"]) { + return node.asElement; + } + } + return nil; +} + +- (void)setDocumentElement:(HTMLElement *)documentElement +{ + [self replaceChildNode:self.documentElement withNode:documentElement]; +} + - (HTMLElement *)head { for (HTMLNode *node in [self nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]) { From 5e482788cebaf67cb5ca869167a7de4556da9086 Mon Sep 17 00:00:00 2001 From: iska <iska.gp@gmail.com> Date: Sat, 6 Jun 2015 18:59:06 +0200 Subject: [PATCH 36/40] Add Tree Walker's initializer methods --- HTMLKit/HTMLTreeWalker.h | 7 +++++++ HTMLKit/HTMLTreeWalker.m | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/HTMLKit/HTMLTreeWalker.h b/HTMLKit/HTMLTreeWalker.h index 8b05394..fff2328 100644 --- a/HTMLKit/HTMLTreeWalker.h +++ b/HTMLKit/HTMLTreeWalker.h @@ -18,6 +18,13 @@ @property (nonatomic, strong, readonly) id<HTMLNodeFilter> filter; @property (nonatomic, strong) HTMLNode *currentNode; +- (instancetype)initWithNode:(HTMLNode *)node; +- (instancetype)initWithNode:(HTMLNode *)node + filter:(id<HTMLNodeFilter>)filter; +- (instancetype)initWithNode:(HTMLNode *)node + showOptions:(HTMLNodeFilterShowOptions)showOptions + filter:(id<HTMLNodeFilter>)filter; + - (HTMLNode *)parentNode; - (HTMLNode *)firstChild; - (HTMLNode *)lastChild; diff --git a/HTMLKit/HTMLTreeWalker.m b/HTMLKit/HTMLTreeWalker.m index b76c119..0d27f0e 100644 --- a/HTMLKit/HTMLTreeWalker.m +++ b/HTMLKit/HTMLTreeWalker.m @@ -27,6 +27,17 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) #pragma mark - Lifecycle +- (instancetype)initWithNode:(HTMLNode *)node +{ + return [self initWithNode:node filter:nil]; +} + +- (instancetype)initWithNode:(HTMLNode *)node + filter:(id<HTMLNodeFilter>)filter +{ + return [self initWithNode:node showOptions:HTMLNodeFilterShowAll filter:filter]; +} + - (instancetype)initWithNode:(HTMLNode *)node showOptions:(HTMLNodeFilterShowOptions)showOptions filter:(id<HTMLNodeFilter>)filter From 7f25aacaf1b5e5294e5f75dfabcabe9247fbe3e9 Mon Sep 17 00:00:00 2001 From: iska <iska.gp@gmail.com> Date: Sat, 6 Jun 2015 19:00:02 +0200 Subject: [PATCH 37/40] Add test cases for the Tree Walker class --- HTMLKit.xcodeproj/project.pbxproj | 6 + HTMLKit/HTMLTreeWalker.m | 6 +- HTMLKitTests/HTMLTreeWalkerTests.m | 503 +++++++++++++++++++++++++++++ 3 files changed, 512 insertions(+), 3 deletions(-) create mode 100644 HTMLKitTests/HTMLTreeWalkerTests.m diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index ff7ddb5..1ea6aea 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -69,6 +69,8 @@ 624717181B22333200C11912 /* HTMLNodeTraversal.h in Headers */ = {isa = PBXBuildFile; fileRef = 624717161B22333200C11912 /* HTMLNodeTraversal.h */; }; 624717191B22333200C11912 /* HTMLNodeTraversal.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717171B22333200C11912 /* HTMLNodeTraversal.m */; }; 6247171A1B22333200C11912 /* HTMLNodeTraversal.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717171B22333200C11912 /* HTMLNodeTraversal.m */; }; + 6247171C1B2240B800C11912 /* HTMLTreeWalkerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6247171B1B2240B800C11912 /* HTMLTreeWalkerTests.m */; }; + 6247171D1B2240B800C11912 /* HTMLTreeWalkerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6247171B1B2240B800C11912 /* HTMLTreeWalkerTests.m */; }; 624717B81B21FE5400B38302 /* HTMLNodeFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */; }; 624717B91B21FE5400B38302 /* HTMLNodeFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */; }; 624717BC1B22009200B38302 /* HTMLTreeWalker.h in Headers */ = {isa = PBXBuildFile; fileRef = 624717BA1B22009200B38302 /* HTMLTreeWalker.h */; }; @@ -221,6 +223,7 @@ 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLToken.m; sourceTree = "<group>"; }; 624717161B22333200C11912 /* HTMLNodeTraversal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeTraversal.h; sourceTree = "<group>"; }; 624717171B22333200C11912 /* HTMLNodeTraversal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeTraversal.m; sourceTree = "<group>"; }; + 6247171B1B2240B800C11912 /* HTMLTreeWalkerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLTreeWalkerTests.m; sourceTree = "<group>"; }; 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeFilter.m; sourceTree = "<group>"; }; 624717BA1B22009200B38302 /* HTMLTreeWalker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLTreeWalker.h; sourceTree = "<group>"; }; 624717BB1B22009200B38302 /* HTMLTreeWalker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLTreeWalker.m; sourceTree = "<group>"; }; @@ -379,6 +382,7 @@ isa = PBXGroup; children = ( 623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */, + 6247171B1B2240B800C11912 /* HTMLTreeWalkerTests.m */, 624FC3791AE591D80015DDF9 /* HTMLKitNodesTests.m */, 62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */, ); @@ -794,6 +798,7 @@ files = ( 6239755B1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */, 623CAF9E1AD88BEA00E34C32 /* HTMLKitParserPerformance.m in Sources */, + 6247171D1B2240B800C11912 /* HTMLTreeWalkerTests.m in Sources */, 62EC7AE71AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */, 624B9FB61AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m in Sources */, 6236738F1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m in Sources */, @@ -849,6 +854,7 @@ files = ( 6239755A1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */, 623CAF9D1AD88BEA00E34C32 /* HTMLKitParserPerformance.m in Sources */, + 6247171C1B2240B800C11912 /* HTMLTreeWalkerTests.m in Sources */, 62EC7AE61AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */, 624B9FB51AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m in Sources */, 6236738E1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m in Sources */, diff --git a/HTMLKit/HTMLTreeWalker.m b/HTMLKit/HTMLTreeWalker.m index 0d27f0e..7224425 100644 --- a/HTMLKit/HTMLTreeWalker.m +++ b/HTMLKit/HTMLTreeWalker.m @@ -93,7 +93,7 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) HTMLNode *sibling = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.nextSibling : node.previousSibling; if (sibling != nil) { node = sibling; - continue; + break; } HTMLNode *parent = node.parentNode; @@ -135,8 +135,8 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) return node; } - HTMLNode *sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.firstChiledNode : node.lastChildNode; - if (sibling == nil) { + sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.firstChiledNode : node.lastChildNode; + if (result == HTMLNodeFilterReject || sibling == nil) { sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.nextSibling : node.previousSibling; } } diff --git a/HTMLKitTests/HTMLTreeWalkerTests.m b/HTMLKitTests/HTMLTreeWalkerTests.m new file mode 100644 index 0000000..256ea32 --- /dev/null +++ b/HTMLKitTests/HTMLTreeWalkerTests.m @@ -0,0 +1,503 @@ + // + // HTMLTreeWalkerTests.m + // HTMLKit + // + // Created by Iska on 05/06/15. + // Copyright (c) 2015 BrainCookie. All rights reserved. + // + +#import <XCTest/XCTest.h> +#import "HTMLTreeWalker.h" +#import "HTMLDOM.h" + +@interface HTMLTreeWalkerTests : XCTestCase + +@end + +@implementation HTMLTreeWalkerTests + +#pragma mark - Asserts + +#define AssertElementWithId(input, id) \ + do { \ + HTMLNode *node = input;\ + XCTAssertEqual(node.nodeType, HTMLNodeElement);\ + XCTAssertEqualObjects(node.asElement[@"id"], id);\ + } while(0) + +#define AssertTextWithValue(input, value) \ + do { \ + HTMLNode *node = input;\ + XCTAssertEqual(node.nodeType, HTMLNodeText);\ + XCTAssertEqualObjects(node.textContent, value);\ + } while(0) + +#define AssertCommentWithValue(input, value) \ + do { \ + HTMLNode *node = input;\ + XCTAssertEqual(node.nodeType, HTMLNodeComment);\ + XCTAssertEqualObjects(node.textContent, value);\ + } while(0) + +#pragma mark - Tests + +- (void)testTreeWalkerInit +{ + HTMLNode *root = self.basicWalkingDOM; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root]; + + XCTAssertNotNil(walker); + XCTAssertNotNil(walker.root); + XCTAssertNotNil(walker.currentNode); + XCTAssertNil(walker.filter); + XCTAssertEqual(walker.whatToShow, HTMLNodeFilterShowAll); + + XCTAssertEqualObjects(walker.root, root); + XCTAssertEqualObjects(walker.root, walker.currentNode); +} + +#pragma mark - Basic Walking + +- (HTMLNode *)basicWalkingDOM +{ + // Tree structure: + // #a + // | + // +----+----+ + // | | + // "b" #c + // | + // +----+----+ + // | | + // #d <!--j--> + // | + // +----+----+ + // | | | + // "e" #f "i" + // | + // +--+--+ + // | | + // "g" <!--h--> + + HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"a"}]; + + [div appendNode:[[HTMLText alloc] initWithData:@"b"]]; + + HTMLElement *c = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"c"}]; + [div appendNode:c]; + + HTMLElement *d = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"d"}]; + [c appendNode:d]; + [c appendNode:[[HTMLComment alloc] initWithData:@"j"]]; + + [d appendNode:[[HTMLText alloc] initWithData:@"e"]]; + + HTMLElement *f = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"f"}]; + [d appendNode:f]; + [d appendNode:[[HTMLText alloc] initWithData:@"i"]]; + + [f appendNode:[[HTMLText alloc] initWithData:@"g"]]; + [f appendNode:[[HTMLComment alloc] initWithData:@"h"]]; + + return div; +} + +- (void)testBasicWalking +{ + HTMLNode *root = self.basicWalkingDOM; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root]; + + HTMLNode *f = root.lastChildNode.firstChiledNode.childNodes[1]; + + AssertElementWithId(walker.currentNode, @"a"); + XCTAssertNil(walker.parentNode); + AssertElementWithId(walker.currentNode, @"a"); + + AssertTextWithValue(walker.firstChild, @"b"); + AssertTextWithValue(walker.currentNode, @"b"); + + AssertElementWithId(walker.nextSibling, @"c"); + AssertElementWithId(walker.currentNode, @"c"); + + AssertCommentWithValue(walker.lastChild, @"j"); + AssertCommentWithValue(walker.currentNode, @"j"); + + AssertElementWithId(walker.previousSibling, @"d"); + AssertElementWithId(walker.currentNode, @"d"); + + AssertTextWithValue(walker.nextNode, @"e"); + AssertTextWithValue(walker.currentNode, @"e"); + + AssertElementWithId(walker.parentNode, @"d"); + AssertElementWithId(walker.currentNode, @"d"); + + AssertElementWithId(walker.previousNode, @"c"); + AssertElementWithId(walker.currentNode, @"c"); + + XCTAssertNil(walker.nextSibling); + AssertElementWithId(walker.currentNode, @"c"); + + walker.currentNode = f; + XCTAssertEqualObjects(walker.currentNode, f); +} + +#pragma mark - Current Node + +- (HTMLDocument *)currentNodeDOM +{ + HTMLDocument *document = [HTMLDocument documentWithString: + @"<div id='first'><p><a></a></p></div>" + @"<div id='second'><p><b></b></p</div>"]; + + return document; +} + +- (void)testThatTreeWalkerParentHasNoEffectCurrentNodeWhenParentIsNotUnderRoot +{ + HTMLDocument *document = self.currentNodeDOM; + HTMLNode *first = document.body.firstChiledNode; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:first + showOptions:HTMLNodeFilterShowElement + filter:nil]; + + AssertElementWithId(walker.currentNode, @"first"); + XCTAssertNil(walker.parentNode); + AssertElementWithId(walker.currentNode, @"first"); +} + +- (void)testThatSettingCurrentNodeToNodesNotUnderRootIsHandledCorrectly +{ + HTMLDocument *document = self.currentNodeDOM; + HTMLNode *first = document.body.firstChiledNode; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:first + showOptions:HTMLNodeFilterShowElement|HTMLNodeFilterShowComment + filter:nil]; + walker.currentNode = document.documentElement; + XCTAssertNil(walker.parentNode); + XCTAssertEqualObjects(walker.currentNode, document.documentElement); + + walker.currentNode = document.documentElement; + XCTAssertEqualObjects(walker.nextNode, document.documentElement.firstChiledNode); + XCTAssertEqualObjects(walker.currentNode, document.documentElement.firstChiledNode); + + walker.currentNode = document.documentElement; + XCTAssertNil(walker.previousNode); + XCTAssertEqualObjects(walker.currentNode, document.documentElement); + + walker.currentNode = document.documentElement; + XCTAssertEqualObjects(walker.firstChild, document.documentElement.firstChiledNode); + XCTAssertEqualObjects(walker.currentNode, document.documentElement.firstChiledNode); + + walker.currentNode = document.documentElement; + XCTAssertEqualObjects(walker.lastChild, document.documentElement.lastChildNode); + XCTAssertEqualObjects(walker.currentNode, document.documentElement.lastChildNode); + + walker.currentNode = document.documentElement; + XCTAssertNil(walker.nextSibling); + XCTAssertEqualObjects(walker.currentNode, document.documentElement); + + walker.currentNode = document.documentElement; + XCTAssertNil(walker.previousSibling); + XCTAssertEqualObjects(walker.currentNode, document.documentElement); +} + +#pragma mark - Filter + +- (HTMLElement *)filterBasicDOM +{ + HTMLElement *root = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"root"}]; + + HTMLElement *a1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"A1"}]; + HTMLElement *b1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B1"}]; + HTMLElement *b2 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B2"}]; + + [root appendNode:a1]; + [a1 appendNode:b1]; + [a1 appendNode:b2]; + + return root; +} + +- (void)testTreeWalkerNilFilter +{ + HTMLElement *root = self.filterBasicDOM; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:nil]; + + AssertElementWithId(walker.currentNode, @"root"); + AssertElementWithId(walker.firstChild, @"A1"); + AssertElementWithId(walker.currentNode, @"A1"); + AssertElementWithId(walker.nextNode, @"B1"); + AssertElementWithId(walker.currentNode, @"B1"); +} + +- (void)testTreeWalkerWithFilter +{ + HTMLElement *root = self.filterBasicDOM; + + id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) { + if ([node.asElement[@"id"] isEqualToString:@"B1"]) { + return HTMLNodeFilterSkip; + } + return HTMLNodeFilterAccept; + }]; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:filter]; + + AssertElementWithId(walker.currentNode, @"root"); + AssertElementWithId(walker.firstChild, @"A1"); + AssertElementWithId(walker.currentNode, @"A1"); + AssertElementWithId(walker.nextNode, @"B2"); + AssertElementWithId(walker.currentNode, @"B2"); +} + +#pragma mark - Filter Skip + +- (HTMLElement *)filterDOM +{ + HTMLElement *root = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"root"}]; + + HTMLElement *a1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"A1"}]; + HTMLElement *b1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B1"}]; + HTMLElement *b2 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B2"}]; + HTMLElement *b3 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B3"}]; + HTMLElement *c1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"C1"}]; + + [root appendNode:a1]; + [a1 appendNode:b1]; + [a1 appendNode:b2]; + [a1 appendNode:b3]; + [b1 appendNode:c1]; + + return root; +} + +- (id<HTMLNodeFilter>)skipB1Filter +{ + id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) { + if ([node.asElement[@"id"] isEqualToString:@"B1"]) { + return HTMLNodeFilterSkip; + } + return HTMLNodeFilterAccept; + }]; + return filter; +} + +- (id<HTMLNodeFilter>)skipB2Filter +{ + id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) { + if ([node.asElement[@"id"] isEqualToString:@"B2"]) { + return HTMLNodeFilterSkip; + } + return HTMLNodeFilterAccept; + }]; + return filter; +} + +- (id<HTMLNodeFilter>)rejectB1Filter +{ + id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) { + if ([node.asElement[@"id"] isEqualToString:@"B1"]) { + return HTMLNodeFilterReject; + } + return HTMLNodeFilterAccept; + }]; + return filter; +} + +- (id<HTMLNodeFilter>)rejectB2Filter +{ + id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) { + if ([node.asElement[@"id"] isEqualToString:@"B2"]) { + return HTMLNodeFilterReject; + } + return HTMLNodeFilterAccept; + }]; + return filter; +} + +static HTMLElement * (^ FindElementById)(HTMLNode *, NSString *) = ^ HTMLElement * (HTMLNode *root, NSString *id) { + for (HTMLNode *node in [root nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]) { + if ([node.asElement[@"id"] isEqualToString:id]) { + return node.asElement; + } + } + return nil; +}; + +- (void)testThatFilterSkipsNextNode +{ + HTMLElement *root = self.filterDOM; + id<HTMLNodeFilter> filter = self.skipB1Filter; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:filter]; + + AssertElementWithId(walker.nextNode, @"A1"); + AssertElementWithId(walker.nextNode, @"C1"); + AssertElementWithId(walker.nextNode, @"B2"); + AssertElementWithId(walker.nextNode, @"B3"); +} + +- (void)testThatFilterSkipsFirstChild +{ + HTMLElement *root = self.filterDOM; + id<HTMLNodeFilter> filter = self.skipB1Filter; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:filter]; + + AssertElementWithId(walker.firstChild, @"A1"); + AssertElementWithId(walker.firstChild, @"C1"); +} + +- (void)testThatFilterSkipsNextSibling +{ + HTMLElement *root = self.filterDOM; + id<HTMLNodeFilter> filter = self.skipB2Filter; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:filter]; + + AssertElementWithId(walker.firstChild, @"A1"); + AssertElementWithId(walker.firstChild, @"B1"); + AssertElementWithId(walker.nextSibling, @"B3"); +} + +- (void)testThatFilterSkipsParentNode +{ + HTMLElement *root = self.filterDOM; + id<HTMLNodeFilter> filter = self.skipB1Filter; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:filter]; + + walker.currentNode = FindElementById(root, @"C1"); + AssertElementWithId(walker.parentNode, @"A1"); +} + +- (void)testThatFilterSkipsPreviousSibling +{ + HTMLElement *root = self.filterDOM; + id<HTMLNodeFilter> filter = self.skipB2Filter; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:filter]; + + walker.currentNode = FindElementById(root, @"B3"); + AssertElementWithId(walker.previousSibling, @"B1"); +} + +- (void)testThatFilterSkipsPreviousNode +{ + HTMLElement *root = self.filterDOM; + id<HTMLNodeFilter> filter = self.skipB1Filter; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:filter]; + + walker.currentNode = FindElementById(root, @"B3"); + AssertElementWithId(walker.previousNode, @"B2"); + AssertElementWithId(walker.previousNode, @"C1"); + AssertElementWithId(walker.previousNode, @"A1"); +} + +#pragma mark - Filter Reject + +- (void)testThatFilterRejectsNextNode +{ + HTMLElement *root = self.filterDOM; + id<HTMLNodeFilter> filter = self.rejectB1Filter; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:filter]; + + AssertElementWithId(walker.nextNode, @"A1"); + AssertElementWithId(walker.nextNode, @"B2"); + AssertElementWithId(walker.nextNode, @"B3"); +} + +- (void)testThatFilterRejectsFirstChild +{ + HTMLElement *root = self.filterDOM; + id<HTMLNodeFilter> filter = self.rejectB1Filter; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:filter]; + + AssertElementWithId(walker.firstChild, @"A1"); + AssertElementWithId(walker.firstChild, @"B2"); +} + +- (void)testThatFilterRejectsNextSibling +{ + HTMLElement *root = self.filterDOM; + id<HTMLNodeFilter> filter = self.rejectB2Filter; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:filter]; + + AssertElementWithId(walker.firstChild, @"A1"); + AssertElementWithId(walker.firstChild, @"B1"); + AssertElementWithId(walker.nextSibling, @"B3"); +} + +- (void)testThatFilterRejectsParentNode +{ + HTMLElement *root = self.filterDOM; + id<HTMLNodeFilter> filter = self.rejectB1Filter; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:filter]; + + walker.currentNode = FindElementById(root, @"C1"); + AssertElementWithId(walker.parentNode, @"A1"); +} + +- (void)testThatFilterRejectsPreviousSibling +{ + HTMLElement *root = self.filterDOM; + id<HTMLNodeFilter> filter = self.rejectB2Filter; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:filter]; + + walker.currentNode = FindElementById(root, @"B3"); + AssertElementWithId(walker.previousSibling, @"B1"); +} + +- (void)testThatFilterRejectsPreviousNode +{ + HTMLElement *root = self.filterDOM; + id<HTMLNodeFilter> filter = self.rejectB1Filter; + + HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root + showOptions:HTMLNodeFilterShowElement + filter:filter]; + + walker.currentNode = FindElementById(root, @"B3"); + AssertElementWithId(walker.previousNode, @"B2"); + AssertElementWithId(walker.previousNode, @"A1"); +} + + +@end From df5387088081dff5b52f12cf16261268e4242f16 Mon Sep 17 00:00:00 2001 From: iska <iska.gp@gmail.com> Date: Sat, 6 Jun 2015 19:04:03 +0200 Subject: [PATCH 38/40] Drop the "Node" suffix from HTML Node's first child & last child properties https://dom.spec.whatwg.org/#interface-node --- HTMLKit/HTMLDocument.m | 2 +- HTMLKit/HTMLElement.m | 4 +-- HTMLKit/HTMLNode.h | 4 +-- HTMLKit/HTMLNode.m | 8 ++--- HTMLKit/HTMLNodeIterator.m | 6 ++-- HTMLKit/HTMLNodeTraversal.m | 8 ++--- HTMLKit/HTMLParser.m | 4 +-- HTMLKit/HTMLTreeWalker.m | 10 +++---- HTMLKitTests/HTMLKitNodeIteratorTests.m | 24 +++++++-------- HTMLKitTests/HTMLKitNodesTests.m | 40 ++++++++++++------------- HTMLKitTests/HTMLTreeWalkerTests.m | 18 +++++------ 11 files changed, 64 insertions(+), 64 deletions(-) diff --git a/HTMLKit/HTMLDocument.m b/HTMLKit/HTMLDocument.m index 86d36c3..09baa88 100644 --- a/HTMLKit/HTMLDocument.m +++ b/HTMLKit/HTMLDocument.m @@ -77,7 +77,7 @@ - (HTMLElement *)rootElement { - for (HTMLNode *node = self.firstChiledNode; node; node = node.nextSibling) { + for (HTMLNode *node = self.firstChild; node; node = node.nextSibling) { if (node.nodeType == HTMLNodeElement) { return node.asElement; } diff --git a/HTMLKit/HTMLElement.m b/HTMLKit/HTMLElement.m index 1c018da..6083537 100644 --- a/HTMLKit/HTMLElement.m +++ b/HTMLKit/HTMLElement.m @@ -146,8 +146,8 @@ return result; } - if ([self.tagName isEqualToAny:@"pre", @"textarea", @"listing", nil] && self.firstChiledNode.nodeType == HTMLNodeText) { - HTMLText *textNode = (HTMLText *)self.firstChiledNode; + if ([self.tagName isEqualToAny:@"pre", @"textarea", @"listing", nil] && self.firstChild.nodeType == HTMLNodeText) { + HTMLText *textNode = (HTMLText *)self.firstChild; if ([textNode.data hasPrefix:@"\n"]) { [result appendString:@"\n"]; } diff --git a/HTMLKit/HTMLNode.h b/HTMLKit/HTMLNode.h index a488dcd..eb07dbc 100644 --- a/HTMLKit/HTMLNode.h +++ b/HTMLKit/HTMLNode.h @@ -53,9 +53,9 @@ typedef NS_ENUM(unsigned short, HTMLDocumentPosition) @property (nonatomic, strong, readonly) NSOrderedSet *childNodes; -@property (nonatomic, strong, readonly) HTMLNode *firstChiledNode; +@property (nonatomic, strong, readonly) HTMLNode *firstChild; -@property (nonatomic, strong, readonly) HTMLNode *lastChildNode; +@property (nonatomic, strong, readonly) HTMLNode *lastChild; @property (nonatomic, strong, readonly) HTMLNode *previousSibling; diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index f6cedbc..fdff072 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -70,12 +70,12 @@ return _parentNode.nodeType == HTMLNodeElement ? (HTMLElement *)_parentNode : nil; } -- (HTMLNode *)firstChiledNode +- (HTMLNode *)firstChild { return self.childNodes.firstObject; } -- (HTMLNode *)lastChildNode +- (HTMLNode *)lastChild { return self.childNodes.lastObject; } @@ -147,13 +147,13 @@ - (HTMLNode *)prependNode:(HTMLNode *)node { - return [self insertNode:node beforeChildNode:self.firstChiledNode]; + return [self insertNode:node beforeChildNode:self.firstChild]; } - (void)prependNodes:(NSArray *)nodes { for (id node in nodes.reverseObjectEnumerator) { - [self insertNode:node beforeChildNode:self.firstChiledNode]; + [self insertNode:node beforeChildNode:self.firstChild]; } } diff --git a/HTMLKit/HTMLNodeIterator.m b/HTMLKit/HTMLNodeIterator.m index c5e85d1..6bfb9f4 100644 --- a/HTMLKit/HTMLNodeIterator.m +++ b/HTMLKit/HTMLNodeIterator.m @@ -89,7 +89,7 @@ typedef NS_ENUM(short, TraverseDirection) } if (_pointerBeforeReferenceNode) { - HTMLNode *nextSibling = oldPreviousSibling != nil ? oldPreviousSibling.nextSibling : oldParent.firstChiledNode; + HTMLNode *nextSibling = oldPreviousSibling != nil ? oldPreviousSibling.nextSibling : oldParent.firstChild; if (nextSibling != nil) { _referenceNode = nextSibling; return; @@ -105,8 +105,8 @@ typedef NS_ENUM(short, TraverseDirection) } HTMLNode * (^ lastInclusiveDescendant) (HTMLNode *) = ^ HTMLNode * (HTMLNode *node) { - while (node.lastChildNode) { - node = node.lastChildNode; + while (node.lastChild) { + node = node.lastChild; } return node; }; diff --git a/HTMLKit/HTMLNodeTraversal.m b/HTMLKit/HTMLNodeTraversal.m index 1c646df..dd17b2a 100644 --- a/HTMLKit/HTMLNodeTraversal.m +++ b/HTMLKit/HTMLNodeTraversal.m @@ -14,8 +14,8 @@ HTMLNode * PrecedingNode(HTMLNode *node, HTMLNode *root) { HTMLNode *previous = node.previousSibling; if (previous != nil) { - while (previous.lastChildNode != nil) { - previous = previous.lastChildNode; + while (previous.lastChild != nil) { + previous = previous.lastChild; } return previous; } @@ -29,8 +29,8 @@ HTMLNode * PrecedingNode(HTMLNode *node, HTMLNode *root) HTMLNode * FollowingNode(HTMLNode *node, HTMLNode *root) { - if (node.firstChiledNode != nil) { - return node.firstChiledNode; + if (node.firstChild != nil) { + return node.firstChild; } do { diff --git a/HTMLKit/HTMLParser.m b/HTMLKit/HTMLParser.m index d561e59..6f7bb46 100644 --- a/HTMLKit/HTMLParser.m +++ b/HTMLKit/HTMLParser.m @@ -455,8 +455,8 @@ if (adjustedInsertionLocation.nodeType != HTMLNodeDocument) { if (child != nil && child.previousSibling.nodeType == HTMLNodeText) { [(HTMLText *)child.previousSibling appendString:data]; - } else if (adjustedInsertionLocation.lastChildNode.nodeType == HTMLNodeText) { - [(HTMLText *)adjustedInsertionLocation.lastChildNode appendString:data]; + } else if (adjustedInsertionLocation.lastChild.nodeType == HTMLNodeText) { + [(HTMLText *)adjustedInsertionLocation.lastChild appendString:data]; } else { HTMLText *text = [[HTMLText alloc] initWithData:data]; [adjustedInsertionLocation insertNode:text beforeChildNode:child]; diff --git a/HTMLKit/HTMLTreeWalker.m b/HTMLKit/HTMLTreeWalker.m index 7224425..0e21ed0 100644 --- a/HTMLKit/HTMLTreeWalker.m +++ b/HTMLKit/HTMLTreeWalker.m @@ -72,7 +72,7 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) { HTMLNode *node = _currentNode; - node = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.firstChiledNode : node.lastChildNode; + node = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.firstChild : node.lastChild; while (node != nil) { HTMLNodeFilterValue result = FilterNode(self.filter, self.whatToShow, node); @@ -82,7 +82,7 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) } if (result == HTMLNodeFilterSkip) { - HTMLNode *child = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.firstChiledNode : node.lastChildNode; + HTMLNode *child = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.firstChild : node.lastChild; if (child != nil) { node = child; continue; @@ -135,7 +135,7 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) return node; } - sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.firstChiledNode : node.lastChildNode; + sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.firstChild : node.lastChild; if (result == HTMLNodeFilterReject || sibling == nil) { sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.nextSibling : node.previousSibling; } @@ -176,7 +176,7 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) HTMLNodeFilterValue result = FilterNode(self.filter, self.whatToShow, node); while (result != HTMLNodeFilterReject && node.hasChildNodes) { - node = node.lastChildNode; + node = node.lastChild; result = FilterNode(self.filter, self.whatToShow, node); } @@ -210,7 +210,7 @@ typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType) while (YES) { while (result != HTMLNodeFilterReject && node.hasChildNodes) { - node = node.firstChiledNode; + node = node.firstChild; result = FilterNode(self.filter, self.whatToShow, node); if (result == HTMLNodeFilterAccept) { _currentNode = node; diff --git a/HTMLKitTests/HTMLKitNodeIteratorTests.m b/HTMLKitTests/HTMLKitNodeIteratorTests.m index 118b5c6..7ff6823 100644 --- a/HTMLKitTests/HTMLKitNodeIteratorTests.m +++ b/HTMLKitTests/HTMLKitNodeIteratorTests.m @@ -367,8 +367,8 @@ static void (^ IterateUpToNode)(HTMLNodeIterator *, HTMLNode *) = ^ (HTMLNodeIte }; static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node) { - while (node.lastChildNode) { - node = node.lastChildNode; + while (node.lastChild) { + node = node.lastChild; } return node; }; @@ -376,7 +376,7 @@ static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node) - (void)testThatRemovingRootNodeShouldNotAffectIterator { HTMLDocument *document = self.document; - HTMLNode *node = document.body.firstChiledNode; // <span> + HTMLNode *node = document.body.firstChild; // <span> HTMLNodeIterator *iterator = node.nodeIterator; @@ -401,7 +401,7 @@ static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node) RemoveThenInsertNode(iterator.root.childNodes[1]); // Remove <p> XCTAssertEqualObjects(iterator.root, body); - XCTAssertEqualObjects(iterator.referenceNode, body.firstChiledNode); + XCTAssertEqualObjects(iterator.referenceNode, body.firstChild); XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO); } @@ -420,7 +420,7 @@ static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node) XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO); HTMLNode *next = iterator.nextNode; // "Hello" - XCTAssertEqualObjects(next, iterator.root.firstChiledNode); + XCTAssertEqualObjects(next, iterator.root.firstChild); } - (void)testThatRemovingReferenceNodeShouldUpdateIterator_NonNilOldPreviousSibling_NotBeforeReference @@ -434,7 +434,7 @@ static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node) IterateUpToNode(iterator, node); // Reference node: <p>, pointer-before-reference: NO RemoveThenInsertNode(node); // Remove <p> with old previos sibling being <span> - XCTAssertEqualObjects(iterator.referenceNode, LastDescendant(body.firstChiledNode)); + XCTAssertEqualObjects(iterator.referenceNode, LastDescendant(body.firstChild)); XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO); } @@ -450,7 +450,7 @@ static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node) [iterator previousNode]; // pointer-before-reference: YES RemoveThenInsertNode(node); // Remove <p> with old previos sibling being <span> - XCTAssertEqualObjects(iterator.referenceNode, body.firstChiledNode); + XCTAssertEqualObjects(iterator.referenceNode, body.firstChild); XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES); } @@ -502,7 +502,7 @@ static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node) [iterator nextNode]; // Reference node: "This is an " RemoveThenInsertNode(parent); - XCTAssertEqualObjects(iterator.referenceNode, LastDescendant(body.firstChiledNode)); + XCTAssertEqualObjects(iterator.referenceNode, LastDescendant(body.firstChild)); XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO); } @@ -519,7 +519,7 @@ static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node) [iterator previousNode]; // pointer-before-reference: YES RemoveThenInsertNode(parent); - XCTAssertEqualObjects(iterator.referenceNode, body.firstChiledNode); + XCTAssertEqualObjects(iterator.referenceNode, body.firstChild); XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES); } @@ -555,13 +555,13 @@ static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node) body.innerHTML = @"<div><p><a></a></p></div><div></div>"; - HTMLNodeIterator *iterator = body.firstChiledNode.nodeIterator; + HTMLNodeIterator *iterator = body.firstChild.nodeIterator; - IterateUpToNode(iterator, LastDescendant(body.firstChiledNode)); // Referecne node: <a> + IterateUpToNode(iterator, LastDescendant(body.firstChild)); // Referecne node: <a> HTMLNode *node = [iterator previousNode]; // pointer-before-reference: YES RemoveThenInsertNode(node); - XCTAssertEqualObjects(iterator.referenceNode, iterator.root.firstChiledNode); + XCTAssertEqualObjects(iterator.referenceNode, iterator.root.firstChild); XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO); } diff --git a/HTMLKitTests/HTMLKitNodesTests.m b/HTMLKitTests/HTMLKitNodesTests.m index 524a25c..87f37f9 100644 --- a/HTMLKitTests/HTMLKitNodesTests.m +++ b/HTMLKitTests/HTMLKitNodesTests.m @@ -37,10 +37,10 @@ XCTAssertNil(node.ownerDocument); XCTAssertNil(node.parentNode); XCTAssertNil(node.parentElement); - XCTAssertNil(node.firstChiledNode); - XCTAssertNil(node.lastChildNode); + XCTAssertNil(node.firstChild); + XCTAssertNil(node.lastChild); XCTAssertNil(node.previousSibling); - XCTAssertNil(node.lastChildNode); + XCTAssertNil(node.lastChild); } - (void)testAppendNode @@ -50,7 +50,7 @@ [element appendNode:comment]; XCTAssertEqual(element.childNodesCount, 1); - XCTAssertEqual(element.firstChiledNode, comment); + XCTAssertEqual(element.firstChild, comment); HTMLElement *firstElement = [HTMLElement new]; HTMLElement *secondElement = [HTMLElement new]; @@ -59,8 +59,8 @@ [element appendNodes:nodes]; XCTAssertEqual(element.childNodesCount, 3); - XCTAssertEqual(element.firstChiledNode, comment); - XCTAssertEqual(element.lastChildNode, secondElement); + XCTAssertEqual(element.firstChild, comment); + XCTAssertEqual(element.lastChild, secondElement); } - (void)testPrependNode @@ -73,7 +73,7 @@ [element prependNode:comment]; XCTAssertEqual(element.childNodesCount, 2); - XCTAssertEqual(element.firstChiledNode, comment); + XCTAssertEqual(element.firstChild, comment); HTMLElement *firstElement = [HTMLElement new]; HTMLElement *secondElement = [HTMLElement new]; @@ -82,8 +82,8 @@ [element prependNodes:nodes]; XCTAssertEqual(element.childNodesCount, 4); - XCTAssertEqual(element.firstChiledNode, firstElement); - XCTAssertEqual(element.lastChildNode, text); + XCTAssertEqual(element.firstChild, firstElement); + XCTAssertEqual(element.lastChild, text); } - (void)testAppendDocumentFragment @@ -104,10 +104,10 @@ XCTAssertEqualObjects(firstChild.parentNode, element); XCTAssertEqualObjects(secondChild.parentNode, element); - XCTAssertEqualObjects(element.firstChiledNode, comment); - XCTAssertEqualObjects(element.firstChiledNode.nextSibling, firstChild); - XCTAssertEqualObjects(element.lastChildNode.previousSibling, firstChild); - XCTAssertEqualObjects(element.lastChildNode, secondChild); + XCTAssertEqualObjects(element.firstChild, comment); + XCTAssertEqualObjects(element.firstChild.nextSibling, firstChild); + XCTAssertEqualObjects(element.lastChild.previousSibling, firstChild); + XCTAssertEqualObjects(element.lastChild, secondChild); } - (void)testParentNode @@ -170,20 +170,20 @@ HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement]; [node appendNode:firstChild]; - XCTAssertEqualObjects(node.firstChiledNode, firstChild); - XCTAssertEqualObjects(node.lastChildNode, firstChild); + XCTAssertEqualObjects(node.firstChild, firstChild); + XCTAssertEqualObjects(node.lastChild, firstChild); HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement]; [node appendNode:secondChild]; - XCTAssertEqualObjects(node.firstChiledNode, firstChild); - XCTAssertEqualObjects(node.lastChildNode, secondChild); + XCTAssertEqualObjects(node.firstChild, firstChild); + XCTAssertEqualObjects(node.lastChild, secondChild); HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement]; [node appendNode:thirdChild]; - XCTAssertEqualObjects(node.firstChiledNode, firstChild); - XCTAssertEqualObjects(node.lastChildNode, thirdChild); + XCTAssertEqualObjects(node.firstChild, firstChild); + XCTAssertEqualObjects(node.lastChild, thirdChild); } - (void)testNextAndPreviousSiblingNodes @@ -478,7 +478,7 @@ XCTAssertEqual(element.childNodesCount, 2); - XCTAssertEqualObjects(element.firstChiledNode.asElement.tagName, @"p"); + XCTAssertEqualObjects(element.firstChild.asElement.tagName, @"p"); XCTAssertEqualObjects([element childNodeAtIndex:1].asElement.tagName, @"p"); } diff --git a/HTMLKitTests/HTMLTreeWalkerTests.m b/HTMLKitTests/HTMLTreeWalkerTests.m index 256ea32..6aeeaf2 100644 --- a/HTMLKitTests/HTMLTreeWalkerTests.m +++ b/HTMLKitTests/HTMLTreeWalkerTests.m @@ -109,7 +109,7 @@ HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root]; - HTMLNode *f = root.lastChildNode.firstChiledNode.childNodes[1]; + HTMLNode *f = root.lastChild.firstChild.childNodes[1]; AssertElementWithId(walker.currentNode, @"a"); XCTAssertNil(walker.parentNode); @@ -157,7 +157,7 @@ - (void)testThatTreeWalkerParentHasNoEffectCurrentNodeWhenParentIsNotUnderRoot { HTMLDocument *document = self.currentNodeDOM; - HTMLNode *first = document.body.firstChiledNode; + HTMLNode *first = document.body.firstChild; HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:first showOptions:HTMLNodeFilterShowElement @@ -171,7 +171,7 @@ - (void)testThatSettingCurrentNodeToNodesNotUnderRootIsHandledCorrectly { HTMLDocument *document = self.currentNodeDOM; - HTMLNode *first = document.body.firstChiledNode; + HTMLNode *first = document.body.firstChild; HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:first showOptions:HTMLNodeFilterShowElement|HTMLNodeFilterShowComment @@ -181,20 +181,20 @@ XCTAssertEqualObjects(walker.currentNode, document.documentElement); walker.currentNode = document.documentElement; - XCTAssertEqualObjects(walker.nextNode, document.documentElement.firstChiledNode); - XCTAssertEqualObjects(walker.currentNode, document.documentElement.firstChiledNode); + XCTAssertEqualObjects(walker.nextNode, document.documentElement.firstChild); + XCTAssertEqualObjects(walker.currentNode, document.documentElement.firstChild); walker.currentNode = document.documentElement; XCTAssertNil(walker.previousNode); XCTAssertEqualObjects(walker.currentNode, document.documentElement); walker.currentNode = document.documentElement; - XCTAssertEqualObjects(walker.firstChild, document.documentElement.firstChiledNode); - XCTAssertEqualObjects(walker.currentNode, document.documentElement.firstChiledNode); + XCTAssertEqualObjects(walker.firstChild, document.documentElement.firstChild); + XCTAssertEqualObjects(walker.currentNode, document.documentElement.firstChild); walker.currentNode = document.documentElement; - XCTAssertEqualObjects(walker.lastChild, document.documentElement.lastChildNode); - XCTAssertEqualObjects(walker.currentNode, document.documentElement.lastChildNode); + XCTAssertEqualObjects(walker.lastChild, document.documentElement.lastChild); + XCTAssertEqualObjects(walker.currentNode, document.documentElement.lastChild); walker.currentNode = document.documentElement; XCTAssertNil(walker.nextSibling); From a7caa347624f5beba255bda9d1a5a139b9e11355 Mon Sep 17 00:00:00 2001 From: iska <iska.gp@gmail.com> Date: Sat, 6 Jun 2015 20:10:28 +0200 Subject: [PATCH 39/40] Disable HTML DOM checks in parser's performance test The baseline was set before the DOM validations were implemented. --- HTMLKitTests/HTMLKitParserPerformance.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/HTMLKitTests/HTMLKitParserPerformance.m b/HTMLKitTests/HTMLKitParserPerformance.m index f4839d0..005282f 100644 --- a/HTMLKitTests/HTMLKitParserPerformance.m +++ b/HTMLKitTests/HTMLKitParserPerformance.m @@ -15,6 +15,8 @@ @implementation HTMLKitParserPerformance +#define HTMLKIT_NO_DOM_CHECKS + - (void)testParserPerformance { NSString *path = [[NSBundle bundleForClass:self.class] resourcePath]; @@ -28,4 +30,6 @@ }]; } +#undef HTMLKIT_NO_DOM_CHECKS + @end From 045e4db9d1e3d80d0ae16578cb56a57a98ae8663 Mon Sep 17 00:00:00 2001 From: iska <iska.gp@gmail.com> Date: Sat, 6 Jun 2015 20:11:49 +0200 Subject: [PATCH 40/40] Add node iterator, tree walker & node filter imports to the HTMLDOM header --- HTMLKit/HTMLDOM.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/HTMLKit/HTMLDOM.h b/HTMLKit/HTMLDOM.h index 4e9d5ce..c570ae0 100644 --- a/HTMLKit/HTMLDOM.h +++ b/HTMLKit/HTMLDOM.h @@ -14,3 +14,6 @@ #import "HTMLComment.h" #import "HTMLText.h" #import "HTMLTemplate.h" +#import "HTMLNodeIterator.h" +#import "HTMLTreeWalker.h" +#import "HTMLNodeFilter.h"