Swift でXMLパースしてみました。

# Swift でXMLパース

## Overview

swiftでXMLパースをしてみました。

OSSでは下記を見つけました

- [yahoojapan/SwiftyXMLParser](https://github.com/yahoojapan/SwiftyXMLParser)
- [drmohundro/SWXMLHash](https://github.com/drmohundro/SWXMLHash)

上記2点以外にもXMLパーサーは存在しているかもしれませんが、

今回はこの2点を列挙させていただきました。

実際にパースしてみたのは drmohundro/SWXMLHash になります。
yahoojapanのXMLパーサーも影響を受けたそうですので、こちらにしてみました。

## Use it

### Cocoapods

To install CocoaPods, run:

```
$ gem install cocoapods
```

```vim:Podfile
platform :ios, '10.0'
use_frameworks!

target 'YOUR_TARGET_NAME' do
  pod 'SWXMLHash', '~> 4.0.0'
end
```

Podfileに上記を記述し、下記を実行します。

```bash

$ pod install
```

通信クラスには下記を使います

[keisukeYamagishi/HttpSession](https://github.com/keisukeYamagishi/HttpSession)

TCP / IP based HTTP communication can be simplified

なのでPodfileは下記のようにします。

```vim:Podfile
platform :ios, '10.0'
use_frameworks!

target 'YOUR_TARGET_NAME' do
  pod 'SWXMLHash', '~> 4.0.0'
  pod 'HttpSession'
end
```

```bash

$ pod install
```

下記のようなXMLをパースする場合の使い方になります。

```xml

<rest order="0">
<id>6363054</id>
<update_date>2017-12-10 05:04:30</update_date>
<name>餃子の安亭 新宿店</name>
<name_kana>ギョウザノアンテイシンジュクテン</name_kana>
<latitude>35.690078</latitude>
<longitude>139.702786</longitude>
<category>餃子</category>
<url>
https://r.gnavi.co.jp/efk1099b0000/?ak=Dil4xinerVDUdo2%2BMpaU4uwlSorYa1jve%2BRSBbdUIAQ%3D
</url>
<url_mobile>
http://mobile.gnavi.co.jp/shop/6363054/?ak=Dil4xinerVDUdo2%2BMpaU4uwlSorYa1jve%2BRSBbdUIAQ%3D
</url_mobile>
<coupon_url>
<pc/>
<mobile/>
</coupon_url>
<image_url>
<shop_image1/>
<shop_image2/>
<qrcode>https://c-r.gnst.jp/tool/qr/?id=6363054&q=6</qrcode>
</image_url>
<address>〒160-0023 東京都新宿区西新宿1-2-1 ファイブKビル2F</address>
<tel>03-5323-8228</tel>
<tel_sub/>
<fax/>
<opentime>
11:30～15:00(L.O.14:45)(平日)、17:00～23:30(L.O.23:00)(平日)<BR>土・日・祝日 11:30～23:30(L.O.23:30)(ランチ～14:30)
</opentime>
<holiday/>
<access>
<line>都営大江戸線（環状部）</line>
<station>新宿西口駅</station>
<station_exit>D3口</station_exit>
<walk>徒歩1</walk>
<note/>
</access>
<parking_lots/>
<pr>
<pr_short/>
<pr_long/>
</pr>
<code>
<areacode>AREA110</areacode>
<areaname>関東</areaname>
<prefcode>PREF13</prefcode>
<prefname>東京都</prefname>
<areacode_s>AREAS2120</areacode_s>
<areaname_s>新宿西口・都庁前</areaname_s>
<category_code_l order="0">RSFST14000</category_code_l>
<category_name_l order="0">中華</category_name_l>
<category_code_s order="0">RSFST14008</category_code_s>
<category_name_s order="0">餃子</category_name_s>
<category_code_l order="1"/>
<category_name_l order="1"/>
<category_code_s order="1"/>
<category_name_s order="1"/>
</code>
<budget/>
<party/>
<lunch/>
<credit_card/>
<e_money/>
<flags>
<mobile_site>1</mobile_site>
<mobile_coupon>0</mobile_coupon>
<pc_coupon>0</pc_coupon>
</flags>
</rest>

```

パースしたいxmlの構造を下記のようにコーディングします。

これを配列として扱ってやるとやってくれます。

```swift

public struct Rest: XMLIndexerDeserializable {
    var name: String = ""
    var latitude: String = ""
    var longitude: String = ""
    var address: String = ""
    var url: String = ""
    init(name: String, latitude:String, longitude: String, address:String, url:String){
        self.name = name
        self.latitude = latitude
        self.longitude = longitude
        self.address = address
        self.url = url
    }
    public static func deserialize(_ node: XMLIndexer) throws -> Rest {
        return try Rest (
            name: node["name"].value(),
            latitude: node["latitude"].value(),
            longitude: node["longitude"].value(),
            address: node["address"].value(),
            url: node["url"].value()
        )
    }
}

let r: [Rest] = try xml["response"]["rest"].value()

```

全体像はこんな感じです。

```swift

//
//  ViewController.swift
//  DEMO
//
//  Created by Shichimitoucarashi on 2018/05/06.
//  Copyright © 2018年 keisuke yamagishi. All rights reserved.
///Users/keisukeyamagishi/Code/GAME/DEMO/DEMO/ViewController.swift:42:32: Argument passed to call that takes no arguments

import UIKit
import HttpSession
import SWXMLHash

public struct Rest: XMLIndexerDeserializable {
    var name: String = ""
    var latitude: String = ""
    var longitude: String = ""
    var address: String = ""
    var url: String = ""
    init(name: String, latitude:String, longitude: String, address:String, url:String){
        self.name = name
        self.latitude = latitude
        self.longitude = longitude
        self.address = address
        self.url = url
    }
    public static func deserialize(_ node: XMLIndexer) throws -> Rest {
        return try Rest (
            name: node["name"].value(),
            latitude: node["latitude"].value(),
            longitude: node["longitude"].value(),
            address: node["address"].value(),
            url: node["url"].value()
        )
    }
}

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
      Http(url:"https://api.gnavi.co.jp/RestSearchAPI/20150630/?keyid=ed0508a689013e2c064187189fc3c568&latitude=35.6900488&longitude=139.7028957&", method: .get)
            .session { (data, responce, error) in
                
                do{
                    let xml = SWXMLHash.parse(data!)
                    
                    let r: [Rest] = try xml["response"]["rest"].value()
                    print (r)
                }catch{
                    
                }
                
        }
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
      
}

```