ObjCで書かれたObjective-C-HTML-ParserをSwiftに。
今回はオリジナルから下記の機能だけ抜き出してみました。
- ノード検索
- 属性名取得
- テキスト取得(コンテンツ取得)
コードはGitHubに置いています。
事前準備
- libxml2.dylibをリンク。
- libxml/HTMLtree.hをブリッジングヘッダでinclude
ブリッジングヘッダは、XCodeのプロジェクトの下記で指定します。
"Build Settings > Swift Compiler - Code Generation > Objective-C Bridging Header"
または、ObjCファイル(.m)を追加するときに作るか聞いてくるのでそちらでも。
ファイル名は"[プロジェクト名]-Bridging-Header.h"という名前にします。
特に決まっているわけでは無いので好きな名前でもOK。
ポインタ型のキャスト方法
UnsafePointer<T>.init<U>(_ from: UnsafePointer<U>)
がやってくれました。
例えば unsigned char* を char* にキャストしたい時はこんな感じです。
var xxx : CUnsignedChar[] = [0x68, 0x6f, 0x67, 0x65, 0x00]
var hoge : CMutablePointer<CUnsignedChar> = &xxx
var fuga = UnsafePointer<CChar>(hoge.value) // unsigned char* を char*にキャスト
println(String.fromCString(fuga))
ちなみに、型の対応は下記の通りです。
C Type | Swift Type |
---|---|
char | CChar |
unsigned char | CUnsignedChar |
Interacting with C APIs - Primitive Types より抜粋 |
-補足-
冒頭のイニシャライザの引数fromの前に付いている'_'は、匿名引数という意味です。
付けると引数名を省略できます。
Generatorをインナークラスにできない?
HTMLNodeクラスのGenerator(HTMLNodeGenerator)をインナークラスにすると、
コンパイルエラーが出たのでとりあえず別クラスにしました。
確認した限り、XCodeでプロジェクトを作った場合のみ発生します。
Playgroundとコマンドラインでは通るので要調査。
// エラー確認用の最小コード(PlaygroundだとOK)
class HTMLNode : Sequence {
class HTMLNodeGenerator : Generator {
func next() -> HTMLNode? {
return nil
}
}
func generate() -> HTMLNodeGenerator {
return HTMLNodeGenerator()
}
}
使用例
import Foundation
let html = "<ul><li><input type='image' name='input1' value='string1value' class='abc' /></li><li><input type='image' name='input2' value='string2value' class='def' /></li></ul><span class='spantext'><b>Hello World 1</b></span><span class='spantext'><b>Hello World 2</b></span>"
var err : NSError?
var parser = HTMLParser(html: html, error: &err)
if err {
println(err)
exit(1)
}
var bodyNode = parser.body
if let inputNodes = bodyNode?.findChildTags("b") {
for node in inputNodes {
println(node.contents)
}
}