57 Commits

Author SHA1 Message Date
iska 0401118657 Merge branch 'release/0.2.0' 2015-06-06 20:12:42 +02:00
iska 045e4db9d1 Add node iterator, tree walker & node filter imports to the HTMLDOM header 2015-06-06 20:11:49 +02:00
iska a7caa34762 Disable HTML DOM checks in parser's performance test
The baseline was set before the DOM validations were implemented.
2015-06-06 20:10:28 +02:00
iska df53870880 Drop the "Node" suffix from HTML Node's first child & last child properties
https://dom.spec.whatwg.org/#interface-node
2015-06-06 19:04:03 +02:00
iska 7f25aacaf1 Add test cases for the Tree Walker class 2015-06-06 19:00:02 +02:00
iska 5e482788ce Add Tree Walker's initializer methods 2015-06-06 18:59:06 +02:00
iska a39890e6e9 Add documentElement property for the HTML Document
The documentElement is the <html> element
2015-06-06 18:58:45 +02:00
iska fd516c67ef Change Node Filter's show options enum to NS_OPTIONS 2015-06-05 23:01:55 +02:00
iska a390edf599 Reintroduce the HTMLNodeFilterValue for Tree Walker implementation
While the Node Iterator treats skip & reject the same way, the Tree Walker can skip over a node
and all its children if rejected.

