HTMLKit 4.2.0

HTMLKit 4.2.0

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布上次发布2021年4月
SPM支持SPM

Iskandar Abudiab维护。



HTMLKit 4.2.0

HTMLKit

HTMLKit Logo

HTMLKit 是一个针对日常HTML需求的Objective-C框架。

Build Status codecov Carthage Compatible CocoaPods Compatible CocoaDocs Platform License MIT

快速概览

HTMLKit 是一个符合 WHATWG 规范 框架,用于解析和序列化iOS和OSX上的HTML文档和文档片段。HTMLKit 会像现代网页浏览器一样解析真实的HTML。

HTMLKit 提供了一个丰富的DOM实现,用于操作和导航文档树。它还支持 CSS3选择器,使得节点选择和查询DOM变得轻而易举。

DOM验证

DOM变更会按照WHATWG DOM标准进行验证。无效的DOM操作会抛出与层次结构相关的异常。您可以通过定义编译器常量HTMLKIT_NO_DOM_CHECKS来禁用这些验证,这将提高性能约20-30%。

测试

HTMLKit通过了所有HTML5Lib标记解析器和树构建测试。)html5lib-tests配置为git子模块。如果你打算运行测试,别忘了也要拉取它。

CSS3选择器实现是通过修改版本的CSS3选择器测试套件进行测试的,忽略需要用户交互、会话历史和脚本的测试。

如何Swift?

查看游乐场!

安装

Carthage

Carthage是一个去中心化的依赖管理器,用于构建你的依赖并提供二进制框架。

如果你还没有Carthage,你可以使用以下命令通过Homebrew安装它

$ brew update
$ brew install carthage

要使用Carthage将HTMLKit作为依赖添加到你的项目,只需在你的Cartfile中添加以下行

github "iabudiab/HTMLKit"

然后,运行以下命令构建框架并将构建的HTMLKit.framework拖到你的Xcode项目中。

$ carthage update

CocoaPods

CocoaPods是Cocoa项目的依赖管理器。

如果你还没有CocoaPods,你可以使用以下命令安装它

$ gem install cocoapods

要将HTMLKit作为依赖添加到你的项目,只需在你的Podfile中添加以下内容

target 'MyTarget' do
  pod 'HTMLKit', '~> 3.1'
end

然后,运行以下命令

$ pod install

Swift包管理器

Swift包管理器是Swift编程语言的包管理器。

HTMLKit添加到您的Package.swift依赖项中

.Package(url: "https://github.com/iabudiab/HTMLKit", majorVersion: 3)

然后运行

$ swift build

手动操作

1- 将HTMLKit作为git子模块添加

$ git submodule add https://github.com/iabudiab/HTMLKit.git

2- 打开HTMLKit文件夹,将HTMLKit.xcodeproj拖放到Xcode的项目导航器中以将其添加为子项目。

3- 在您的目标的“通用”面板中,在“嵌入的二进制文件”下添加HTMLKit.framework

解析

解析文档

给定一些HTML内容,您可以通过HTMLParser或直接实例化一个HTMLDocument来解析它

NSString *htmlString = @"<div><h1>HTMLKit</h1><p>Hello there!</p></div>";

// Via parser
HTMLParser *parser = [[HTMLParser alloc] initWithString:htmlString];
HTMLDocument *document = [parser parseDocument];

// Via static initializer
HTMLDocument *document = [HTMLDocument documentWithString:htmlString];

解析片段

您也可以将HTML内容作为具有指定上下文元素的文档片段进行解析。

NSString *htmlString = @"<div><h1>HTMLKit</h1><p>Hello there!</p></div>";

HTMLParser *parser = [[HTMLParser alloc] initWithString: htmlString];

HTMLElement *tableContext = [[HTMLElement alloc] initWithTagName:@"table"];
NSArray *nodes = [parser parseFragmentWithContextElement:tableContext];

for (HTMLNode *node in nodes) {
	NSLog(@"%@", node.outerHTML);
}

// The same parser instance can be reusued:
HTMLElement *bodyContext = [[HTMLElement alloc] initWithTagName:@"body"];
nodes = [parser parseFragmentWithContextElement:bodyContext];

DOM树

DOM树可以通过多种方式操作,以下是一些例子:

  • 创建新元素并分配属性
HTMLElement *description = [[HTMLElement alloc] initWithTagName:@"meta"  attributes: @{@"name": @"description"}];
description[@"content"] = @"HTMLKit for iOS & OSX";
  • 将节点添加到文档中
HTMLElement *head = document.head;
[head appendNode:description];

HTMLElement *body = document.body;
NSArray *nodes = @[
	[[HTMLElement alloc] initWithTagName:@"div" attributes: @{@"class": @"red"}],
	[[HTMLElement alloc] initWithTagName:@"div" attributes: @{@"class": @"green"}],
	[[HTMLElement alloc] initWithTagName:@"div" attributes: @{@"class": @"blue"}]
];
[body appendNodes:nodes];
  • 枚举子元素并进行DOM编辑
[body enumerateChildElementsUsingBlock:^(HTMLElement *element, NSUInteger idx, BOOL *stop) {
	if ([element.tagName isEqualToString:@"div"]) {
		HTMLElement *lorem = [[HTMLElement alloc] initWithTagName:@"p"];
		lorem.textContent = [NSString stringWithFormat:@"Lorem ipsum: %lu", (unsigned long)idx];
		[element appendNode:lorem];
	}
}];
  • 从文档中删除节点
