このページの本文へ

XMLとJSONを解析するiPhoneアプリの作り方

2015年09月17日 11時00分更新

森 巧尚

  • この記事をはてなブックマークに追加
本文印刷

「アプリの考え方」を他のサービスやアプリとつながるiOSアプリをSwiftで作成しながら習得できる本連載。2回にわたって、ネットワーク上のデータをアプリに読み込んで扱う方法について解説しています。前回は「データをアプリにダウンロードする方法」を同期、非同期2つの方法で解説しました。今回は「ダウンロードしたデータをアプリで使える形に解析する方法」について解説します。

解析が必要なデータの形式で代表的なXMLとJSONで解説します。

※本連載では、2015年4月時点で最新のXcode 6.3、Swift 1.2で解説します。

おさえておきたい「XML」と「JSON」

XMLとJSON。名前は聞いたことがあるかもしれませんが、どんなものか具体的にわからない方のために、簡単に解説します。

1)XMLとは

XMLとは、「Extensible Markup Language」の略で、テキストデータの意味や構造を記述するための「テキストフォーマット」です。データはタグ<>を使って記述します。タグを入れ子にして、ツリー構造でデータを扱えます。

例)


<?xml version="1.0" encoding="UTF-8"?>
<data>     
    <tea name="ダージリン" price="600"/>
    <tea name="アールグレイ" price="550"/>
</data>

「data」要素に2つの「tea」要素がある2階層のデータ構造です。tea要素には属性データ「name」と「price」があります。

SwiftでXMLを解析する

Swiftは、「データの構造を考えながら」XMLデータを解析します。先頭から解析し、「<data>」タグで、dataの階層に入ったと判断します。次に「<tea>」タグで、dataの階層の下にteaの階層があると判断し、次の「<tea>」タグで、teaの階層には2つの要素があると判断します。「</data>」タグでdataの階層が終わったと判断します。

2)JSONとは

JSONとは、「JavaScript Object Notation」の略で、JavaScriptのオブジェクトデータを扱う「テキストフォーマット」です。

JSONは、JavaScriptの書き方で記述されている、XMLよりシンプルで扱いやすいデータ形式です。JavaScriptだけでなく、多くのプログラミング言語で自動的に読み込んで処理できます。

例)


{"data":
    [
    {"name":"ダージリン","price":600},
    {"name":"アールグレイ","price":550}
    ]
}

「data」階層の中に配列があり、配列として複数の要素が入っている3階層の構造で、3階層目の要素の中に「name」と「price」という2つの属性があります。

Swiftは、JSONデータを自動的に読み込んで処理できます。

XMLとJSONを扱えるアプリをSwiftで作る

データ形式がわかったところで実際にネット上にあるデータをアプリにダウンロードして、データを表示するアプリを作成しましょう。XMLやJSONはデータサイズが大きくなりやすいので、ダウンロード待ちがない非同期ダウンロードを使います。

1. XMLを解析する方法

XMLの解析にはSwiftの命令「NSXMLParser」を使います。ダウンロードしたテキストデータを先頭から順番に読み進めて、階層データを含むタグを判断します。

XMLをSwiftで使えるデータとして読み込むには、XMLのデータ構造に応じた解析プログラムが必要です。XMLが複雑になるほど、解析プログラムも複雑になるデメリットがあります。

1)Xcodeのメニュー「File」→「New」→「Project」から「Single View Application」を選択して、新規プロジェクトを作成しましょう。

2)Webにダウンロード用のXMLデータをアップします。データ構造にあわせてプログラミングする必要があるので、今回は以下のデータを使います。


<?xml version="1.0" encoding="UTF-8"?>
<data>     
    <tea name="ダージリン" price="600"/>
    <tea name="アールグレイ" price="550"/>
</data>

※サンプルファイル http://editors.ascii.jp/c-minamoto/swift/swift-5-data.xml で代用できます。

3)画面に[Button]と[textView]を配置して、アプリ画面を作ります。

「Main.storyboard」を選択し、右下のライブラリから[Button]と[textView]をドラッグ&ドロップして配置します。 右下の「|△|」ボタンを押して、「Reset to Suggested Constraints(自動レイアウト設定)」を選択します。

「Main.storyboard」の仮画面の中央にボタンを配置しただけでは、縦長のiPhone画面で見るとボタンが端に表示されてしまいます。自動レイアウト設定をすることで、縦長の画面でも中央に表示されます。

4)[textView]に名前をつけてコントロールします。

