조앤의 기술블로그

[뉴스리더] 구글 뉴스 RSS xml 파싱하기(iOS, Swift) 본문

Programming/프로젝트

[뉴스리더] 구글 뉴스 RSS xml 파싱하기(iOS, Swift)

쬬앤 2020. 4. 7. 12:00

뉴스 리더 앱을 만들 때 xml파싱 필요.

참고할만한 좋은 예제를 발견했다. 

 

https://github.com/arled/swift-rss-reader-example

 

arled/swift-rss-reader-example

An RSS reader example app written in Swift. Contribute to arled/swift-rss-reader-example development by creating an account on GitHub.

github.com

(고마우신 분..... 인상 좋으시네..)

이 예제를 따라서 구글 뉴스 RSS를 파싱해보겠다. 

 

 

xml 파싱은 XmlParserManager.swift 파일에서 한다. 

이 class는 NSObject, XMLParserDelegate를 상속한다. 

 

 

파싱한 요소들을 저장할 변수들을 선언한다. 

 

파싱을 시작하기 위한 함수들

//initialize parser
    func initWithURL(_ url : URL) -> AnyObject {
        startParse(url)
        return self
    }
    
    func startParse(_ url: URL) {
        feeds = []
        parser = XMLParser(contentsOf: url)!
        parser.delegate = self
        parser.shouldProcessNamespaces = false
        parser.shouldReportNamespacePrefixes = false
        parser.shouldResolveExternalEntities = false
        parser.parse()
       
    }

 

parser 함수 - didStartElement, didEndElement, foundCharacters 세가지가 필요하다. 

 

[didStartElement]

시작 태그를 발견하면 호출하여 텍스트 요소들을 읽는다. 

 func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
        element = elementName as NSString
        if (element as NSString).isEqual(to: "item") {
            elements = NSMutableDictionary()
            elements = [:]
            ftitle = NSMutableString()
            ftitle = ""
            link = NSMutableString()
            link = ""
            fdescription = NSMutableString()
            fdescription = ""
            fdate = NSMutableString()
            fdate = ""
        } else if (element as NSString).isEqual(to: "enclosure") {
            if let urlString = attributeDict["url"] {
                img.append(urlString as AnyObject)
            }
        }
    }
    

 

 

[didEndElement]

종료 태그를 발견하면 호출하여 지금까지 읽어들인 텍스트 요소를 확정시킨다. 

func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        if (elementName as NSString).isEqual(to: "item"){
            if ftitle != "" {
                elements.setObject(ftitle, forKey: "title" as NSCopying)
            }
            if link != "" {
                elements.setObject(link, forKey: "link" as NSCopying)
            }
            if fdescription != "" {
                elements.setObject(fdescription, forKey: "description" as NSCopying)
                //print("desc", fdescription)
            }
            if fdate != "" {
                elements.setObject(fdate, forKey: "pubDate" as NSCopying)
            }
            feeds.add(elements)
        }
    }

 

[foundCharacters]

현재 나에게 필요한 텍스트 요소를 발견하면 호출하여 필요한 텍스트 요소를 저장한다. 

 func parser(_ parser: XMLParser, foundCharacters string: String) {
        if element.isEqual(to: "title"){
            ftitle.append(string)
        } else if element.isEqual(to: "link"){
            link.append(string)
        } else if element.isEqual(to: "descriptioin"){
            fdescription.append(string)
        } else if element.isEqual(to: "pubDate"){
            fdate.append(string)
        }
    }

 

여기까지 XmlParserManager.swift의 구성이다. 

 

뉴스 피드를 출력하는 부분인 FeedListViewController.swift 의 구성을 살펴보겠다. 

# part 1.

override func viewDidLoad() {
        super.viewDidLoad()
        //tableView.estimatedRowHeight = 140
        loadData()
    }
   
    func loadData() {
        url = URL(string: "https://news.google.com/rss?hl=ko&gl=KR&ceid=KR:ko")
        loadRss(url)
    }
    
    func loadRss(_ data: URL) {
        let myParser : XmlParserManager = XmlParserManager().initWithURL(data) as! XmlParserManager
        //put feed in array
        myFeed = myParser.feeds
        tableView.reloadData()
    }

 

#part 2. 뉴스의 타이틀만 출력하도록 구현하였다. 

 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return myFeed.count
    }

   
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "ListCell") as! NewsCell
     
        cell.title?.text = (myFeed.object(at: indexPath.row) as AnyObject).object(forKey: "title") as? String
        //cell.contents?.text = (myFeed.object(at: indexPath.row) as AnyObject).object(forKey: "description") as? String
        //cell.thumbnail?.image
        
        return cell
    }