[body removeChildNodeAtIndex:1];
[head removeAllChildNodes];
[body.lastChild removeFromParentNode];
  • 直接操作HTML
greenDiv.innerHTML = @"<ul><li>item 1<li>item 2";
  • 导航到子节点和兄弟节点
HTMLNode *firstChild = body.firstChild;
HTMLNode *greenDiv = firstChild.nextSibling;
  • 使用自定义过滤器迭代DOM树
HTMLNodeFilterBlock *filter =[HTMLNodeFilterBlock filterWithBlock:^ HTMLNodeFilterValue (HTMLNode *node) {
	if (node.childNodesCount != 1) {
		return HTMLNodeFilterReject;
	}
	return HTMLNodeFilterAccept;
}];

for (HTMLElement *element in [body nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:filter]) {
	NSLog(@"%@", element.outerHTML);
}
  • 创建和操作DOM范围
HTMLDocument *document = [HTMLDocument documentWithString:@"<div><h1>HTMLKit</h1><p id='foo'>Hello there!</p></div>"];
HTMLRange *range = [[HTMLRange alloc] initWithDocument:document];

HTMLNode *paragraph = [document querySelector:@"#foo"];
[range selectNode:paragraph];
[range extractContents];

CSS3选择器

除了伪元素(::first-line::first-letter等)之外,所有CSS3选择器都受支持。您可以使用它们像以往一样使用

// Given the document:
NSString *htmlString = @"<div><h1>HTMLKit</h1><p class='greeting'>Hello there!</p><p class='description'>This is a demo of HTMLKit</p></div>";
HTMLDocument *document = [HTMLDocument documentWithString: htmlString];

// Here are some of the supported selectors
NSArray *paragraphs = [document querySelectorAll:@"p"];
NSArray *paragraphsOrHeaders = [document querySelectorAll:@"p, h1"];
NSArray *hasClassAttribute = [document querySelectorAll:@"[class]"];
NSArray *greetings = [document querySelectorAll:@".greeting"];
NSArray *classNameStartsWith_de = [document querySelectorAll:@"[class^='de']"];

NSArray *hasAdjacentHeader = [document querySelectorAll:@"h1 + *"];
NSArray *hasSiblingHeader = [document querySelectorAll:@"h1 ~ *"];
NSArray *hasSiblingParagraph = [document querySelectorAll:@"p ~ *"];

NSArray *nonParagraphChildOfDiv = [document querySelectorAll:@"div :not(p)"];

HTMLKit还提供了API,以类型安全的方式创建选择器实例,而无需首先解析它们。前面的示例可以像这样

NSArray *paragraphs = [document elementsMatchingSelector:typeSelector(@"p")];
NSArray *paragraphsOrHeaders = [document elementsMatchingSelector:
	anyOf(@[
		typeSelector(@"p"), typeSelector(@"h1")
	])
];

NSArray *hasClassAttribute = [document elementsMatchingSelector:hasAttributeSelector(@"class")];
NSArray *greetings = [document elementsMatchingSelector:classSelector(@"greeting")];
NSArray *classNameStartsWith_de = [document elementsMatchingSelector:attributeSelector(CSSAttributeSelectorBegins, @"class", @"de")];

NSArray *hasAdjacentHeader = [document elementsMatchingSelector:adjacentSiblingSelector(typeSelector(@"h1"))];
NSArray *hasSiblingHeader = [document elementsMatchingSelector:generalSiblingSelector(typeSelector(@"h1"))];
NSArray *hasSiblingParagraph = [document elementsMatchingSelector:generalSiblingSelector(typeSelector(@"p"))];

NSArray *nonParagraphChildOfDiv = [document elementsMatchingSelector:
	allOf(@[
		childOfElementSelector(typeSelector(@"div")),
		not(typeSelector(@"p"))
	])
];

以下是一些更多示例

HTMLNode *firstDivElement = [document firstElementMatchingSelector:typeSelector(@"div")];

NSArray *secondChildOfDiv = [firstDivElement querySelectorAll:@":nth-child(2)"];
NSArray *secondOfType = [firstDivElement querySelectorAll:@":nth-of-type(2n)"];

secondChildOfDiv = [firstDivElement elementsMatchingSelector:nthChildSelector(CSSNthExpressionMake(0, 2))];
secondOfType = [firstDivElement elementsMatchingSelector:nthOfTypeSelector(CSSNthExpressionMake(2, 0))];

NSArray *notParagraphAndNotDiv = [firstDivElement querySelectorAll:@":not(p):not(div)"];
notParagraphAndNotDiv = [firstDivElement elementsMatchingSelector:
	allOf([
		not(typeSelector(@"p")),
		not(typeSelector(@"div"))
	])
];

还有一件事!您也可以创建自己的选择器。您可以子类化CSSSelector,或者仅使用基于块的包装器。例如,前面的选择器可以像这样实现

CSSSelector *myAwesomeSelector = namedBlockSelector(@"myAwesomeSelector", ^BOOL (HTMLElement *element) {
	return ![element.tagName isEqualToString:@"p"] && ![element.tagName isEqualToString:@"div"];
});
notParagraphAndNotDiv = [firstDivElement elementsMatchingSelector:myAwesomeSelector];

变更日志

更多详细信息,请参阅CHANGELOG.md

许可

HTMLKit遵循MIT许可协议。更多详细信息,请参阅LICENSE文件。