This reverses dc3de7a470
2015-06-05 23:00:50 +02:00
iska 0c82f6891b Add implementation for the Tree Walker
https://dom.spec.whatwg.org/#interface-treewalker
2015-06-05 22:46:41 +02:00
iska 0d7c57d755 Refactor common node traversal methods into separate class
These will be used in the Tree Walker
https://dom.spec.whatwg.org/#interface-treewalker
2015-06-05 22:09:02 +02:00
iska 40400864d8 Add block-based API for Node Filter
- HTMLNodeFilterBlock is a block-based class implementation conforming to HTMLNodeFilter
- HTMLNode & NodeIterator get block-based initializers
2015-06-05 18:06:23 +02:00
iska dc3de7a470 Remove the HTMLNodeFilterValue enum since Reject and Skip are semantically equivalent 2015-06-05 17:05:22 +02:00
iska c1b18f527c Refactor Node Iterator's initializers so that the filter argument is last 2015-06-05 17:04:28 +02:00
iska d4bb3c6636 Add implementation for the removing steps of the HTML Node Iterator
https://dom.spec.whatwg.org/#interface-nodeiterator
2015-06-05 16:47:37 +02:00
iska 0baa343e95 Add Document methods to access the root, head & body elements
The implementation will be changed/adapted later when the CSS Selectors are ready.
2015-06-05 16:46:36 +02:00
iska 2f1555e93d Rename group for DOM tests 2015-06-02 01:06:13 +02:00
iska a0fd89f417 Move test class for Ordered Dictionary into own group 2015-06-02 01:05:44 +02:00
iska d002c6cedd Add HTML Node methods for comparing node positions in a tree
https://dom.spec.whatwg.org/#dom-node-comparedocumentpositionother
2015-05-31 16:53:54 +02:00
iska 71fefa2fa9 Add methods to attach Node Iterators to the owner document node of the iterator's root
This is a prerequisite to implement the iterator's removing steps.
https://dom.spec.whatwg.org/#interface-nodeiterator
2015-05-29 20:16:17 +02:00
iska 066bdeffa8 Add Node Iterator test cases for iteration and filtering logic 2015-05-29 00:39:52 +02:00
iska 3df5a219e1 Add Node Iterator initializers with filter and show-options arguments 2015-05-28 23:26:08 +02:00
iska e1c3533a1c Remove unused import in Tree Construction test class 2015-05-28 22:57:31 +02:00
iska dfeebc7f7f Remove frameworks search path entry causing an ignored warning on build 2015-05-28 22:56:49 +02:00
iska cd6e8bf4fc Remove Tree Enumerator since it was superseded by the Node Iterator implementation 2015-05-28 01:22:29 +02:00
iska 0fa394b911 Fix traversing method in Node Iterator 2015-05-28 01:21:06 +02:00
iska 13ed63017e Fix initial Node Iterator values 2015-05-28 00:55:45 +02:00
iska ac561570f3 Use correct DOM import in test classes 2015-05-28 00:43:27 +02:00
iska 165cdb5a75 Fix HTML Element initializer usage after arguments reordering 2015-05-28 00:42:59 +02:00
iska aece7138a4 Rename Tree Enumeration Tests to Node Iterator Tests 2015-05-28 00:42:20 +02:00
iska 45156d98fd Add implementation for HTML Node Iterator
This, along with Tree Walker, will replace the Tree Enumerator.
https://dom.spec.whatwg.org/#interface-nodeiterator
2015-05-28 00:34:17 +02:00
iska 7892a925c8 Fix Element initializer after reordering the arguments 2015-05-27 00:59:37 +02:00
iska f8ee4a38b4 Add HTML Node Filter protocol 2015-05-27 00:59:10 +02:00
iska de597a51a4 Reorganize HTML DOM classes 2015-05-27 00:53:58 +02:00
iska 470b9b8d37 Change arguments order in HTML Element initializer for convenience
Dictionary argument moved to last position.
2015-05-27 00:39:39 +02:00
iska 915f4cc064 Remove baseURI property from HTMLNode
Proper support will be implemented when needed.
2015-05-27 00:38:07 +02:00
iska 11af0509a3 Rename type property to nodeType in HTMLNode for better clarity 2015-05-27 00:37:23 +02:00
iska 2ee3b2d2b3 Rename HTMLNode header to HTMLDOM 2015-05-22 20:06:24 +02:00
iska 1e9118078f Rename Nodes group to DOM 2015-05-21 23:24:13 +02:00
iska 74aec57785 Add method to set inner HTML of an Element 2015-05-21 00:20:20 +02:00
iska 111acb4f8f Add a convenience HTML Document initializer
Creates a document directly given a HTML string, instead of manually creating a parser.
2015-05-20 22:39:52 +02:00
iska 2c9f68e2ea Add Node methods to prepend nodes 2015-05-02 21:08:21 +02:00
iska 3d3e4d52b4 Add a NO_DOM_CHECKS macro to disable validations for DOM manipulations
DOM validation checks are expensive. This macro would allow for removing these checks from the compiled
product, which would increase performance by about 20-30%. However, the user is responsible for the validity
of the manipulations and the resulting DOM.
2015-05-02 20:52:03 +02:00
iska bf061d6367 Add support for inserting a Document Fragment
Previous implementation would just insert the fragment as a child node, whereas it should insert its
child nodes.
2015-05-02 20:47:40 +02:00
iska 40baea8ece Move tests for Mutation Algorithms into separate class 2015-04-27 19:43:43 +02:00
iska a2c6f22495 Add comments for insertion and replacement tests 2015-04-25 22:31:47 +02:00
iska b2f1864c80 Add tests for validating the replacing child node within a Document 2015-04-25 22:31:12 +02:00
iska cffe1cc703 Fix validation for replacing a child node and refactor common logic into a block 2015-04-25 22:25:31 +02:00
iska bc6bbf1d63 Add tests for validation for inserting an Element & Document Type into a Document 2015-04-25 15:27:25 +02:00
iska 71aed89574 Fix validation for inserting a Document Fragment into a Document 2015-04-25 15:13:43 +02:00
iska 36960dceb3 Rename node parameter in the validation method of HTML Node for clarity 2015-04-25 13:21:08 +02:00
iska 3ddfa15b15 Add tests to validate the insertions of nodes into a given parent
These tests check the implementation of the Mutation Algorithms of the DOM Standard
https://dom.spec.whatwg.org/#mutation-algorithms
2015-04-25 13:20:15 +02:00
iska 071742fb27 Add default initializers for HTML Comment, Document Type & Document Fragment 2015-04-25 13:17:02 +02:00
iska 1bc896efc9 Add tests for HTML Node methods
Todo: Tests for negative cases, e.g. invalid manipulations that lead to hierarchy or not found errors.
2015-04-23 00:43:06 +02:00
iska 429f00adb6 Fix project settings after update to Xcode 6.3.1 2015-04-23 00:40:35 +02:00
iska d08ac2100e Fix the isEqualTo call in Parser
Use isEqual instead
2015-04-21 23:07:57 +02:00
iska 62a6336dce Merge branch 'release/0.1.0' into develop 2015-04-20 21:51:38 +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