メニュー「View」→「Assitant Editor」→「Show Assistant Editor」を選択して、「アシスタントエディター」を表示し、キーボードのcontrolを押しながら、[textView]をViewController.swiftへドラッグして、名前を「myTextView」とします。

ViewControll.swiftにコード、


@IBOutlet weak var myTextView: UITextView!

が追加されます。

5)ボタンが押されたときに実行される関数を作ります。

ボタンが押されたときの命令を記述するための関数を作ります。

キーボードのcontrolを押しながら「Button」をViewController.swiftへドラッグし、「Connection」を「Action」に切り換えてボタンを押したとき実行する関数を作ります。関数名は「tapBtn」にします。

6)ViewController.swiftに、プログラムを記述します。

ボタンが押されたときにサーバーからデータをダウンロードして解析し、アプリに表示するプログラムを記述します。

テキストデータのURLを用意して、19行目「sendAsynchronousRequest」で非同期ダウンロードを実行します。データの読み込みが終わったら、22行目「dispXML関数」が呼び出され、33行目「parser!.parse()」でXML解析を開始します。

XMLの解析を開始したら、タグ情報が見つかるたびにparser関数が自動的に呼ばれます。

開始タグが見つかったら、42行目「parser関数 didStartElement」が呼び出されるので、タグがdataならば、data階層に入ったことがわかるようにXMLtag1変数に「data」という文字列を格納して、判断できるようにします。

タグteaが見つかったときに、判断用に保存していたXMLtag1を見てdataの階層に入っていることがわかったら、tea要素から属性を取りだして「表示用変数 msg」に追加します。

終了タグが見つかったら、60行目「parser関数 didEndElement」が呼び出され、解析したデータを「myTextView」に表示します。

また、XMLデータの読み込みを確認するために、読み込みが完了したときに呼ばれるdispXML関数の中で、26行目「println文」を使ってデバッグエリアへXMLデータを出力します。

記述したプログラムは以下の通りです。


//(中略)
class ViewController: UIViewController, NSXMLParserDelegate{

    @IBAction func tapBtn(sender: AnyObject) {
        let url:NSURL = NSURL(string: "http://editors.ascii.jp/c-minamoto/swift/swift-5-data.xml")!
        let request = NSURLRequest(URL: url)
        // 読み込みが終わったらdispXML関数を呼ぶ
        NSURLConnection.sendAsynchronousRequest(request, queue: .mainQueue(), completionHandler: self.dispXML)
    }
    // 読み込みが終わったら行う関数
    func dispXML(response:NSURLResponse?, data:NSData?, error:NSError?) {
        if data != nil {
            // チェックのため、読み込んだデータをそのまま表示
            let myString = NSString(data:data!, encoding: NSUTF8StringEncoding) as! String
            println(myString)
            
            // XMLの解析を開始
            let parser:NSXMLParser? = NSXMLParser(data: data!)
            if parser != nil   {
                // 解析が進んだら、parser関数を呼び出すようにする
                parser!.delegate = self;
                parser!.parse()
            }
        }
    }
    // 1階層目のタグを覚えておく変数を用意
    var XMLtag1: String! = ""
    // 表示するメッセージを入れる変数
    var msg:String = ""
    // タグの最初が見つかったら呼ばれる関数
    func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [NSObject : AnyObject]) {
        // タグが「data」なら「dataタグ」に入ったことをXMLtag1に覚えておく
        if elementName == "data" {
            XMLtag1 = "data"
        }
        // タグが「tea」で、すでに「dataタグ」に入った状態なら、その中のデータを取り出す
        if elementName == "tea" && XMLtag1 == "data" {
            // 属性「name」の文字を取りだしてmsg変数に追加
            if let teaName = attributeDict["name"] as? String {
                msg += "名前=\(teaName)\n"
            }
            // 属性「price」の文字を取りだしてmsg変数に追加
            if let teaPrice = attributeDict["price"] as? String {
                msg += "価格=\(teaPrice)\n"
            }
        }
    }
    // タグの終わりが見つかったら呼ばれる関数
    func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        // タグが「data」なら タグが閉じられたので、XMLtag1をリセットして、メッセージを表示
        if elementName == "data" {
            XMLtag1 = ""
            myTextView.text = msg
        }
    }
//(中略)

ボタンを押すと、データが読み込まれて解析され、「textView」に表示されます。

Xcodeの下に表示されているデバッグエリアを確認してみましょう。XMLデータが読み込まれていることがわかります。

この連載の記事

一覧へ
Web Professionalトップページバナー

この記事の編集者は以下の記事をオススメしています

ASCII.jp会員サービス 週刊Web Professional登録

Webディレクター江口明日香が行く