2015/12/13

【Swift】NSXMLParserで文字列にアルファベットや数字、マルチバイト文字が含まれる場合、複数に分かれてパースされる件

SwiftでXMLをパースする際に、
NSXMLParserを使用するのですが、以下のような要素をパースする際に

aaa あいうえお abcd 春夏秋冬 123
マルチバイト+アルファベット文字列が要素内であったとすると、
それぞれ分かれて、一回目aaaで二回目あいうえお、三回目abcdの形で取得できてしまって、
一気に取れないのが不便。
フラグとかはないので手動で配列に貯めてから、閉じタグを読み込んだ時にreduceで再帰的に足して取得する

実装

NSXMLParserDelegateを指定
    var isTitle:Bool=false
    var parsedStrArr:Array<String>!
    var entries : NSMutableArray!
    var tmpEntry : NSMutableArray!

    override func viewDidLoad() {
        super.viewDidLoad()
        loadRss()
    }

    func loadRss() {

        // Sample feed url
        let rUrl: NSURL = NSURL(string: "https://hoge.co.jp/feed/?cat=5")!
        let rssUrl = rUrl

        parser = NSXMLParser(contentsOfURL: rssUrl)!
        parser.delegate = self

        //以下の1行の処理でparse関連の処理が行われる。
        let success:Bool = parser.parse()
        if success {
            print("パース成功")
        } else {
            print("パース失敗")
        }
    }

    // NSXMLParserDelegate
    // ここから下はParse関連処理

    func parserDidStartDocument(parser: NSXMLParser){
        entries = NSMutableArray()
    }

    // 開始タグを読み込んだ時よばれる - Start
    func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [NSObject : AnyObject]) {

        parsedStrArr = []

        if (elementName == "title"){
          // 配列初期化
            tmpEntry = NSMutableArray()
            entries.addObject(tmpEntry)
            isTitle = true;
        }
    }

    //閉じタグを読み込んだ時よばれる - End
    func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {

        if (elementName == "title"){
            // reduceによる再帰処理で文字列を足す
            tmpEntry.addObject(parsedStrArr.reduce(String()) { $0 + $1 })
            isTitle = false
        }
    }

    //タグ以外のテキストを読み込んだ時(タグとタグ間の文字列)
    func parser(parser: NSXMLParser, foundCharacters string: String?) {

        if(isTitle && tmpEntry != nil){
            // タイトル内文字列を追加していく
            parsedStrArr.append(string!)
        }
    }

    func parserDidEndDocument(parser: NSXMLParser){
        // ここで最終処理 entries
    }

参考

[iOS] NSXMLParser で文字列が1つのエレメントで複数に分かれてパースされる
http://www.kuma-de.com/blog/2012-07-20/3782