【Swift】XMLParserについて

XMLParserについてまとめました。
Yahoo! RSS（ https://news.yahoo.co.jp/pickup/rss.xml ）を使用して、最新の記事の情報を取得します。

#解析するXMLについて
Yahoo! RSSのXMLは以下のようになっています。

```
<rss xmlns:blogChannel="http://backend.userland.com/blogChannelModule" version="2.0">
　　　<channel>
　　　　　　<title>Yahoo!ニュース・トピックス - 主要</title>
　　　　　　<link>https://news.yahoo.co.jp/</link>
　　　　　　<description>Yahoo! JAPANのニュース・トピックスで取り上げている最新の見出しを提供しています。</description>
　　　　　　<language>ja</language>
　　　　　　<pubDate>Sun, 11 Aug 2019 02:17:25 +0900</pubDate>
　　　　　　<item>
　　　　　　　　　<title>記事のタイトル</title>
　　　　　　　　　<link>記事のURL(Link)</link>
　　　　　　　　　<pubDate>配信時間</pubDate>
　　　　　　　　　<enclosure length="133" url="https://s.yimg.jp/images/icon/photo.gif" type="image/gif"> 　　　　　　　　　</enclosure>
　　　　　　　　　<guid isPermaLink="false">記事のURL(PermaLink)</guid>
　　　　　　</item>
　　　　　　<item>・・・</item>
　　　</channel>
</rss>

```
今回は、記事のタイトルとURLの情報がほしいため、< title >と< link >の要素を取得します。


#XMLの取得
ViewControllerにXMLParserDelegateプロトコルを実装させます。

```
class ViewController: UIViewController, XMLParserDelegate, UITableViewDataSource, UITableViewDelegate {

}
```

URLSessionを使用し、XMLをDataで取得します。
取得後にDataの中身を解析します。

```
let url: URL = URL(string:"https://news.yahoo.co.jp/pickup/rss.xml")!

let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
　　　let parser: XMLParser? = XMLParser(data: data!)
　　　parser!.delegate = self
　　　parser!.parse()
})
//タスク開始
task.resume()
```



#XMLParserの解析処理
要素の取得時に呼び出される関数から、記事のタイトル等の値を取得します。

```
var check_title = [String]()
var news_title = [String]()
var link = [String]()
var enclosure = [String]()
var check_element = String()

//解析_開始時
func parserDidStartDocument(_ parser: XMLParser) {
        
}
    
    
//解析_要素の開始時
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
    if elementName == "enclosure" {
        enclosure.append(attributeDict["url"]!)
    }
    check_element = elementName
}
    
//解析_要素内の値取得
func parser(_ parser: XMLParser, foundCharacters string: String) {
    if string != "\n" {
        if check_element == "title" {
            //要素がtitleの場合値を取得する
            check_title.append(string)
        }

        if check_element == "link" {
            //要素がlinkの場合値を取得する
            link.append(string)
        }
    }
}
    
//解析_要素の終了時
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
    if check_element == "title" {
        var title = check_title[0]
        for i in 1..<check_title.count {
            //titleの値が複数取得された場合一つにまとめる
            title = title + check_title[i]
        }
        check_title = [String]()
        news_title.append(title)
    }
}
    
//解析_終了時
func parserDidEndDocument(_ parser: XMLParser) {
![undefined]()

}
    
//解析_エラー発生時
func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
    print("エラー:" + parseError.localizedDescription)
}
```

#実行結果
XMLParserで取得した値から記事の一覧を表示しています。
タイトルを選択するとUIWebViewで記事の内容を表示します。

![実行結果.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431502/c34bf115-7f5e-b972-0db6-97a9a0fe1ad7.gif)


[ソースコード](https://github.com/MoriyamaNaoki/rss_ios)



#参考
https://developer.apple.com/documentation/foundation/xmlparserdelegate
https://mizumotok.hatenablog.jp/entry/2018/04/13/001002