Merge branch 'release/0.2.0'

This commit is contained in:
iska
2015-06-06 20:12:42 +02:00
33 changed files with 3143 additions and 397 deletions
+113 -43
View File
@@ -49,14 +49,11 @@
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 */; };
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 */; };
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 */; };
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 */; };
@@ -69,6 +66,20 @@
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 */; };
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 */; };
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 */; };
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 */; };
@@ -80,6 +91,8 @@
624B9FB31AE0313300646C4C /* HTMLKitStringCategoryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B9FB11AE0313300646C4C /* HTMLKitStringCategoryTests.m */; };
624B9FB51AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B9FB41AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m */; };
624B9FB61AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B9FB41AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m */; };
624FC37A1AE591D80015DDF9 /* HTMLKitNodesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624FC3791AE591D80015DDF9 /* HTMLKitNodesTests.m */; };
624FC37B1AE591D80015DDF9 /* HTMLKitNodesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624FC3791AE591D80015DDF9 /* HTMLKitNodesTests.m */; };
625A14B019C7829400AD0C32 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 625A14AF19C7829400AD0C32 /* Cocoa.framework */; };
625A14BA19C7829400AD0C32 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 625A14B819C7829400AD0C32 /* InfoPlist.strings */; };
625A14BE19C7829400AD0C32 /* HTMLKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 625A14BD19C7829400AD0C32 /* HTMLKit.m */; };
@@ -116,6 +129,16 @@
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 /* 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 */; };
62D89DB41AE7081600B6243D /* HTMLElementTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 6223211D1A969B9300BACED5 /* HTMLElementTypes.h */; };
62D89DB51AE7081600B6243D /* HTMLElementAdjustment.h in Headers */ = {isa = PBXBuildFile; fileRef = 6234C3361AB3BF710046F527 /* HTMLElementAdjustment.h */; };
62D89DB61AE7081600B6243D /* HTMLParserInsertionModes.h in Headers */ = {isa = PBXBuildFile; fileRef = 6279F87119E17DC700F12EE5 /* HTMLParserInsertionModes.h */; };
62D89DB71AE7081600B6243D /* HTMLQuirksMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 623719431AA12EE8002E03C8 /* HTMLQuirksMode.h */; };
62EC7AE61AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */; };
62EC7AE71AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */; };
62F31FDD19E9DCCF007F0657 /* HTMLTokenizerEntities.h in Headers */ = {isa = PBXBuildFile; fileRef = 62F31FDB19E9DCCF007F0657 /* HTMLTokenizerEntities.h */; };
62F31FDE19E9DCCF007F0657 /* HTMLTokenizerEntities.m in Sources */ = {isa = PBXBuildFile; fileRef = 62F31FDC19E9DCCF007F0657 /* HTMLTokenizerEntities.m */; };
62F31FDF19E9DCCF007F0657 /* HTMLTokenizerEntities.m in Sources */ = {isa = PBXBuildFile; fileRef = 62F31FDC19E9DCCF007F0657 /* HTMLTokenizerEntities.m */; };
@@ -173,7 +196,7 @@
6235CE9F1AA5170A0026937B /* HTMLMarker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLMarker.m; sourceTree = "<group>"; };
62362A3A1A9FA70400301989 /* HTMLText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLText.h; sourceTree = "<group>"; };
62362A3B1A9FA70400301989 /* HTMLText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLText.m; sourceTree = "<group>"; };
62362A3F1A9FDE8A00301989 /* HTMLNodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLNodes.h; sourceTree = "<group>"; };
62362A3F1A9FDE8A00301989 /* HTMLDOM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLDOM.h; sourceTree = "<group>"; };
62363C3B1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLListOfActiveFormattingElements.h; sourceTree = "<group>"; };
62363C3C1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLListOfActiveFormattingElements.m; sourceTree = "<group>"; };
6236738D1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTokenizerPerformance.m; sourceTree = "<group>"; };
@@ -186,11 +209,9 @@
623857951A9E8606003A45D9 /* HTMLDocumentType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLDocumentType.m; sourceTree = "<group>"; };
623857991A9E8934003A45D9 /* HTMLComment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLComment.h; sourceTree = "<group>"; };
6238579A1A9E8934003A45D9 /* HTMLComment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLComment.m; sourceTree = "<group>"; };
6238C9831AB8D6330006512E /* HTMLKitExceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLKitExceptions.h; sourceTree = "<group>"; };
6238C9841AB8D6330006512E /* HTMLKitExceptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitExceptions.m; sourceTree = "<group>"; };
623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeTreeEnumerator.h; sourceTree = "<group>"; };
623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeTreeEnumerator.m; sourceTree = "<group>"; };
623916C61AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitNodeTreeEnumratorTests.m; sourceTree = "<group>"; };
6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLKitDOMExceptions.h; sourceTree = "<group>"; };
6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitDOMExceptions.m; sourceTree = "<group>"; };
623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitNodeIteratorTests.m; sourceTree = "<group>"; };
623975591AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTreeConstructionTests.m; sourceTree = "<group>"; };
6239755C1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTML5LibTreeConstructionTest.h; sourceTree = "<group>"; };
6239755D1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTML5LibTreeConstructionTest.m; sourceTree = "<group>"; };
@@ -200,12 +221,22 @@
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>"; };
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>"; };
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>"; };
624AC8FE19FBF4F700BD3C4A /* HTMLTokens.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLTokens.h; sourceTree = "<group>"; };
624AC90019FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTokenizerTests.m; sourceTree = "<group>"; };
624AC90419FBFE8A00BD3C4A /* html5lib-tests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "html5lib-tests"; sourceTree = "<group>"; };
624AC90D19FC702E00BD3C4A /* HTML Standard.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "HTML Standard.html"; sourceTree = "<group>"; };
624B9FB11AE0313300646C4C /* HTMLKitStringCategoryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitStringCategoryTests.m; sourceTree = "<group>"; };
624B9FB41AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitOrderedDictionaryTests.m; sourceTree = "<group>"; };
624FC3791AE591D80015DDF9 /* HTMLKitNodesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitNodesTests.m; sourceTree = "<group>"; };
625A14AC19C7829400AD0C32 /* HTMLKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = HTMLKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
625A14AF19C7829400AD0C32 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
625A14B219C7829400AD0C32 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@@ -242,6 +273,7 @@
62D8345719FB1AC4009205A9 /* HTML5LibTokenizerTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTML5LibTokenizerTest.h; sourceTree = "<group>"; };
62D8345819FB1AC4009205A9 /* HTML5LibTokenizerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTML5LibTokenizerTest.m; sourceTree = "<group>"; };
62E7CAAE19CDFFB500465A83 /* HTMLTokenizerCharacters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLTokenizerCharacters.h; sourceTree = "<group>"; };
62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitMutationAlgorithmsTests.m; sourceTree = "<group>"; };
62F31FDB19E9DCCF007F0657 /* HTMLTokenizerEntities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLTokenizerEntities.h; sourceTree = "<group>"; };
62F31FDC19E9DCCF007F0657 /* HTMLTokenizerEntities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLTokenizerEntities.m; sourceTree = "<group>"; };
62F873E919E088C90062683C /* HTMLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLParser.h; sourceTree = "<group>"; };
@@ -299,31 +331,40 @@
name = Tokenizer;
sourceTree = "<group>";
};
623719441AA1472B002E03C8 /* Nodes */ = {
623719441AA1472B002E03C8 /* DOM */ = {
isa = PBXGroup;
children = (
623719431AA12EE8002E03C8 /* HTMLQuirksMode.h */,
62362A3F1A9FDE8A00301989 /* HTMLNodes.h */,
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 */,
6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */,
6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */,
624717BA1B22009200B38302 /* HTMLTreeWalker.h */,
624717BB1B22009200B38302 /* HTMLTreeWalker.m */,
624717161B22333200C11912 /* HTMLNodeTraversal.h */,
624717171B22333200C11912 /* HTMLNodeTraversal.m */,
6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */,
624717B71B21FE5400B38302 /* HTMLNodeFilter.m */,
6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */,
6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */,
628B7CE61A080E1000602C87 /* HTMLNamespaces.h */,
623719431AA12EE8002E03C8 /* HTMLQuirksMode.h */,
);
name = Nodes;
name = DOM;
sourceTree = "<group>";
};
623975581AC362A5007E26F1 /* Tree Construction */ = {
@@ -337,13 +378,15 @@
name = "Tree Construction";
sourceTree = "<group>";
};
624B9FB71AE072CB00646C4C /* Nodes */ = {
624B9FB71AE072CB00646C4C /* DOM */ = {
isa = PBXGroup;
children = (
623916C61AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m */,
624B9FB41AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m */,
623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */,
6247171B1B2240B800C11912 /* HTMLTreeWalkerTests.m */,
624FC3791AE591D80015DDF9 /* HTMLKitNodesTests.m */,
62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */,
);
name = Nodes;
name = DOM;
sourceTree = "<group>";
};
624B9FB81AE072D500646C4C /* Categories */ = {
@@ -354,6 +397,14 @@
name = Categories;
sourceTree = "<group>";
};
624E1A2D1B1D1C8A00E66AAC /* Structures */ = {
isa = PBXGroup;
children = (
624B9FB41AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m */,
);
name = Structures;
sourceTree = "<group>";
};
625A14A219C7829400AD0C32 = {
isa = PBXGroup;
children = (
@@ -401,11 +452,9 @@
children = (
625A14BC19C7829400AD0C32 /* HTMLKit.h */,
625A14BD19C7829400AD0C32 /* HTMLKit.m */,
6238C9831AB8D6330006512E /* HTMLKitExceptions.h */,
6238C9841AB8D6330006512E /* HTMLKitExceptions.m */,
62AE593219F97CCA0043F069 /* Tokenizing */,
628E16EC1ADAE71700B15A06 /* Parsing */,
623719441AA1472B002E03C8 /* Nodes */,
623719441AA1472B002E03C8 /* DOM */,
628E16ED1ADAE73700B15A06 /* Categories */,
628E16EE1ADAE75300B15A06 /* Structures */,
625A14B619C7829400AD0C32 /* Supporting Files */,
@@ -429,8 +478,9 @@
children = (
6236738C1AC0CD2400FF89B3 /* Tokenizer */,
623975581AC362A5007E26F1 /* Tree Construction */,
624B9FB71AE072CB00646C4C /* Nodes */,
624B9FB71AE072CB00646C4C /* DOM */,
624B9FB81AE072D500646C4C /* Categories */,
624E1A2D1B1D1C8A00E66AAC /* Structures */,
625A14CB19C7829400AD0C32 /* Supporting Files */,
);
name = Tests;
@@ -457,7 +507,6 @@
6234BEED1AABBF1400DEB15F /* HTMLStackOfOpenElements.m */,
62363C3B1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h */,
62363C3C1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m */,
628B7CE61A080E1000602C87 /* HTMLNamespaces.h */,
6223211D1A969B9300BACED5 /* HTMLElementTypes.h */,
6234C3361AB3BF710046F527 /* HTMLElementAdjustment.h */,
6279F87119E17DC700F12EE5 /* HTMLParserInsertionModes.h */,
@@ -522,24 +571,34 @@
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 */,
62D89DB31AE7081600B6243D /* HTMLNamespaces.h in Headers */,
62D89DB41AE7081600B6243D /* HTMLElementTypes.h in Headers */,
62D89DB51AE7081600B6243D /* HTMLElementAdjustment.h in Headers */,
62D89DB61AE7081600B6243D /* HTMLParserInsertionModes.h in Headers */,
62D89DB71AE7081600B6243D /* HTMLQuirksMode.h in Headers */,
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 */,
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 */,
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 */,
6247A9431B152F4F00CCF25C /* HTMLNodeIterator.h in Headers */,
625A150419C783EB00AD0C32 /* HTMLKit.h in Headers */,
625A150819C78ABA00AD0C32 /* HTMLInputStreamReader.h in Headers */,
6238579B1A9E8934003A45D9 /* HTMLComment.h in Headers */,
@@ -548,6 +607,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 */,
);
@@ -701,24 +761,27 @@
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 */,
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 */,
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 */,
6247171A1B22333200C11912 /* HTMLNodeTraversal.m in Sources */,
62F873ED19E088C90062683C /* HTMLParser.m in Sources */,
623803A11AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */,
6279F87619E1808D00F12EE5 /* HTMLElement.m in Sources */,
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 */,
@@ -735,13 +798,16 @@
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 */,
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 */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -751,24 +817,27 @@
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 */,
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 */,
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 */,
624717191B22333200C11912 /* HTMLNodeTraversal.m in Sources */,
62F873EC19E088C90062683C /* HTMLParser.m in Sources */,
623803A01AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */,
6279F87519E1808D00F12EE5 /* HTMLElement.m in Sources */,
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 */,
@@ -785,13 +854,16 @@
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 */,
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 */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1008,7 +1080,6 @@
buildSettings = {
BUNDLE_LOADER = "";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
@@ -1032,7 +1103,6 @@
buildSettings = {
BUNDLE_LOADER = "";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
+5
View File
@@ -10,6 +10,11 @@
@implementation HTMLComment
- (instancetype)init
{
return [self initWithData:nil];
}
- (instancetype)initWithData:(NSString *)data
{
self = [super initWithName:@"#comment" type:HTMLNodeComment];
+4 -1
View File
@@ -9,8 +9,11 @@
#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"
#import "HTMLNodeIterator.h"
#import "HTMLTreeWalker.h"
#import "HTMLNodeFilter.h"
+10
View File
@@ -27,6 +27,16 @@ typedef NS_ENUM(short, HTMLDocumentReadyState)
@property (nonatomic, assign, readonly) HTMLDocumentReadyState readyState;
@property (nonatomic, strong) HTMLElement *rootElement;
@property (nonatomic, strong) HTMLElement *documentElement;
@property (nonatomic, strong) HTMLElement *head;
@property (nonatomic, strong) HTMLElement *body;
+ (instancetype)documentWithString:(NSString *)string;
- (HTMLNode *)adoptNode:(HTMLNode *)node;
- (HTMLDocument *)associatedInertTemplateDocument;
+103 -2
View File
@@ -7,16 +7,25 @@
//
#import "HTMLDocument.h"
#import "HTMLKitExceptions.h"
#import "HTMLParser.h"
#import "HTMLNodeIterator.h"
#import "HTMLKitDOMExceptions.h"
@interface HTMLNode (Private)
@property (nonatomic, weak) HTMLDocument *ownerDocument;
@property (nonatomic, weak) HTMLNode *parentNode;
@end
@interface HTMLNodeIterator (Private)
- (void)runRemovingStepsForNode:(HTMLNode *)oldNode
withOldParent:(HTMLNode *)oldParent
andOldPreviousSibling:(HTMLNode *)oldPreviousSibling;
@end
@interface HTMLDocument ()
{
HTMLDocument *_inertTemplateDocument;
NSMutableArray *_nodeIterators;
}
@property (nonatomic, assign) HTMLDocumentReadyState readyState;
@end
@@ -25,11 +34,18 @@
#pragma mark - Init
+ (instancetype)documentWithString:(NSString *)string
{
HTMLParser *parser = [[HTMLParser alloc] initWithString:string];
return [parser parseDocument];
}
- (instancetype)init
{
self = [super initWithName:@"#document" type:HTMLNodeDocument];
if (self) {
_readyState = HTMLDocumentLoading;
_nodeIterators = [NSMutableArray new];
}
return self;
}
@@ -57,6 +73,91 @@
}
}
#pragma mark -
- (HTMLElement *)rootElement
{
for (HTMLNode *node = self.firstChild; node; node = node.nextSibling) {
if (node.nodeType == HTMLNodeElement) {
return node.asElement;
}
}
return nil;
}
- (void)setRootElement:(HTMLElement *)rootElement
{
[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]) {
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 nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]) {
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
{
[_nodeIterators addObject:iterator];
}
- (void)detachNodeIterator:(HTMLNodeIterator *)iterator
{
[_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
@@ -65,7 +166,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)];
}
+6 -1
View File
@@ -15,6 +15,11 @@
@implementation HTMLDocumentFragment
- (instancetype)init
{
return [self initWithDocument:nil];
}
- (instancetype)initWithDocument:(HTMLDocument *)document
{
self = [super initWithName:@"#document-fragment" type:HTMLNodeDocumentFragment];
@@ -28,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]];
}
}
+5
View File
@@ -22,6 +22,11 @@ NS_INLINE BOOL nilOrEqual(id first, id second) {
@implementation HTMLDocumentType
- (instancetype)init
{
return [self initWithName:@"html" publicIdentifier:nil systemIdentifier:nil];
}
- (instancetype)initWithName:(NSString *)name
publicIdentifier:(NSString *)publicIdentifier
systemIdentifier:(NSString *)systemIdentifier
+1 -1
View File
@@ -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;
+15 -6
View File
@@ -7,6 +7,7 @@
//
#import "HTMLElement.h"
#import "HTMLParser.h"
#import "HTMLDocument.h"
#import "HTMLText.h"
@@ -35,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) {
@@ -87,8 +88,8 @@
- (NSString *)textContent
{
NSMutableString *content = [NSMutableString string];
for (HTMLNode *node in self.treeEnumerator) {
if (node.type == HTMLNodeText) {
for (HTMLNode *node in self.nodeIterator) {
if (node.nodeType == HTMLNodeText) {
[content appendString:[(HTMLText *)node data]];
}
}
@@ -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
@@ -137,8 +146,8 @@
return result;
}
if ([self.tagName isEqualToAny:@"pre", @"textarea", @"listing", nil] && self.firstChiledNode.type == 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"];
}
@@ -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";
+1 -1
View File
@@ -52,7 +52,7 @@
}
if (node.htmlNamespace == element.htmlNamespace &&
[node.tagName isEqualToString:element.tagName] &&
[node.attributes isEqualTo:element.attributes]) {
[node.attributes isEqual:element.attributes]) {
existing++;
}
if (existing == 3) {
+40 -12
View File
@@ -7,6 +7,7 @@
//
#import <Foundation/Foundation.h>
#import "HTMLNodeIterator.h"
typedef NS_ENUM(short, HTMLNodeType)
{
@@ -24,28 +25,37 @@ 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;
@interface HTMLNode : NSObject <NSCopying>
@property (nonatomic, assign, readonly) HTMLNodeType type;
@property (nonatomic, assign, readonly) HTMLNodeType nodeType;
@property (nonatomic, strong, readonly) NSString *name;
@property (nonatomic, weak, readonly) HTMLDocument *ownerDocument;
@property (nonatomic, strong, readonly) NSString *baseURI;
@property (nonatomic, weak, readonly) HTMLNode *parentNode;
@property (nonatomic, weak, readonly) HTMLElement *parentElement;
@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;
@@ -53,8 +63,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;
@@ -65,16 +83,22 @@ typedef NS_ENUM(short, HTMLNodeType)
- (NSUInteger)indexOfChildNode:(HTMLNode *)node;
- (HTMLNode *)insertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child;
- (HTMLNode *)prependNode:(HTMLNode *)node;
- (void)prependNodes:(NSArray *)nodes;
- (HTMLNode *)appendNode:(HTMLNode *)node;
- (void)appendNodes:(NSArray *)nodes;
- (HTMLNode *)insertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child;
- (HTMLNode *)replaceChildNode:(HTMLNode *)node withNode:(HTMLNode *)replacement;
- (void)replaceAllChildNodesWithNode:(HTMLNode *)node;
- (void)removeFromParentNode;
- (HTMLNode *)removeChildNode:(HTMLNode *)node;
- (HTMLNode *)removeChildNodeAtIndex:(NSUInteger)index;
@@ -83,15 +107,19 @@ 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;
- (NSEnumerator *)treeEnumerator;
- (void)enumerateChildElementsUsingBlock:(void (^)(HTMLElement *element, NSUInteger idx, BOOL *stop))block;
- (NSEnumerator *)reverseTreeEnumerator;
- (NSString *)outerHTML;
- (NSString *)innerHTML;
- (HTMLNodeIterator *)nodeIterator;
- (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions
filter:(id<HTMLNodeFilter>)filter;
- (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions
filterBlock:(HTMLNodeFilterValue (^)(HTMLNode *node))filter;
- (NSString *)treeDescription;
+238 -94
View File
@@ -12,8 +12,13 @@
#import "HTMLElement.h"
#import "HTMLText.h"
#import "HTMLComment.h"
#import "HTMLKitExceptions.h"
#import "HTMLNodeTreeEnumerator.h"
#import "HTMLKitDOMExceptions.h"
@interface HTMLDocument (Private)
- (void)runRemovingStepsForNode:(HTMLNode *)oldNode
withOldParent:(HTMLNode *)oldParent
andOldPreviousSibling:(HTMLNode *)oldPreviousSibling;
@end
@interface HTMLNode ()
{
@@ -32,7 +37,7 @@
self = [super init];
if (self) {
_name = name;
_type = type;
_nodeType = type;
_childNodes = [NSMutableOrderedSet new];
}
return self;
@@ -42,7 +47,7 @@
- (HTMLDocument *)ownerDocument
{
if (_type == HTMLNodeDocument) {
if (_nodeType == HTMLNodeDocument) {
return (HTMLDocument *)self;
} else {
return _ownerDocument;
@@ -55,12 +60,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;
@@ -68,15 +67,15 @@
- (HTMLElement *)parentElement
{
return _parentNode.type == HTMLNodeElement ? (HTMLElement *)_parentNode : nil;
return _parentNode.nodeType == HTMLNodeElement ? (HTMLElement *)_parentNode : nil;
}
- (HTMLNode *)firstChiledNode
- (HTMLNode *)firstChild
{
return self.childNodes.firstObject;
}
- (HTMLNode *)lastChildNode
- (HTMLNode *)lastChild
{
return self.childNodes.lastObject;
}
@@ -104,6 +103,13 @@
return nil;
}
#pragma mark - Cast
- (HTMLElement *)asElement
{
return (HTMLElement *)self;
}
#pragma mark - Child Nodes
- (BOOL)hasChildNodes
@@ -114,7 +120,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;
}
@@ -139,35 +145,65 @@
return [self.childNodes indexOfObject:node];
}
- (HTMLNode *)insertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child
- (HTMLNode *)prependNode:(HTMLNode *)node
{
node = [self preInsertNode:node beforeChildNode:child];
node.parentNode = self;
return node;
return [self insertNode:node beforeChildNode:self.firstChild];
}
- (void)prependNodes:(NSArray *)nodes
{
for (id node in nodes.reverseObjectEnumerator) {
[self insertNode:node beforeChildNode:self.firstChild];
}
}
- (HTMLNode *)appendNode:(HTMLNode *)node
{
node = [self preInsertNode:node beforeChildNode:nil];
node.parentNode = self;
return node;
return [self insertNode:node beforeChildNode:nil];
}
- (void)appendNodes:(NSArray *)nodes
{
for (id node in nodes) {
[self appendNode:node];
[self insertNode:node beforeChildNode:nil];
}
}
- (HTMLNode *)insertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child
{
#ifndef HTMLKIT_NO_DOM_CHECKS
[self ensurePreInsertionValidityOfNode:node beforeChildNode:child];
#endif
[self.ownerDocument adoptNode:node];
NSArray *nodes = node.nodeType == HTMLNodeDocumentFragment ? [NSArray arrayWithArray: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];
}
if (node.nodeType == HTMLNodeDocumentFragment) {
[node removeAllChildNodes];
}
[nodes makeObjectsPerformSelector:@selector(setParentNode:) withObject:self];
return node;
}
- (HTMLNode *)replaceChildNode:(HTMLNode *)child withNode:(HTMLNode *)node
{
#ifndef HTMLKIT_NO_DOM_CHECKS
[self ensureReplacementValidityOfChildNode:child withNode:node];
#endif
[self.ownerDocument adoptNode:node];
NSUInteger index = [self indexOfChildNode:child];
node.parentNode = self;
[(NSMutableOrderedSet *)self.childNodes replaceObjectAtIndex:index withObject:node];
[self insertNode:node beforeChildNode:child];
[child removeFromParentNode];
return child;
}
@@ -181,6 +217,11 @@
}
}
- (void)removeFromParentNode
{
[self.parentNode removeChildNode:self];
}
- (HTMLNode *)removeChildNode:(HTMLNode *)child
{
if (child.parentNode != self) {
@@ -189,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;
}
@@ -205,14 +254,95 @@
for (HTMLNode *child in self.childNodes.array) {
[node appendNode:child];
}
[self removeAllChildNodes];
[(NSMutableOrderedSet *)self.childNodes removeAllObjects];
}
- (void)removeAllChildNodes
{
[self.childNodes.array makeObjectsPerformSelector:@selector(setParentNode:) withObject:nil];
[(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
@@ -226,40 +356,48 @@
}];
}
- (NSEnumerator *)treeEnumerator
- (void)enumerateChildElementsUsingBlock:(void (^)(HTMLElement *element, NSUInteger idx, BOOL *stop))block
{
return [[HTMLNodeTreeEnumerator alloc] initWithNode:self reverse:NO];
}
- (NSEnumerator *)reverseTreeEnumerator
{
return [[HTMLNodeTreeEnumerator alloc] initWithNode:self reverse:YES];
}
#pragma mark - Mutation Algorithms
- (HTMLNode *)preInsertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child
{
[self ensurePreInsertionValidityOfNode:node beforeChildNode:child];
[self.ownerDocument adoptNode:node];
NSUInteger index = [self indexOfChildNode:child];
if (index != NSNotFound) {
[(NSMutableOrderedSet *)self.childNodes insertObject:node atIndex:index];
} else {
[(NSMutableOrderedSet *)self.childNodes addObject:node];
if (block == nil) {
return;
}
return node;
[self.childNodes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[HTMLElement class]]) {
block([obj asElement], idx, stop);
}
}];
}
NS_INLINE void CheckParentValid(HTMLNode *node, NSString *cmd)
- (HTMLNodeIterator *)nodeIterator
{
if (node.type != HTMLNodeDocument &&
node.type != HTMLNodeDocumentFragment &&
node.type != HTMLNodeElement) {
return [self nodeIteratorWithShowOptions:HTMLNodeFilterShowAll filter:nil];
}
- (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions
filter:(id<HTMLNodeFilter>)filter
{
return [[HTMLNodeIterator alloc] initWithNode:self showOptions:showOptions filter:filter];
}
- (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions
filterBlock:(HTMLNodeFilterValue (^)(HTMLNode *node))filter
{
return [HTMLNodeIterator iteratorWithNode:self showOptions:showOptions filter:filter];
}
#ifndef HTMLKIT_NO_DOM_CHECKS
#pragma mark - Validity Checks
NS_INLINE void CheckParentValid(HTMLNode *parent, NSString *cmd)
{
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, node.name];
cmd, parent.name];
}
}
@@ -275,11 +413,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];
@@ -288,13 +426,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];
@@ -313,28 +451,28 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin
void (^ hierarchyError)() = ^{
[NSException raise:HTMLKitHierarchyRequestError
format:@"%@: Hierarchy Request Error. The operation would yield an incorrect node tree.",
NSStringFromSelector(_cmd)];
format:@"%@: Hierarchy Request Error, inserting (%@) into (%@). The operation would yield an incorrect node tree.",
NSStringFromSelector(_cmd), self, node];
};
if (self.type == HTMLNodeDocument) {
switch (node.type) {
if (self.nodeType == HTMLNodeDocument) {
switch (node.nodeType) {
case HTMLNodeDocumentFragment:
if (self.childNodesCount > 1 ||
[self hasChildNodeOfType:HTMLNodeText]) {
if (node.childNodesCount > 1 ||
[node hasChildNodeOfType:HTMLNodeText]) {
hierarchyError();
} else if (self.childNodesCount == 1) {
if (self.hasChildNodes ||
child.type == HTMLNodeDocumentType ||
child.nextSibling.type == HTMLNodeDocumentType) {
} else if (node.childNodesCount == 1) {
if ([self hasChildNodeOfType:HTMLNodeElement] ||
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;
@@ -367,43 +505,42 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin
NSStringFromSelector(_cmd)];
};
if (self.type == HTMLNodeDocument) {
switch (node.type) {
void (^ checkParentHasAnotherChildOfType)(HTMLNodeType) = ^ void (HTMLNodeType type) {
[self enumerateChildNodesUsingBlock:^(HTMLNode *node, NSUInteger idx, BOOL *stop) {
if (node.nodeType == type && node != child) {
*stop = YES;
hierarchyError();
}
}];
};
if (self.nodeType == HTMLNodeDocument) {
switch (node.nodeType) {
case HTMLNodeDocumentFragment:
if (self.childNodesCount > 1 ||
[self hasChildNodeOfType:HTMLNodeText]) {
if (node.childNodesCount > 1 ||
[node hasChildNodeOfType:HTMLNodeText]) {
hierarchyError();
} else if (self.childNodesCount == 1) {
if (self.firstChiledNode != node ||
child.nextSibling.type == HTMLNodeDocumentType) {
} else if (node.childNodesCount == 1) {
if (child.nextSibling.nodeType == HTMLNodeDocumentType) {
hierarchyError();
}
checkParentHasAnotherChildOfType(HTMLNodeElement);
}
break;
case HTMLNodeElement:
{
if (child.nextSibling.type == HTMLNodeDocumentType) {
if (child.nextSibling.nodeType == HTMLNodeDocumentType) {
hierarchyError();
}
[self enumerateChildNodesUsingBlock:^(HTMLNode *node, NSUInteger idx, BOOL *stop) {
if (node.type == HTMLNodeElement && node != child) {
*stop = YES;
hierarchyError();
}
}];
checkParentHasAnotherChildOfType(HTMLNodeElement);
break;
}
case HTMLNodeDocumentType:
{
if (child.previousSibling.type == HTMLNodeElement) {
if (child.previousSibling.nodeType == HTMLNodeElement) {
hierarchyError();
}
[self enumerateChildNodesUsingBlock:^(HTMLNode *node, NSUInteger idx, BOOL *stop) {
if (node.type == HTMLNodeDocument && node != child) {
*stop = YES;
hierarchyError();
}
}];
checkParentHasAnotherChildOfType(HTMLNodeDocumentType);
break;
}
default:
@@ -412,11 +549,13 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin
}
}
#endif
#pragma mark - NSCopying
- (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;
}
@@ -433,6 +572,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
+41
View File
@@ -0,0 +1,41 @@
//
// HTMLNodeFilter.h
// HTMLKit
//
// Created by Iska on 27/05/15.
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef NS_ENUM(unsigned short, HTMLNodeFilterValue)
{
HTMLNodeFilterAccept = 1,
HTMLNodeFilterReject = 2,
HTMLNodeFilterSkip = 3
};
typedef NS_OPTIONS(unsigned long, HTMLNodeFilterShowOptions)
{
HTMLNodeFilterShowAll = 0xFFFFFFFF,
HTMLNodeFilterShowElement = 0x1,
HTMLNodeFilterShowText = 0x4,
HTMLNodeFilterShowComment = 0x80,
HTMLNodeFilterShowDocument = 0x100,
HTMLNodeFilterShowDocumentType = 0x200,
HTMLNodeFilterShowDocumentFragment = 0x400
};
@class HTMLNode;
@protocol HTMLNodeFilter <NSObject>
- (HTMLNodeFilterValue)acceptNode:(HTMLNode *)node;
@end
@interface HTMLNodeFilterBlock : NSObject <HTMLNodeFilter>
+ (instancetype)filterWithBlock:(HTMLNodeFilterValue (^)(HTMLNode *node))block;
@end
+42
View File
@@ -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:(HTMLNodeFilterValue (^)(HTMLNode *))block
{
return [[self alloc] initWithBlock:block];
}
- (instancetype)initWithBlock:(HTMLNodeFilterValue (^)(HTMLNode *))block
{
self = [super init];
if (self) {
_block = [block copy];
}
return self;
}
- (HTMLNodeFilterValue)acceptNode:(HTMLNode *)node
{
if (!_block) {
return HTMLNodeFilterSkip;
}
return _block(node);
}
@end
+36
View File
@@ -0,0 +1,36 @@
//
// HTMLNodeIterator.h
// HTMLKit
//
// Created by Iska on 27/05/15.
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
#import <Foundation/Foundation.h>
#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<HTMLNodeFilter> filter;
+ (instancetype)iteratorWithNode:(HTMLNode *)node
showOptions:(HTMLNodeFilterShowOptions)showOptions
filter:(HTMLNodeFilterValue (^)(HTMLNode *node))filter;
- (instancetype)initWithNode:(HTMLNode *)node;
- (instancetype)initWithNode:(HTMLNode *)node
filter:(id<HTMLNodeFilter>)filter;
- (instancetype)initWithNode:(HTMLNode *)node
showOptions:(HTMLNodeFilterShowOptions)showOptions
filter:(id<HTMLNodeFilter>)filter;
- (HTMLNode *)nextNode;
- (HTMLNode *)previousNode;
@end
+166
View File
@@ -0,0 +1,166 @@
//
// HTMLNodeIterator.m
// HTMLKit
//
// Created by Iska on 27/05/15.
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
#import "HTMLNodeIterator.h"
#import "HTMLDocument.h"
#import "HTMLNode.h"
#import "HTMLNodeFilter.h"
#import "HTMLNodeTraversal.h"
typedef NS_ENUM(short, TraverseDirection)
{
TraverseDirectionNext,
TraverseDirectionPrevious
};
@interface HTMLDocument (Private)
- (void)attachNodeIterator:(HTMLNodeIterator *)iterator;
- (void)detachNodeIterator:(HTMLNodeIterator *)iterator;
@end
@interface HTMLNodeIterator ()
{
HTMLNode *_root;
}
@end
@implementation HTMLNodeIterator
#pragma mark - Lifecycle
+ (instancetype)iteratorWithNode:(HTMLNode *)node
showOptions:(HTMLNodeFilterShowOptions)showOptions
filter:(HTMLNodeFilterValue (^)(HTMLNode *))filter
{
return [[self alloc] initWithNode:node
showOptions:showOptions
filter:[HTMLNodeFilterBlock filterWithBlock:filter]];
}
- (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
{
self = [super init];
if (self) {
_root = node;
_filter = filter;
_whatToShow = showOptions;
_referenceNode = _root;
_pointerBeforeReferenceNode = YES;
[_root.ownerDocument attachNodeIterator:self];
}
return self;
}
- (void)dealloc
{
[_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.firstChild;
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.lastChild) {
node = node.lastChild;
}
return node;
};
_referenceNode = oldPreviousSibling != nil ? lastInclusiveDescendant(oldPreviousSibling) : oldParent;
}
#pragma mark - Traversal
- (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.filter, self.whatToShow, node) != HTMLNodeFilterAccept);
_referenceNode = node;
_pointerBeforeReferenceNode = beforeNode;
return node;
}
- (HTMLNode *)nextNode
{
return [self traverseInDirection:TraverseDirectionNext];
}
- (HTMLNode *)previousNode
{
return [self traverseInDirection:TraverseDirectionPrevious];
}
#pragma mark - NSEnumerator
- (id)nextObject
{
return self.nextNode;
}
@end
+17
View File
@@ -0,0 +1,17 @@
//
// 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 HTMLNode * FollowingNodeSkippingChildren(HTMLNode *node, HTMLNode *root);
extern HTMLNodeFilterValue FilterNode(id<HTMLNodeFilter> filter, HTMLNodeFilterShowOptions whatToShow, HTMLNode *node);
+76
View File
@@ -0,0 +1,76 @@
//
// 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.lastChild != nil) {
previous = previous.lastChild;
}
return previous;
}
if (node == root) {
return nil;
}
return node.parentNode;
}
HTMLNode * FollowingNode(HTMLNode *node, HTMLNode *root)
{
if (node.firstChild != nil) {
return node.firstChild;
}
do {
if (node == root) {
return nil;
}
if (node.nextSibling != nil) {
return node.nextSibling;
}
node = node.parentNode;
} while (node != nil);
return nil;
}
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;
}
HTMLNodeFilterValue FilterNode(id<HTMLNodeFilter> filter, HTMLNodeFilterShowOptions whatToShow, HTMLNode *node)
{
unsigned long nthBit = (1 << (node.nodeType - 1)) & whatToShow;
if (!nthBit) {
return HTMLNodeFilterSkip;
}
if (filter == nil) {
return HTMLNodeFilterAccept;
}
return [filter acceptNode:node];
}
-17
View File
@@ -1,17 +0,0 @@
//
// HTMLNodeTreeEnumerator.h
// HTMLKit
//
// Created by Iska on 28/03/15.
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
#import <Foundation/Foundation.h>
@class HTMLNode;
@interface HTMLNodeTreeEnumerator : NSEnumerator
- (instancetype)initWithNode:(HTMLNode *)node reverse:(BOOL)reverse;
@end
-54
View File
@@ -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
+8 -8
View File
@@ -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"
@@ -127,7 +127,7 @@
return nil;
}
if ([_contextElement isEqualTo:contextElement]) {
if ([_contextElement isEqual:contextElement]) {
return [_document childNodeAtIndex:0].childNodes.array;
}
@@ -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;
}
@@ -452,11 +452,11 @@
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) {
[(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];
+36
View File
@@ -0,0 +1,36 @@
//
// 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;
- (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;
- (HTMLNode *)previousSibling;
- (HTMLNode *)nextSibling;
- (HTMLNode *)previousNode;
- (HTMLNode *)nextNode;
@end
+236
View File
@@ -0,0 +1,236 @@
//
// 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
{
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
{
self = [super init];
if (self) {
_root = node;
_filter = filter;
_whatToShow = showOptions;
_currentNode = _root;
}
return self;
}
#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;
node = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.firstChild : node.lastChild;
while (node != nil) {
HTMLNodeFilterValue result = FilterNode(self.filter, self.whatToShow, node);
if (result == HTMLNodeFilterAccept) {
_currentNode = node;
return node;
}
if (result == HTMLNodeFilterSkip) {
HTMLNode *child = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.firstChild : node.lastChild;
if (child != nil) {
node = child;
continue;
}
}
while (node != nil) {
HTMLNode *sibling = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.nextSibling : node.previousSibling;
if (sibling != nil) {
node = sibling;
break;
}
HTMLNode *parent = node.parentNode;
if (parent == nil || parent == _root || parent == _currentNode) {
return nil;
}
node = parent;
}
}
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;
HTMLNodeFilterValue result = FilterNode(self.filter, self.whatToShow, node);
if (result == HTMLNodeFilterAccept) {
_currentNode = node;
return node;
}
sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.firstChild : node.lastChild;
if (result == HTMLNodeFilterReject || 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) == HTMLNodeFilterAccept) {
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;
HTMLNodeFilterValue result = FilterNode(self.filter, self.whatToShow, node);
while (result != HTMLNodeFilterReject && node.hasChildNodes) {
node = node.lastChild;
result = FilterNode(self.filter, self.whatToShow, node);
}
if (result == HTMLNodeFilterAccept) {
_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) == HTMLNodeFilterAccept) {
_currentNode = node;
return node;
}
}
return nil;
}
- (HTMLNode *)nextNode
{
HTMLNode *node = _currentNode;
HTMLNodeFilterValue result = YES;
while (YES) {
while (result != HTMLNodeFilterReject && node.hasChildNodes) {
node = node.firstChild;
result = FilterNode(self.filter, self.whatToShow, node);
if (result == HTMLNodeFilterAccept) {
_currentNode = node;
return node;
}
}
HTMLNode *nextSibling;
while ((nextSibling = FollowingNodeSkippingChildren(node, _root)) != nil) {
node = nextSibling;
result = FilterNode(self.filter, self.whatToShow, node);
if (result == HTMLNodeFilterAccept) {
_currentNode = node;
return node;
}
break;
}
}
return nil;
}
@end
+2 -3
View File
@@ -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";
@@ -111,7 +110,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 +244,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;
}
@@ -0,0 +1,376 @@
//
// HTMLKitMutationAlgorithmsTests.m
// HTMLKit
//
// Created by Iska on 27/04/15.
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "HTMLDOM.h"
#import "NSString+HTMLKit.h"
extern uint64_t dispatch_benchmark(size_t count, void (^block)(void));
@interface HTMLKitMutationAlgorithmsTests : XCTestCase
@end
@implementation HTMLKitMutationAlgorithmsTests
- (void)testValidParentNodeWhenAppending
{
HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];
id parent = [HTMLDocument new];
XCTAssertNoThrow([parent appendNode:element]);
parent = [HTMLDocumentFragment new];
XCTAssertNoThrow([parent appendNode:element]);
parent = [HTMLElement new];
XCTAssertNoThrow([parent appendNode:element]);
parent = [HTMLTemplate new];
XCTAssertNoThrow([parent appendNode:element]);
parent = [HTMLDocumentType new];
XCTAssertThrows([parent appendNode:element]);
parent = [HTMLComment new];
XCTAssertThrows([parent appendNode:element]);
parent = [HTMLText new];
XCTAssertThrows([parent appendNode:element]);
}
- (void)testValidParentNodeWhenInserting
{
HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];
id parent = [HTMLDocument new];
XCTAssertNoThrow([parent insertNode:element beforeChildNode:nil]);
parent = [HTMLDocumentFragment new];
XCTAssertNoThrow([parent insertNode:element beforeChildNode:nil]);
parent = [HTMLElement new];
XCTAssertNoThrow([parent insertNode:element beforeChildNode:nil]);
parent = [HTMLTemplate new];
XCTAssertNoThrow([parent insertNode:element beforeChildNode:nil]);
parent = [HTMLDocumentType new];
XCTAssertThrows([parent insertNode:element beforeChildNode:nil]);
parent = [HTMLComment new];
XCTAssertThrows([parent insertNode:element beforeChildNode:nil]);
parent = [HTMLText new];
XCTAssertThrows([parent insertNode:element beforeChildNode:nil]);
}
- (void)testValidChildNodeWhenInserting
{
HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"];
HTMLElement *p = [[HTMLElement alloc] initWithTagName:@"p"];
[div appendNode:p];
HTMLElement *table = [[HTMLElement alloc] initWithTagName:@"table"];
XCTAssertNoThrow([div insertNode:table beforeChildNode:p]);
[div removeChildNode:p];
HTMLElement *section = [[HTMLElement alloc] initWithTagName:@"section"];
XCTAssertThrows([div insertNode:section beforeChildNode:p]);
}
- (void)testValidChildNodeWhenReplacing
{
HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"];
HTMLElement *p = [[HTMLElement alloc] initWithTagName:@"p"];
[div appendNode:p];
HTMLElement *table = [[HTMLElement alloc] initWithTagName:@"table"];
XCTAssertNoThrow([div replaceChildNode:p withNode:table]);
XCTAssertThrows([div replaceChildNode:p withNode:[HTMLComment new]]);
}
- (void)testValidChildNodeWhenRemoving
{
HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"];
HTMLElement *p = [[HTMLElement alloc] initWithTagName:@"p"];
[div appendNode:p];
XCTAssertNoThrow([div removeChildNode:p]);
XCTAssertThrows([div removeChildNode:p]);
}
- (void)testValidInsertedNode
{
HTMLDocument *document = [HTMLDocument new];
XCTAssertNoThrow([document appendNode:[HTMLDocumentFragment new]]);
XCTAssertNoThrow([document appendNode:[HTMLDocumentType new]]);
XCTAssertNoThrow([document appendNode:[HTMLElement new]]);
HTMLElement *element = [HTMLElement new];
XCTAssertNoThrow([element appendNode:[HTMLTemplate new]]);
XCTAssertNoThrow([element appendNode:[HTMLComment new]]);
XCTAssertNoThrow([element appendNode:[HTMLText new]]);
}
- (void)testValidParentForDoctype
{
HTMLDocumentType *doctype = [HTMLDocumentType new];
XCTAssertNoThrow([[HTMLDocument new] appendNode:doctype]);
XCTAssertThrows([[HTMLDocumentFragment new] appendNode:doctype]);
XCTAssertThrows([[HTMLDocumentType new] appendNode:doctype]);
XCTAssertThrows([[HTMLElement new] appendNode:doctype]);
XCTAssertThrows([[HTMLTemplate new] appendNode:doctype]);
XCTAssertThrows([[HTMLComment new] appendNode:doctype]);
XCTAssertThrows([[HTMLText new] appendNode:doctype]);
}
- (void)testValidParentForText
{
HTMLText *text = [HTMLText new];
XCTAssertThrows([[HTMLDocument new] appendNode:text]);
XCTAssertThrows([[HTMLDocumentType new] appendNode:text]);
XCTAssertThrows([[HTMLComment new] appendNode:text]);
XCTAssertThrows([[HTMLText new] appendNode:text]);
XCTAssertNoThrow([[HTMLDocumentFragment new] appendNode:text]);
XCTAssertNoThrow([[HTMLElement new] appendNode:text]);
XCTAssertNoThrow([[HTMLTemplate new] appendNode:text]);
}
- (void)testValidDocumentFragmentInsertionIntoDocument
{
HTMLDocument *document = [HTMLDocument new];
HTMLDocumentFragment *fragment = [[HTMLDocumentFragment alloc] initWithDocument:document];
void (^ reset)() = ^ {
[fragment removeAllChildNodes];
[document removeAllChildNodes];
};
/**
* Fragment has a Text node child
*/
[fragment appendNode:[HTMLText new]];
XCTAssertThrows([document appendNode:fragment]);
/**
* Fragment has more than one Element child
*/
reset();
[fragment appendNode:[HTMLElement new]];
[fragment appendNode:[HTMLElement new]];
XCTAssertThrows([document appendNode:fragment]);
/**
* Fragment has one node child
* Document has an Element child
*/
reset();
[fragment appendNode:[HTMLElement new]];
[document appendNode:[HTMLElement new]];
XCTAssertThrows([document appendNode:fragment]);
/**
* Fragment has one node child
* "before child" is a Doctype
*/
reset();
HTMLDocumentType *doctype = [HTMLDocumentType new];
[fragment appendNode:[HTMLElement new]];
[document appendNode:doctype];
XCTAssertThrows([document insertNode:fragment beforeChildNode:doctype]);
/**
* Fragment has one node child
* "before child" is following a Doctype
*/
reset();
HTMLComment *doctypePreviousSibling = [HTMLComment new];
[fragment appendNode:[HTMLElement new]];
[document appendNode:doctypePreviousSibling];
[document appendNode:doctype];
XCTAssertThrows([document insertNode:fragment beforeChildNode:doctypePreviousSibling]);
}
- (void)testValidElementInsertionIntoDocument
{
HTMLDocument *document = [HTMLDocument new];
HTMLElement *element = [HTMLElement new];
void (^ reset)() = ^ {
[element removeAllChildNodes];
[document removeAllChildNodes];
};
/**
* Document has an Element child
*/
[document appendNode:[HTMLElement new]];
XCTAssertThrows([document appendNode:element]);
/**
* "before child" is a Doctype
*/
reset();
HTMLDocumentType *doctype = [HTMLDocumentType new];
[document appendNode:doctype];
XCTAssertThrows([document insertNode:element beforeChildNode:doctype]);
/**
* Doctype is following the "before child"
*/
reset();
HTMLComment *doctypePreviousSibling = [HTMLComment new];
[document appendNode:doctypePreviousSibling];
[document appendNode:doctype];
XCTAssertThrows([document insertNode:element beforeChildNode:doctypePreviousSibling]);
}
- (void)testValidDoctypeInsertionIntoDocument
{
HTMLDocument *document = [HTMLDocument new];
HTMLDocumentType *doctype = [HTMLDocumentType new];
void (^ reset)() = ^ {
[document removeAllChildNodes];
};
/**
* Document has a Doctype child
*/
[document appendNode:[HTMLDocumentType new]];
XCTAssertThrows([document appendNode:doctype]);
/**
* An Element is preceding the "before child"
*/
reset();
HTMLComment *secondChild = [HTMLComment new];
[document appendNode:[HTMLElement new]];
[document appendNode:secondChild];
XCTAssertThrows([document insertNode:doctype beforeChildNode:secondChild]);
/**
* Document has an Element child
*/
reset();
[document appendNode:[HTMLElement new]];
XCTAssertThrows([document appendNode:doctype]);
}
- (void)testValidDocumentFragmentReplacementIntoDocument
{
HTMLDocument *document = [HTMLDocument new];
HTMLComment *child = [HTMLComment new];
HTMLDocumentFragment *replacement = [[HTMLDocumentFragment alloc] initWithDocument:document];
void (^ reset)() = ^ {
[replacement removeAllChildNodes];
[document removeAllChildNodes];
[document appendNode:child];
};
/**
* Replacement Fragment has a Text node child
*/
[replacement appendNode:[HTMLText new]];
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
/**
* Replacement Fragment has more than one Element child
*/
reset();
[replacement appendNode:[HTMLElement new]];
[replacement appendNode:[HTMLElement new]];
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
/**
* Replacement Fragment has one Element child
* Document has an Element child that is not the Replacement
*/
reset();
[replacement appendNode:[HTMLElement new]];
[document appendNode:[HTMLElement new]];
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
/**
* Replacement Fragment has one Element child
* Doctype is following the child node
*/
reset();
HTMLDocumentType *doctype = [HTMLDocumentType new];
[replacement appendNode:[HTMLElement new]];
[document appendNode:doctype];
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
}
- (void)testValidElementReplacementIntoDocument
{
HTMLDocument *document = [HTMLDocument new];
HTMLComment *child = [HTMLComment new];
HTMLElement *replacement = [HTMLElement new];
void (^ reset)() = ^ {
[replacement removeAllChildNodes];
[document removeAllChildNodes];
[document appendNode:child];
};
/**
* Docment has an Element child that is not replacement
*/
[document appendNode:[HTMLElement new]];
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
/**
* Doctype is following the child node
*/
reset();
HTMLDocumentType *doctype = [HTMLDocumentType new];
[document appendNode:doctype];
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
}
- (void)testValidDoctypeReplacementIntoDocument
{
HTMLDocument *document = [HTMLDocument new];
HTMLComment *child = [HTMLComment new];
HTMLDocumentType *replacement = [HTMLDocumentType new];
void (^ reset)() = ^ {
[replacement removeAllChildNodes];
[document removeAllChildNodes];
[document appendNode:child];
};
/**
* Docment has an Doctype child that is not replacement
*/
[document appendNode:[HTMLDocumentType new]];
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
/**
* An Element is preceding the child node
*/
reset();
[document insertNode:[HTMLElement new] beforeChildNode:child];
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
}
@end
+568
View File
@@ -0,0 +1,568 @@
//
// HTMLKitNodeTreeEnumratorTests.m
// HTMLKit
//
// Created by Iska on 28/03/15.
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "HTMLDOM.h"
@interface HTMLKitNodeIteratorTests : XCTestCase
@end
@implementation HTMLKitNodeIteratorTests
#pragma mark - Test DOM
- (HTMLElement *)div
{
return [[HTMLElement alloc] initWithTagName:@"div"];
}
- (HTMLElement *)simpleTree
{
/*
| div
| a
| b
| c
*/
HTMLElement *div = self.div;
[div appendNode:[[HTMLElement alloc] initWithTagName:@"a"]];
[div appendNode:[[HTMLElement alloc] initWithTagName:@"b"]];
[div appendNode:[[HTMLElement alloc] initWithTagName:@"c"]];
return div;
}
- (HTMLElement *)nestedSimpleTree
{
/*
| div
| div
| a
| b
| c
| div
| a
| b
| c
*/
HTMLElement *div = self.div;
[div appendNode:self.simpleTree];
[div appendNode:self.simpleTree];
return div;
}
- (HTMLElement *)complexTree
{
/*
| div
| div
| div
| a
| b
| c
| e
| f
| div
| a
| b
| c
*/
HTMLElement *root = self.div;
HTMLElement *div = self.div;
[div appendNode:self.simpleTree];
[root appendNode:div];
HTMLElement *e = [[HTMLElement alloc] initWithTagName:@"e"];
[e appendNode:[[HTMLElement alloc] initWithTagName:@"f"]];
[root appendNode:e];
[root appendNode:self.simpleTree];
return root;
}
- (HTMLDocument *)mixedTree
{
/*
| doctype
| #comment <!-- This is a Comment -->
| #comment <!-- This is a second 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;
}
- (HTMLDocument *)document
{
NSString *htmlString =
@"<!DOCTYPE html>"
@"<html>"
@"<head>"
@"<title>Title</title>"
@"</head>"
@"<body>"
@"<span>Hello<strong>World!</strong><strong>HTML <!-- This is a Comment! --> Kit</strong></span>"
@"<p>This is an <em>Important</em> paragraph</p>"
@"</body>"
@"</html>";
HTMLDocument *document = [HTMLDocument documentWithString:htmlString];
return document;
}
#pragma mark - Test Iterator
- (void)testNodeIteratorInit
{
HTMLElement *tree = self.simpleTree;
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)testNewIteratorNextNodeShouldBeRoot
{
HTMLElement *tree = self.simpleTree;
HTMLNodeIterator *iterator = tree.nodeIterator;
XCTAssertEqualObjects(iterator.nextNode, tree);
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
}
- (void)testNewIteratorPreviousNodeShouldBeNil
{
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
{
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");
}
- (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);
}
#pragma mark - Test Iterator ShowOptions (WhatToShow)
- (void)testShowDocument
{
HTMLDocument *document = self.mixedTree;
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowDocument filter:nil];
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 nodeIteratorWithShowOptions:HTMLNodeFilterShowDocumentType filter:nil];
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 nodeIteratorWithShowOptions:HTMLNodeFilterShowComment filter:nil];
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 nodeIteratorWithShowOptions:HTMLNodeFilterShowText filter:nil];
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 nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil];
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 nodeIteratorWithShowOptions:HTMLNodeFilterShowElement | HTMLNodeFilterShowText
filter:nil];
NSArray *result = iterator.allObjects;
NSArray *expected = @[@"html", @"#text", @"div"];
XCTAssertEqual(result.count, 3);
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
}
#pragma mark - Test Iterator Filter
- (void)testNodeFilter
{
HTMLDocument *document = self.mixedTree;
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowAll
filterBlock:^HTMLNodeFilterValue(HTMLNode *node) {
if (node.nodeType == HTMLNodeComment) {
if ([[(HTMLComment *)node data] rangeOfString:@"second"].location != NSNotFound) {
return HTMLNodeFilterAccept;
}
}
return HTMLNodeFilterSkip;
}];
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);
}
#pragma mark - Test Removing Steps
/*
Test cases for the Removing Steps
https://dom.spec.whatwg.org/#interface-nodeiterator
Following DOM is used:
| <html>
| <head>
| <title>
| "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.lastChild) {
node = node.lastChild;
}
return node;
};
- (void)testThatRemovingRootNodeShouldNotAffectIterator
{
HTMLDocument *document = self.document;
HTMLNode *node = document.body.firstChild; // <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.firstChild);
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.firstChild);
}
- (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.firstChild));
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.firstChild);
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.firstChild));
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.firstChild);
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.firstChild.nodeIterator;
IterateUpToNode(iterator, LastDescendant(body.firstChild)); // Referecne node: <a>
HTMLNode *node = [iterator previousNode]; // pointer-before-reference: YES
RemoveThenInsertNode(node);
XCTAssertEqualObjects(iterator.referenceNode, iterator.root.firstChild);
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
}
@end
@@ -1,148 +0,0 @@
//
// HTMLKitNodeTreeEnumratorTests.m
// HTMLKit
//
// Created by Iska on 28/03/15.
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "HTMLNodes.h"
@interface HTMLKitNodeTreeEnumratorTests : XCTestCase
@end
@implementation HTMLKitNodeTreeEnumratorTests
#pragma mark - Elements
- (HTMLElement *)div
{
return [[HTMLElement alloc] initWithTagName:@"div"];
}
- (HTMLElement *)simpleTree
{
/*
| div
| a
| b
| c
*/
HTMLElement *div = self.div;
[div appendNode:[[HTMLElement alloc] initWithTagName:@"a"]];
[div appendNode:[[HTMLElement alloc] initWithTagName:@"b"]];
[div appendNode:[[HTMLElement alloc] initWithTagName:@"c"]];
return div;
}
- (HTMLElement *)nestedSimpleTree
{
/*
| div
| div
| a
| b
| c
| div
| a
| b
| c
*/
HTMLElement *div = self.div;
[div appendNode:self.simpleTree];
[div appendNode:self.simpleTree];
return div;
}
- (HTMLElement *)complexTree
{
/*
| div
| div
| div
| a
| b
| c
| e
| f
| div
| a
| b
| c
*/
HTMLElement *root = self.div;
HTMLElement *div = self.div;
[div appendNode:self.simpleTree];
[root appendNode:div];
HTMLElement *e = [[HTMLElement alloc] initWithTagName:@"e"];
[e appendNode:[[HTMLElement alloc] initWithTagName:@"f"]];
[root appendNode:e];
[root appendNode:self.simpleTree];
return root;
}
#pragma mark - Tests
- (void)testSingle
{
HTMLElement *div = self.div;
NSArray *result = div.treeEnumerator.allObjects;
NSArray *expected = @[@"div"];
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
}
- (void)testSimpleTree
{
HTMLElement *tree = self.simpleTree;
NSArray *result = tree.treeEnumerator.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);
}
- (void)testNestedSimpleTree
{
HTMLElement *tree = self.nestedSimpleTree;
NSArray *result = tree.treeEnumerator.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);
}
- (void)testComplexSimpleTree
{
HTMLElement *tree = self.complexTree;
NSArray *result = tree.treeEnumerator.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);
}
@end
+485
View File
@@ -0,0 +1,485 @@
//
// HTMLKitNodesTests.m
// HTMLKit
//
// Created by Iska on 20/04/15.
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "HTMLDOM.h"
@interface HTMLKitNodesTests : XCTestCase
@end
@implementation HTMLKitNodesTests
- (void)setUp
{
[super setUp];
}
- (void)tearDown
{
[super tearDown];
}
- (void)testInitNode
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
XCTAssertNotNil(node);
XCTAssertEqualObjects(node.name, @"name");
XCTAssertEqual(node.nodeType, HTMLNodeElement);
XCTAssertNotNil(node.childNodes);
XCTAssertEqual(node.childNodes.count, 0);
XCTAssertNil(node.ownerDocument);
XCTAssertNil(node.parentNode);
XCTAssertNil(node.parentElement);
XCTAssertNil(node.firstChild);
XCTAssertNil(node.lastChild);
XCTAssertNil(node.previousSibling);
XCTAssertNil(node.lastChild);
}
- (void)testAppendNode
{
HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];
HTMLComment *comment = [HTMLComment new];
[element appendNode:comment];
XCTAssertEqual(element.childNodesCount, 1);
XCTAssertEqual(element.firstChild, comment);
HTMLElement *firstElement = [HTMLElement new];
HTMLElement *secondElement = [HTMLElement new];
NSArray *nodes = @[firstElement, secondElement];
[element appendNodes:nodes];
XCTAssertEqual(element.childNodesCount, 3);
XCTAssertEqual(element.firstChild, comment);
XCTAssertEqual(element.lastChild, secondElement);
}
- (void)testPrependNode
{
HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];
HTMLText *text = [HTMLText new];
[element appendNode:text];
HTMLComment *comment = [HTMLComment new];
[element prependNode:comment];
XCTAssertEqual(element.childNodesCount, 2);
XCTAssertEqual(element.firstChild, comment);
HTMLElement *firstElement = [HTMLElement new];
HTMLElement *secondElement = [HTMLElement new];
NSArray *nodes = @[firstElement, secondElement];
[element prependNodes:nodes];
XCTAssertEqual(element.childNodesCount, 4);
XCTAssertEqual(element.firstChild, firstElement);
XCTAssertEqual(element.lastChild, text);
}
- (void)testAppendDocumentFragment
{
HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];
HTMLComment *comment = [HTMLComment new];
[element appendNode:comment];
HTMLDocumentFragment *fragment = [HTMLDocumentFragment new];
HTMLElement *firstChild = [HTMLElement new];
HTMLElement *secondChild = [HTMLElement new];
[fragment appendNode:firstChild];
[fragment appendNode:secondChild];
[element appendNode:fragment];
XCTAssertEqual(element.childNodesCount, 3);
XCTAssertEqual(fragment.childNodesCount, 0);
XCTAssertEqualObjects(firstChild.parentNode, element);
XCTAssertEqualObjects(secondChild.parentNode, element);
XCTAssertEqualObjects(element.firstChild, comment);
XCTAssertEqualObjects(element.firstChild.nextSibling, firstChild);
XCTAssertEqualObjects(element.lastChild.previousSibling, firstChild);
XCTAssertEqualObjects(element.lastChild, secondChild);
}
- (void)testParentNode
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
XCTAssertNil(firstChild.parentNode);
[node appendNode:firstChild];
XCTAssertTrue(node.hasChildNodes);
XCTAssertEqual(node.childNodesCount, 1);
XCTAssertNotNil(firstChild.parentNode);
XCTAssertEqualObjects(firstChild.parentNode, node);
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
[node appendNodes:@[secondChild, thirdChild]];
XCTAssertTrue(node.hasChildNodes);
XCTAssertEqual(node.childNodesCount, 3);
XCTAssertNotNil(secondChild.parentNode);
XCTAssertEqualObjects(secondChild.parentNode, node);
XCTAssertNotNil(thirdChild.parentNode);
XCTAssertEqualObjects(thirdChild.parentNode, node);
}
- (void)testChildNodesCount
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
XCTAssertFalse(node.hasChildNodes);
XCTAssertEqual(node.childNodesCount, 0);
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
XCTAssertTrue(node.hasChildNodes);
XCTAssertEqual(node.childNodesCount, 1);
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
[node appendNode:secondChild];
XCTAssertTrue(node.hasChildNodes);
XCTAssertEqual(node.childNodesCount, 2);
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
[node appendNode:thirdChild];
XCTAssertTrue(node.hasChildNodes);
XCTAssertEqual(node.childNodesCount, 3);
}
- (void)testFirstAndLastChildNodes
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
XCTAssertEqualObjects(node.firstChild, firstChild);
XCTAssertEqualObjects(node.lastChild, firstChild);
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
[node appendNode:secondChild];
XCTAssertEqualObjects(node.firstChild, firstChild);
XCTAssertEqualObjects(node.lastChild, secondChild);
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
[node appendNode:thirdChild];
XCTAssertEqualObjects(node.firstChild, firstChild);
XCTAssertEqualObjects(node.lastChild, thirdChild);
}
- (void)testNextAndPreviousSiblingNodes
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
[node appendNode:secondChild];
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
[node appendNode:thirdChild];
XCTAssertNil(firstChild.previousSibling);
XCTAssertEqualObjects(firstChild.nextSibling, secondChild);
XCTAssertEqualObjects(secondChild.previousSibling, firstChild);
XCTAssertEqualObjects(secondChild.nextSibling, thirdChild);
XCTAssertEqualObjects(thirdChild.previousSibling, secondChild);
XCTAssertNil(thirdChild.nextSibling);
}
- (void)testHasChildNodeOfType
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
XCTAssertFalse([node hasChildNodeOfType:HTMLNodeElement]);
XCTAssertFalse([node hasChildNodeOfType:HTMLNodeText]);
XCTAssertFalse([node hasChildNodeOfType:HTMLNodeComment]);
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
XCTAssertTrue([node hasChildNodeOfType:HTMLNodeElement]);
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeText];
[node appendNode:secondChild];
XCTAssertTrue([node hasChildNodeOfType:HTMLNodeText]);
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeComment];
[node appendNode:thirdChild];
XCTAssertTrue([node hasChildNodeOfType:HTMLNodeComment]);
}
- (void)testChildNodeAtIndex
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
[node appendNode:secondChild];
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
[node appendNode:thirdChild];
XCTAssertEqualObjects([node childNodeAtIndex:0], firstChild);
XCTAssertEqualObjects([node childNodeAtIndex:1], secondChild);
XCTAssertEqualObjects([node childNodeAtIndex:2], thirdChild);
}
- (void)testIndexOfChildNode
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
[node appendNode:secondChild];
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
[node appendNode:thirdChild];
XCTAssertEqual([node indexOfChildNode:firstChild], 0);
XCTAssertEqual([node indexOfChildNode:secondChild], 1);
XCTAssertEqual([node indexOfChildNode:thirdChild], 2);
}
- (void)testIndertNodeBeforeChild
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
[node insertNode:secondChild beforeChildNode:firstChild];
XCTAssertEqual([node indexOfChildNode:firstChild], 1);
XCTAssertEqual([node indexOfChildNode:secondChild], 0);
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
[node insertNode:thirdChild beforeChildNode:firstChild];
XCTAssertEqual([node indexOfChildNode:firstChild], 2);
XCTAssertEqual([node indexOfChildNode:secondChild], 0);
XCTAssertEqual([node indexOfChildNode:thirdChild], 1);
}
- (void)testReplaceChildNode
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
[node appendNode:secondChild];
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
[node replaceChildNode:firstChild withNode:thirdChild];
XCTAssertNil(firstChild.parentNode);
XCTAssertEqual([node indexOfChildNode:firstChild], NSNotFound);
XCTAssertEqual([node indexOfChildNode:secondChild], 1);
XCTAssertEqual([node indexOfChildNode:thirdChild], 0);
}
- (void)testReplaceAllChildNodes
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
[node appendNode:secondChild];
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
[node replaceAllChildNodesWithNode:thirdChild];
XCTAssertNil(firstChild.parentNode);
XCTAssertNil(secondChild.parentNode);
XCTAssertEqualObjects(thirdChild.parentNode, node);
XCTAssertEqual(node.childNodesCount, 1);
XCTAssertEqual([node indexOfChildNode:thirdChild], 0);
}
- (void)testRemoveFromParentNode
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
[firstChild removeFromParentNode];
XCTAssertNil(firstChild.parentNode);
XCTAssertEqual(node.childNodesCount, 0);
XCTAssertEqual([node indexOfChildNode:firstChild], NSNotFound);
}
- (void)testRemoveChildNode
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
[node appendNode:secondChild];
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
[node appendNode:thirdChild];
[node removeChildNode:secondChild];
XCTAssertEqual(node.childNodesCount, 2);
XCTAssertEqualObjects(firstChild.parentNode, node);
XCTAssertNil(secondChild.parentNode);
XCTAssertEqualObjects(thirdChild.parentNode, node);
XCTAssertEqual([node indexOfChildNode:firstChild], 0);
XCTAssertEqual([node indexOfChildNode:secondChild], NSNotFound);
XCTAssertEqual([node indexOfChildNode:thirdChild], 1);
[node removeChildNode:firstChild];
XCTAssertEqual(node.childNodesCount, 1);
XCTAssertNil(firstChild.parentNode);
XCTAssertNil(secondChild.parentNode);
XCTAssertEqualObjects(thirdChild.parentNode, node);
XCTAssertEqual([node indexOfChildNode:firstChild], NSNotFound);
XCTAssertEqual([node indexOfChildNode:secondChild], NSNotFound);
XCTAssertEqual([node indexOfChildNode:thirdChild], 0);
}
- (void)testRemoveChildNodeAtIndex
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
[node appendNode:secondChild];
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
[node appendNode:thirdChild];
[node removeChildNodeAtIndex:1];
XCTAssertEqual(node.childNodesCount, 2);
XCTAssertEqualObjects(firstChild.parentNode, node);
XCTAssertNil(secondChild.parentNode);
XCTAssertEqualObjects(thirdChild.parentNode, node);
XCTAssertEqual([node indexOfChildNode:firstChild], 0);
XCTAssertEqual([node indexOfChildNode:secondChild], NSNotFound);
XCTAssertEqual([node indexOfChildNode:thirdChild], 1);
[node removeChildNodeAtIndex:0];
XCTAssertEqual(node.childNodesCount, 1);
XCTAssertNil(firstChild.parentNode);
XCTAssertNil(secondChild.parentNode);
XCTAssertEqualObjects(thirdChild.parentNode, node);
XCTAssertEqual([node indexOfChildNode:firstChild], NSNotFound);
XCTAssertEqual([node indexOfChildNode:secondChild], NSNotFound);
XCTAssertEqual([node indexOfChildNode:thirdChild], 0);
}
- (void)testRemoveAllChildNodes
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
[node appendNode:secondChild];
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
[node appendNode:thirdChild];
[node removeAllChildNodes];
XCTAssertEqual(node.childNodesCount, 0);
XCTAssertNil(firstChild.parentNode);
XCTAssertNil(secondChild.parentNode);
XCTAssertNil(thirdChild.parentNode);
XCTAssertEqual([node indexOfChildNode:firstChild], NSNotFound);
XCTAssertEqual([node indexOfChildNode:secondChild], NSNotFound);
XCTAssertEqual([node indexOfChildNode:thirdChild], NSNotFound);
}
- (void)testReparentChildNodes
{
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
[node appendNode:firstChild];
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
[node appendNode:secondChild];
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
[node appendNode:thirdChild];
HTMLNode *newParent = [[HTMLNode alloc] initWithName:@"new-parent" type:HTMLNodeElement];
[node reparentChildNodesIntoNode:newParent];
XCTAssertEqual(node.childNodesCount, 0);
XCTAssertEqual([node indexOfChildNode:firstChild], NSNotFound);
XCTAssertEqual([node indexOfChildNode:secondChild], NSNotFound);
XCTAssertEqual([node indexOfChildNode:thirdChild], NSNotFound);
XCTAssertEqualObjects(firstChild.parentNode, newParent);
XCTAssertEqualObjects(secondChild.parentNode, newParent);
XCTAssertEqualObjects(thirdChild.parentNode, newParent);
}
- (void)testElementSetInnerHTML
{
HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];
[element appendNode:[[HTMLElement alloc] initWithTagName:@"img"]];
[element setInnerHTML:@"<p></p><p></p>"];
XCTAssertEqual(element.childNodesCount, 2);
XCTAssertEqualObjects(element.firstChild.asElement.tagName, @"p");
XCTAssertEqualObjects([element childNodeAtIndex:1].asElement.tagName, @"p");
}
@end
+4
View File
@@ -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
+5 -5
View File
@@ -9,7 +9,7 @@
#import <XCTest/XCTest.h>
#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);
+503
View File
@@ -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.lastChild.firstChild.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.firstChild;
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.firstChild;
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.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.firstChild);
XCTAssertEqualObjects(walker.currentNode, document.documentElement.firstChild);
walker.currentNode = document.documentElement;
XCTAssertEqualObjects(walker.lastChild, document.documentElement.lastChild);
XCTAssertEqualObjects(walker.currentNode, document.documentElement.lastChild);
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