공공데이터포털 API를 통해 데이터를 가져오면 보통 JSON/XML 형식으로 가져오는데 ( 요즘은 JSON을 많이 쓰지만.. )
XML로 데이터를 가져오는 경우, 원하는 태그의 데이터를 추출하는 방법을 정리하려고 한다.
해당글에서는 2가지 방법을 소개하려고 한다.
1) 특정태그의 데이터를 1개 가져오는 방법
2) 특정태그의 데이터를 여러개 가져오는 방법
틀린 게 있을 수도 있지만, 그냥 정리하는 겸 쓴 글이기도 하고 어떤 사람들에게는 도움이 될 수도 있다고 생각한다.
우선 샘플로 사용 할 데이터는 공공데이터포털에서 제공하는 기상청_지상(종관, ASOS) 일자료 조회서비스이다.
자세한 내용을 보고싶은 사람은 아래 링크를 통해 이동하여 확인하도록 하자.
기상청_지상(종관, ASOS) 일자료 조회서비스로 이동
샘플URL ( 기상청_지상(종관, ASOS) 일자료 조회서비스 Doc에서 제공 )
http://apis.data.go.kr/1360000/AsosDalyInfoService/getWthrDataList
?serviceKey=인증키&numOfRows=10&pageNo=1
&dataCd=ASOS&dateCd=DAY&startDt=20100101&endDt=20100102&stnIds=108
위의 URL에 본인의 인증키를 그대로 넣고 주소창에 치면 데이터를 확인할 수 있다. 나는 이걸 사용 할 예정이다.
위의 URL을 통해 실제 가져온 데이터
XML데이터에서 원하는 태그의 데이터를 가져오는 방법
1. xPath를 통해 XML태그의 데이터를 가져오는 방법
샘플코드
package app.model.com;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class XmlExample {
public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException, XPathExpressionException {
/**
* testUrl : 공공데이터포털 기상청_지상(종관, ASOS) 일자료 조회서비스 샘플 URL
* result : 받아온 데이터(XML)를 문자열로 받을 변수
* line : 받아온 데이터값을 읽을 변수
*/
String testUrl = "http://apis.data.go.kr/1360000/AsosDalyInfoService/getWthrDataList?serviceKey=인증키&pageNo=1&numOfRows=10&dataType=XML&dataCd=ASOS&dateCd=DAY&startDt=20210101&endDt=20220601&stnIds=108";
String result = "";
String line = "";
/**
* URL 생성 및 openStream()를 통해 서버통신
* bf에 공공데이터포털에서 받아온 데이터를 적재
* bf에서 데이터를 읽어들여 값이 null이 될때까지 반복하여
* line을 result에 concat해줌
*/
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(testUrl);
URL url = new URL(urlBuilder.toString());
BufferedReader bf;
bf = new BufferedReader(new InputStreamReader(url.openStream()));
while((line = bf.readLine())!=null) {
result = result.concat(line);
}
/**
* 받아온 xml문자열인 result을 가지고 Document인 xml을 선언
* xpath를 통해 원하는 태그의 데이터를 각 String변수에 담음
* 여기서 데이터 태그에 맞는 자식노드를 작성해주어야함..
* stnNm 라는 데이터를 가져오기 위해서는 //response//body//items//item//stnNm와 같이 작성
*/
Document xml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(result.getBytes()));
xml.getDocumentElement().normalize();
XPath xpath = XPathFactory.newInstance().newXPath();
String stnNm = (String)xpath.evaluate("//response//body//items//item//stnNm", xml, XPathConstants.STRING);
String tm = (String)xpath.evaluate("//response//body//items//item//tm", xml, XPathConstants.STRING);
String maxTaHrmt = (String)xpath.evaluate("//response//body//items//item//maxTaHrmt", xml, XPathConstants.STRING);
/**
* 받아온 데이터를 출력함
*/
System.out.println(stnNm);
System.out.println(tm);
System.out.println(maxTaHrmt);
}
}
결과화면
근데 이렇게 xpath를 통해 데이터를 String에 넣으면 데이터를 하나씩밖에 못가져온다..
보통 우리가 데이터를 가져올 때, 몇백건이든 몇천건이든 많은 데이터를 가져오는데.. 그렇게 가져오려면
아래와 같이 반복문을 통해 nodeList에서 각 데이터를 추출하고 넣어줘야 한다.
2. 여러개의 태그 데이터를 가져오는 방법
샘플코드
package app.model.com;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class XmlExample {
public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException, XPathExpressionException {
/**
* testUrl : 공공데이터포털 기상청_지상(종관, ASOS) 일자료 조회서비스 샘플 URL
* result : 받아온 데이터(XML)를 문자열로 받을 변수
* line : 받아온 데이터값을 읽을 변수
* xmlMap : 추출한 문자열을 담을 Map
* resultList : xmlMap을 담을 List
*/
String testUrl = "http://apis.data.go.kr/1360000/AsosDalyInfoService/getWthrDataList?serviceKey=인증키&pageNo=1&numOfRows=10&dataType=XML&dataCd=ASOS&dateCd=DAY&startDt=20210101&endDt=20220601&stnIds=108";
String result = "";
String line = "";
HashMap<String, String> xmlMap = new HashMap<String, String>();
ArrayList<Map<String, String>> resultList = new ArrayList<Map<String, String>>();
/**
* URL 생성 및 openStream()를 통해 서버통신
* bf에 공공데이터포털에서 받아온 데이터를 적재
* bf에서 데이터를 읽어들여 값이 null이 될때까지 반복하여
* line을 result에 concat해줌
*/
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(testUrl);
URL url = new URL(urlBuilder.toString());
BufferedReader bf;
bf = new BufferedReader(new InputStreamReader(url.openStream()));
while((line = bf.readLine())!=null) {
result = result.concat(line);
}
/**
* 받아온 xml문자열인 result을 가지고 Document인 xml을 선언
* xpath의 경로는 자신이 가져올 데이터들을 포함하는 태그임
* 실제 XML트리를 보면서 이해하면 될 것 같음
*/
Document xml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(result.getBytes()));
xml.getDocumentElement().normalize();
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nodeList = (NodeList) xpath.evaluate("//response//body//items//item", xml, XPathConstants.NODESET);
/**
* item태그에서 원하는 데이터 3가지를 지정함
* 1) stnNm : 지점명
* 2) tm : 시간
* 3) maxTaHrmt : 최저기온 시각
*/
String stnNm = "";
String tm = "";
String maxTaHrmt = "";
/**
* nodeList의 길이만큼 반복문을 돌림. ( 10개의 item이 있을 경우, 10회 반복.. )
* 각 node를 Element객체인 eElement로 선언
* getElementsByTagName()를 통해 원하는 태그 값의 0번째 값을 getTextContent()로
* Stirng 문자열로 추출하여 각 String 변수에 적재함
* getElementsByTagName() 안의 파라메터는 실제 XML트리의 item태그 안의 태그를 의미함..
* 이해 안되면 직접 XML트리를 보면서 테스트 해보면 될 듯 함..
*/
for (int index = 0; index < nodeList.getLength(); index++) {
Element eElement = (Element) nodeList.item(index);
/**xmlMap 생성자 초기화*/
xmlMap = new HashMap<String, String>();
/**각 값을 적재*/
stnNm = eElement.getElementsByTagName("stnNm").item(0).getTextContent();
tm = eElement.getElementsByTagName("tm").item(0).getTextContent();
maxTaHrmt = eElement.getElementsByTagName("maxTaHrmt").item(0).getTextContent();
/**가져온 값을 xmlMap에 put 해줌*/
xmlMap.put("stnNm", stnNm);
xmlMap.put("tm", tm);
xmlMap.put("maxTaHrmt", maxTaHrmt);
/**xmlMap을 List에 add해줌*/
resultList.add(xmlMap);
}
/**resultList를 콘솔에 출력해줌*/
System.out.println(resultList);
}
}
결과화면
이렇게 하면 <item>이라는 태그를 여러개 가져올 수 있다. 객체 형태로 배열에 담았으니,
필요한 곳에서 꺼내 쓰면 될 것 같다..
코드가 너무 길어져서 읽기 싫을 수도 있지만.. 막 어려운 코드는 아니니 필요한 사람들은 코드를 직접 디버깅 걸어서
하나하나 보면서 이해해보도록 하자..