IGHTMLQuery是iOS上一个轻量级的XML/HTML解析器,基于libxml构建。它受jQuery和nokogiri的启发。考虑以下代码片段
IGXMLDocument* node = [[IGXMLDocument alloc] initWithXMLString:catelogXml error:nil];
NSString* title = [[[node queryWithXPath:@"//cd/title"] firstObject] text];
[[node queryWithXPath:@"//title"] enumerateNodesUsingBlock:^(IGXMLNode *title, NSUInteger idx, BOOL *stop) {
NSLog(@"title = %@", title.text);
}];
// or use CSS Selector
[[node queryWithCSS:@"title"] enumerateNodesUsingBlock:^(IGXMLNode *title, NSUInteger idx, BOOL *stop) {
NSLog(@"title = %@", title.text);
}];
// quick manipulation
[[node queryWithXPath:@"//title"] appendWithXMLString:@"<message>Hi!</message>"];
IGHTMLQuery可以通过CocoaPods获得,要安装它,只需将以下行添加到您的Podfile中
pod "IGHTMLQuery", "~> 0.8.4"
或者
Classes
目录中的源文件添加到您的Xcode项目中libxml2
。$(SDK_DIR)/usr/include/libxml2
对于每个使用IGHTMLQuery的文件,导入IGHTMLQuery.h
#import 'IGHTMLQuery.h'
创建一个XML文档
IGXMLDocument* node = [[IGXMLDocument alloc] initWithXMLString:xml error:nil];
创建一个HTML文档
IGHTMLDocument* node = [[IGHTMLDocument alloc] initWithHTMLString:html error:nil];
使用parent
、nextSibling
、previousSibling
、children
和firstChild
来遍历文档。
您可以使用queryWithXPath:
或queryWithCSS:
方法查询文档或任何节点。它们将始终返回一个IGXMLNodeSet
对象,这是一个可以链式查询和操作类似集合的对象。
IGXMLNodeSet* contents = [doc queryWithXPath:@"//div[@class='content']"];
[contents enumerateNodesUsingBlock:^(IGXMLNode* content, NSUInteger idx, BOOL *stop){
NSLog(@"%@", content.xml);
}];
// use a @try/@catch block for queryWithCSS, as it can throw an exception if
// the CSS Selector cannot be converted to XPath.
@try {
contents = [doc queryWithCSS:@"div.content"];
[contents enumerateNodesUsingBlock:^(IGXMLNode* content, NSUInteger idx, BOOL *stop){
NSLog(@"%@", content.xml);
}];
} @catch(NSException * e) {
// handle error
}
您可以使用IGXMLNodeManipulation
协议中的方法更改文档。
@protocol IGXMLNodeManipulation <NSObject>
-(instancetype) appendWithNode:(IGXMLNode*)child;
-(instancetype) prependWithNode:(IGXMLNode*)child;
-(instancetype) addChildWithNode:(IGXMLNode*)child;
-(instancetype) addNextSiblingWithNode:(IGXMLNode*)child;
-(instancetype) addPreviousSiblingWithNode:(IGXMLNode*)child;
-(void) empty;
-(void) remove;
@end
IGHTMLQuery中的所有类都支持JavaScriptCore导出。此外,还提供了Ruby包装器来与
#import "JSContext+IGHTMLQueryRubyAdditions.h"
#import "JSContext+OpalAdditions.h"
// load IGHTMLQuery ruby wrapper classes
[context configureIGHTMLQuery];
// create a lambda that evalulate script on the fly
JSValue* instanceEval = [context evaluateRuby:@"lambda { |doc, script| XMLNode.new(doc).instance_eval(&eval(\"lambda { #{script} }\")) }"];
// a simple script that find the title of first cd have a price less than 9.0
JSValue* node = [instanceEval callWithArguments:@[doc, @"self.xpath('//cd').find {|node| node.xpath('./price').text.to_f < 9.0 }.xpath('./title').text"]];
// convert the result to string
NSString* title = [node toString];
XCTAssertEqualObjects((@"Greatest Hits"), title, @"title should be Greatest Hits");
要使用带有Ruby支持的IGHTMLQuery,请将以下行添加到您的Podfile中:
pod "IGHTMLQuery/Ruby"
有关更多详细信息,请参阅测试用例。
在之前的版本中,方法[[IGHTMLDocument alloc] initWithHTMLString:]会创建不带隐含HTML标签的html元素(libxml中的HTML_PARSE_NOIMPLIED选项)。从0.7.2版本开始,HTML_PARSE_NOIMPLIED将不再是默认值。
如果您想保持旧的行为,请检查[[IGHTMLDocument alloc] initWithHTMLFragmentString:]方法。
MIT许可证。