deprecated/코로나 알림(project-ios)

Swift XML Parsing (OpenAPI)

lgvv 2021. 7. 21. 11:49

Swift5 Open API - xml parsing

 

공공 데이터를 이용한 코로나 open api를 통해 XML parsing에 대해서 알아볼 예정.

 

목차

1. 공공 데이터 open API 사용하는 방법

2. 전체 코드 및 사용법에 대한 설명

 

✅ 1. 공공 데이터 open API 사용하는 방법

 

1. 공공데이터 포털에 접속한다(https://www.data.go.kr/index.do)

1. 공공데이터 포털에 접속한다(https://www.data.go.kr/index.do)

 

2. 공공데이터 포털에서 [코로나]를 검색하고, 아래에 보이는 것을 신청

    • 이미 신청완료한 상태라 마이페이지에서 확인한 모습!
    • 신청 후 즉시 되는 건 아니고 약간의 시간이 흘러야 가능 (금방 처리)

 

 

이번에 사용할 데이터

 

 

3. 공공데이터 활용 지원센터를 클릭해서 상세보기

여기서 중요한 것은 [참고문서] 부분에서 워드 파일을 다운받아서 어떻게 사용되는지 직접 읽어보는 것이 중요.

3. 공공데이터 활용 지원센터를 클릭해서 상세보기!

 


4. 워드 파일을 열어본 후 - 문서를 내려 요청 메시지와 응답 메시지 부분을 확인하기

이걸 확인하는 이유는 우리가 요청했을 때 응답 메시지가 어떻게 내려오는 지 알아서 우리가 xml 파싱에서 구조를 활용할 수 있음.

요청 메시지와 응답메시지

 

요청 메시지 부분을 보면 인증키라고 있는데, 마이페이지에서 Encoding 부분에 내가 발급받은 키 부분을 넣어주면 된다.

마이페이지에서 - 오픈API - 개발계정 창에 들어가면 Encoding 부분이 나옴.

❗️API 요청시 필수 파라미터 부분을 누락하면 초기에는 요청이 가능하나 시간이 지나면 제대로 요청이 되지 않음.

 

 

✅ 2. 전체 코드 및 사용법에 대한 설명

//
//  ViewController.swift
//  Covid19AlarmApp
//
//  Created by Hamlit Jason on 2021/07/20.
//

import UIKit

enum TagType {
    case createDt
    case deathCnt
    case defCnt
    case gubun
    case gubunCn
    case gubunEn
    case incDec
    case isolClearCnt
    case isolIngCnt
    case localOccCnt
    case overFlowCnt
    case qurRate
    case seq
    case stdDay
    case none
}

struct item {
    var createDt: String
    var deathCnt: String
    var defCnt: String
    var gubun: String
    var gubunCn: String
    var gubunEn: String
    var incDec: String
    var isolClearCnt: String
    var isolIngCnt: String
    var localOccCnt: String
    var overFlowCnt: String
    var qurRate: String
    var seq: String
    var stdDay: String
    
    init() {
        createDt = ""
        deathCnt = ""
        defCnt = ""
        gubun = ""
        gubunCn = ""
        gubunEn = ""
        incDec = ""
        isolClearCnt = ""
        isolIngCnt = ""
        localOccCnt = ""
        overFlowCnt = ""
        qurRate = ""
        seq = ""
        stdDay = ""
    }
    
}

class ViewController : UIViewController, XMLParserDelegate {

    var isLock = true
    var tagType : TagType = .none
    var tempModel : item?
    var books: [item] = []
    
    override func viewDidLoad() {
        var parser : XMLParser
        var yourKey = "" // 공공 데이터 포털에서 발급받은 개인 키
        var url = URL(string: "http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19SidoInfStateJson?serviceKey=\(yourKey)")
        parser = XMLParser(contentsOf: url!)!
        parser.delegate = self
        parser.parse()
    }
    
    ///MARK ::: LOGIC
    
    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
        // 태그의 시작
        
        if elementName == "item" {
            isLock = true
            tempModel = item.init()
        } else if elementName == "createDt" {
            tagType = .createDt
        } else if elementName == "deathCnt" {
            tagType = .deathCnt
        } else if elementName == "defCnt" {
            tagType = .defCnt
        } else if elementName == "gubun" {
            tagType = .gubun
        } else if elementName == "gubunCn" {
            tagType = .gubunCn
        } else if elementName == "gubunEn" {
            tagType = .gubunEn
        } else if elementName == "incDec" {
            tagType = .incDec
        } else if elementName == "isolClearCnt" {
            tagType = .isolClearCnt
        } else if elementName == "isolIngCnt" {
            tagType = .isolIngCnt
        } else if elementName == "localOccCnt" {
            tagType = .localOccCnt
        } else if elementName == "overFlowCnt" {
            tagType = .overFlowCnt
        } else if elementName == "qurRate" {
            tagType = .qurRate
        } else if elementName == "seq" {
            tagType = .seq
        } else if elementName == "stdDay" {
            tagType = .stdDay
        } else {
            tagType = .none
        }
    }
    
    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        if elementName == "item" {
            guard let tempModel = tempModel else {
                return
            }
            books.append(tempModel)
            isLock = false
        } else {
            print("----- didEndElement (else)-----")
        }
    }
    
    func parser(_ parser: XMLParser, foundCharacters string: String) {
        let parseString = string.trimmingCharacters(in: .whitespacesAndNewlines)
        if isLock {
            switch tagType {
            case .createDt:
                tempModel?.createDt = parseString
            case .deathCnt:
                tempModel?.deathCnt = parseString
            case .defCnt:
                tempModel?.defCnt = parseString
            case .gubun:
                tempModel?.gubun = parseString
            case .gubunCn:
                tempModel?.gubunCn = parseString
            case .gubunEn:
                tempModel?.gubunEn = parseString
            case .incDec:
                tempModel?.incDec = parseString
            case .isolClearCnt:
                tempModel?.isolClearCnt = parseString
            case .isolIngCnt:
                tempModel?.isolIngCnt = parseString
            case .localOccCnt:
                tempModel?.localOccCnt = parseString
            case .overFlowCnt:
                tempModel?.overFlowCnt = parseString
            case .qurRate:
                tempModel?.qurRate = parseString
            case .seq:
                tempModel?.seq = parseString
            case .stdDay:
                tempModel?.stdDay = parseString
            case .none: break
            }
        }
        
    }
    
    @IBAction func tap(_ sender: Any) {
        for i in 0..<books.count {
            print(books[i])
        }
        print(books.count)
    }
    
}

 

XML Parser는 크게 3가지 부분으로 나뉨

 

xml은 마크 다운 언어임으로 주로 이렇게 작성되어 있는데

<title> 안녕하세요 내용입니다 </title>

// 태그의 시작
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:])

// 태그의 끝
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?)

// 태그 안의 내용
func parser(_ parser: XMLParser, foundCharacters string: String)

 

이렇게 세가지 함수로 파싱을 진행 가능.

  • 태그의 시작같은 경우에는 "title"이 호출되고
  • 태그안의 내용에는 "안녕하세요 내용입니다"가 호출 돼
  • 태그의 끝에는 "title"이 호출되게 된다.

✅ 향후 코드에는 API키를 보호해야 함으로 .gitignore로 파일을 관리하거나 백엔드에서 키를 받아와서 사용하는 방식을 채택한다면 더욱 안전한 프로그래밍을 할 수 있을 것으로 생각된다.