LoginSignup
16

More than 5 years have passed since last update.

SwiftでObjCコードを書き換えてみる(Objective-C-HTML-Parser)

Posted at

ObjCで書かれたObjective-C-HTML-ParserをSwiftに。
今回はオリジナルから下記の機能だけ抜き出してみました。

  • ノード検索
  • 属性名取得
  • テキスト取得(コンテンツ取得)

コードはGitHubに置いています。

事前準備

  1. libxml2.dylibをリンク。
  2. 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とコマンドラインでは通るので要調査。

test.swift
// エラー確認用の最小コード(PlaygroundだとOK)
class HTMLNode : Sequence {
    class HTMLNodeGenerator : Generator {
        func next() -> HTMLNode? {
            return nil
        }
    }

    func generate() -> HTMLNodeGenerator {
        return HTMLNodeGenerator()
    }
}

使用例

main.swift
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)
    }
}

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16