diff --git a/.jazzy.yaml b/.jazzy.yaml index e8c5082..f808537 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -1,5 +1,5 @@ module: HTMLKit -module_version: 2.1.4 +module_version: 2.1.5 author: Iskandar Abudiab author_url: https://twitter.com/iabudiab github_url: https://github.com/iabudiab/HTMLKit diff --git a/CHANGELOG.md b/CHANGELOG.md index 1042e0d..84b4c9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Change Log +## [2.1.5](https://github.com/iabudiab/HTMLKit/releases/tag/2.1.5) + +Released on 2018.07.16 + +### Fixes + +- Parser would handle foreign attributes incorrectly (issue #30) + + ## [2.1.4](https://github.com/iabudiab/HTMLKit/releases/tag/2.1.4) Released on 2018.05.01 diff --git a/HTMLKit.podspec b/HTMLKit.podspec index 4042956..4d07935 100644 --- a/HTMLKit.podspec +++ b/HTMLKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "HTMLKit" - s.version = "2.1.4" + s.version = "2.1.5" s.summary = "HTMLKit, an Objective-C framework for your everyday HTML needs." s.license = "MIT" s.homepage = "https://github.com/iabudiab/HTMLKit" diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index 4cd4fe4..02250de 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -312,6 +312,9 @@ 62A95A4D1FB0FBFC0009FF26 /* HTMLSerializationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62A95A4C1FB0FBFC0009FF26 /* HTMLSerializationTests.m */; }; 62A95A4E1FB0FBFC0009FF26 /* HTMLSerializationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62A95A4C1FB0FBFC0009FF26 /* HTMLSerializationTests.m */; }; 62A95A4F1FB0FBFC0009FF26 /* HTMLSerializationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62A95A4C1FB0FBFC0009FF26 /* HTMLSerializationTests.m */; }; + 62C82E0D20FD2FFD008497A8 /* HTMLKitParserIssuesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62C82E0C20FD2FFD008497A8 /* HTMLKitParserIssuesTests.m */; }; + 62C82E0E20FD2FFD008497A8 /* HTMLKitParserIssuesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62C82E0C20FD2FFD008497A8 /* HTMLKitParserIssuesTests.m */; }; + 62C82E0F20FD2FFD008497A8 /* HTMLKitParserIssuesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62C82E0C20FD2FFD008497A8 /* HTMLKitParserIssuesTests.m */; }; 62D8345A19FB1AC4009205A9 /* HTML5LibTokenizerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 62D8345819FB1AC4009205A9 /* HTML5LibTokenizerTest.m */; }; 62D91C231DE218A500BEFADE /* HTMLRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 62D91C211DE218A500BEFADE /* HTMLRange.h */; settings = {ATTRIBUTES = (Public, ); }; }; 62D91C241DE218A500BEFADE /* HTMLRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 62D91C211DE218A500BEFADE /* HTMLRange.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -723,6 +726,7 @@ 62AE594319F992F30043F069 /* HTMLCommentToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLCommentToken.m; sourceTree = ""; }; 62AE594719F9948A0043F069 /* HTMLCharacterToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTMLCharacterToken.h; path = include/HTMLCharacterToken.h; sourceTree = ""; }; 62AE594819F9948A0043F069 /* HTMLCharacterToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLCharacterToken.m; sourceTree = ""; }; + 62C82E0C20FD2FFD008497A8 /* HTMLKitParserIssuesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = HTMLKitParserIssuesTests.m; path = HTMLKitTests/HTMLKitParserIssuesTests.m; sourceTree = ""; }; 62D8345719FB1AC4009205A9 /* HTML5LibTokenizerTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTML5LibTokenizerTest.h; path = HTMLKitTests/HTML5LibTokenizerTest.h; sourceTree = ""; }; 62D8345819FB1AC4009205A9 /* HTML5LibTokenizerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTML5LibTokenizerTest.m; path = HTMLKitTests/HTML5LibTokenizerTest.m; sourceTree = ""; }; 62D91C211DE218A500BEFADE /* HTMLRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTMLRange.h; path = include/HTMLRange.h; sourceTree = ""; }; @@ -993,6 +997,7 @@ 625EE45A1CBB171300F2CC8E /* HTMLKitTestUtil.m */, 6236738C1AC0CD2400FF89B3 /* Tokenizer */, 623975581AC362A5007E26F1 /* Tree Construction */, + 62C82E0B20FD2FCB008497A8 /* Parser */, 624B9FB71AE072CB00646C4C /* DOM */, 624B9FB81AE072D500646C4C /* Categories */, 624E1A2D1B1D1C8A00E66AAC /* Structures */, @@ -1097,6 +1102,14 @@ name = Tokenizing; sourceTree = ""; }; + 62C82E0B20FD2FCB008497A8 /* Parser */ = { + isa = PBXGroup; + children = ( + 62C82E0C20FD2FFD008497A8 /* HTMLKitParserIssuesTests.m */, + ); + name = Parser; + sourceTree = ""; + }; 62ECBEDF1C0B671000AF847B /* Parsing */ = { isa = PBXGroup; children = ( @@ -1758,6 +1771,7 @@ 620AB7B12087F18D00AFCCC7 /* CSSStructuralPseudoSelectors.m in Sources */, 62E0BA971E25456700E4D193 /* HTMLCharacterDataTests.m in Sources */, 6216ACFD1C28DCC80074CAB4 /* CSSExtensionSelectorsParsingTests.m in Sources */, + 62C82E0D20FD2FFD008497A8 /* HTMLKitParserIssuesTests.m in Sources */, 62132E5A1C01F83200084175 /* CSSSelectorTest.m in Sources */, 6239755B1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */, 62F658711BD83C8E0045F137 /* CSSNThExpressionSelectorTests.m in Sources */, @@ -1902,6 +1916,7 @@ 620AB7B32087F18D00AFCCC7 /* CSSStructuralPseudoSelectors.m in Sources */, 62E0BA991E25456700E4D193 /* HTMLCharacterDataTests.m in Sources */, 62857D3B1D39A345008DC254 /* CSSSelectorTest.m in Sources */, + 62C82E0F20FD2FFD008497A8 /* HTMLKitParserIssuesTests.m in Sources */, 62857D421D39A345008DC254 /* CSSCombinatorSelectorTests.m in Sources */, 62857D3C1D39A345008DC254 /* CSSSelectorParserTests.m in Sources */, 62857D301D39A339008DC254 /* HTMLKitTokenizerPerformance.m in Sources */, @@ -1991,6 +2006,7 @@ 620AB7B22087F18D00AFCCC7 /* CSSStructuralPseudoSelectors.m in Sources */, 62E0BA981E25456700E4D193 /* HTMLCharacterDataTests.m in Sources */, 6216ACFE1C28DCC80074CAB4 /* CSSExtensionSelectorsParsingTests.m in Sources */, + 62C82E0E20FD2FFD008497A8 /* HTMLKitParserIssuesTests.m in Sources */, 62ECBFCA1C0B6E2E00AF847B /* HTML5LibTokenizerTest.m in Sources */, 62ECBFCB1C0B6E2E00AF847B /* HTMLKitTokenizerTests.m in Sources */, 62ECBFCC1C0B6E2E00AF847B /* HTMLKitTokenizerPerformance.m in Sources */, diff --git a/Sources/HTMLKit-Info.plist b/Sources/HTMLKit-Info.plist index 2dbfcba..82ff466 100644 --- a/Sources/HTMLKit-Info.plist +++ b/Sources/HTMLKit-Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.1.4 + 2.1.5 CFBundleSignature ???? CFBundleVersion diff --git a/Sources/HTMLNode.m b/Sources/HTMLNode.m index d948ff9..6038db3 100644 --- a/Sources/HTMLNode.m +++ b/Sources/HTMLNode.m @@ -127,7 +127,7 @@ NSString * const RemoveChildNode = @"-removeChildNode:"; - (HTMLElement *)nextSiblingElement { - HTMLNode *node = self.previousSibling; + HTMLNode *node = self.nextSibling; while (node && node.nodeType != HTMLNodeElement) { node = node.nextSibling; } diff --git a/Sources/HTMLParser.m b/Sources/HTMLParser.m index e9603cc..5aa9cbc 100644 --- a/Sources/HTMLParser.m +++ b/Sources/HTMLParser.m @@ -1443,7 +1443,6 @@ } else if ([tagName isEqualToString:@"math"]) { [self reconstructActiveFormattingElements]; AdjustMathMLAttributes(token); - AdjustForeignAttributes(token); [self insertForeignElementForToken:token inNamespace:HTMLNamespaceMathML]; if (token.isSelfClosing) { [_stackOfOpenElements popCurrentNode]; @@ -1451,7 +1450,6 @@ } else if ([tagName isEqualToString:@"svg"]) { [self reconstructActiveFormattingElements]; AdjustSVGAttributes(token); - AdjustForeignAttributes(token); [self insertForeignElementForToken:token inNamespace:HTMLNamespaceSVG]; if (token.isSelfClosing) { [_stackOfOpenElements popCurrentNode]; @@ -2541,7 +2539,6 @@ AdjustSVGNameCase(token.asTagToken); AdjustSVGAttributes(token.asTagToken); } - AdjustForeignAttributes(token.asTagToken); [self insertForeignElementForToken:token.asTagToken inNamespace:self.adjustedCurrentNode.htmlNamespace]; if (token.asTagToken.selfClosing) { [_stackOfOpenElements popCurrentNode]; diff --git a/Sources/include/HTMLElementAdjustment.h b/Sources/include/HTMLElementAdjustment.h index 17b1864..907fa7e 100644 --- a/Sources/include/HTMLElementAdjustment.h +++ b/Sources/include/HTMLElementAdjustment.h @@ -140,31 +140,3 @@ NS_INLINE void AdjustSVGNameCase(HTMLTagToken *token) NSString *replacement = replacements[token.tagName] ?: token.tagName; token.tagName = replacement; } - -NS_INLINE void AdjustForeignAttributes(HTMLTagToken *token) -{ - if (token.attributes == nil) { - return; - } - - NSDictionary *replacements = @{ @"xlink:actuate": @"xlink actuate", - @"xlink:arcrole": @"xlink arcrole", - @"xlink:href": @"xlink href", - @"xlink:role": @"xlink role", - @"xlink:show": @"xlink show", - @"xlink:title": @"xlink title", - @"xlink:type": @"xlink type", - @"xml:base": @"xml base", - @"xml:lang": @"xml lang", - @"xml:space": @"xml space", - @"xmlns": @"xmlns", - @"xmlns:xlink": @"xmlns xlink"}; - - HTMLOrderedDictionary *adjusted = [HTMLOrderedDictionary new]; - for (id key in token.attributes) { - NSString *replacement = replacements[key] ?: key; - adjusted[replacement] = token.attributes[key]; - } - token.attributes = adjusted; -} - diff --git a/Tests/HTMLKitTests/HTML5LibTreeConstructionTest.m b/Tests/HTMLKitTests/HTML5LibTreeConstructionTest.m index 3b08d2c..2e9231b 100644 --- a/Tests/HTMLKitTests/HTML5LibTreeConstructionTest.m +++ b/Tests/HTMLKitTests/HTML5LibTreeConstructionTest.m @@ -9,6 +9,7 @@ #import "HTML5LibTreeConstructionTest.h" #import +#import "HTMLDOM.h" #import "HTMLDocumentType.h" #import "HTMLElement.h" #import "HTMLText.h" @@ -289,6 +290,8 @@ NS_INLINE NSArray * parseAttribute(NSString *str) NSRange range = [str rangeOfString:@"=" options:0]; NSString *key = [str substringToIndex:range.location]; + key = [key stringByReplacingOccurrencesOfString:@" " withString:@":"]; + NSString *value = [str substringFromIndex:range.location + 2]; value = [value substringToIndex:value.length - 1]; diff --git a/Tests/HTMLKitTests/HTMLKitParserIssuesTests.m b/Tests/HTMLKitTests/HTMLKitParserIssuesTests.m new file mode 100644 index 0000000..37d6eed --- /dev/null +++ b/Tests/HTMLKitTests/HTMLKitParserIssuesTests.m @@ -0,0 +1,43 @@ +// +// HTMLKitParserTests.m +// HTMLKit +// +// Created by Iska on 16.07.18. +// Copyright © 2018 BrainCookie. All rights reserved. +// + +#import +#import "HTMLDOM.h" + +@interface HTMLKitParserIssuesTests : XCTestCase + +@end + +@implementation HTMLKitParserIssuesTests + +#pragma mark - Bug Fixes + +- (void)testBugFix_Issue_30 { + NSString *html = + @"" + " " + " " + " " + ""; + + HTMLDocument* document = [HTMLDocument documentWithString:html]; + HTMLElement *svg = [document querySelector:@"#draw_area"]; + + XCTAssertNil(svg.attributes[@"xlink"]); + XCTAssertEqualObjects(svg.attributes[@"xmlns"], @"http://www.w3.org/2000/svg"); + XCTAssertEqualObjects(svg.attributes[@"xmlns:xlink"], @"http://www.w3.org/1999/xlink"); + + HTMLElement *image = [document querySelector:@"#overlay_img"]; + + XCTAssertNil(image.attributes[@"xlink"]); + XCTAssertNil(image.attributes[@"href"]); + XCTAssertEqualObjects(image.attributes[@"xlink:href"], @"foo.png"); + XCTAssertEqualObjects(image.outerHTML, @""); +} + +@end diff --git a/Tests/HTMLKitTests/HTMLNodeIteratorTests.m b/Tests/HTMLKitTests/HTMLNodeIteratorTests.m index 71f1b70..fe51ef4 100644 --- a/Tests/HTMLKitTests/HTMLNodeIteratorTests.m +++ b/Tests/HTMLKitTests/HTMLNodeIteratorTests.m @@ -608,4 +608,19 @@ static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node) XCTAssertTrue([element.elementId isEqualToString:divId]); } +- (void)testBugFix_Issue_28 { + HTMLDocument *document = self.document; + HTMLNodeIterator *iterator = document.body.nodeIterator; + + [iterator nextNode]; // Reference node: + + HTMLElement *span = (HTMLElement*)iterator.nextNode; // + NSString *spanTag = @"span"; + XCTAssertTrue([span.tagName isEqualToString:spanTag]); + + HTMLElement *paragraph = span.nextSiblingElement; //

+ NSString *paragraphTag = @"p"; + XCTAssertTrue([paragraph.tagName isEqualToString:paragraphTag]); +} + @end