Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

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)
    }
}

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away