공공데이터를 활용하는 방법에는
1. 공공데이터 사이트에서 파일을 다운받아 파싱
2. 온라인에서 바로 파싱
이번에는 1. 다운받은 파일을 파싱하는 법을 알아보자.

0. 파일 넣기
- 우선 다운받은 파일을 프로젝트의
src/webapp/WEB-INF 에 파일을 만들어서 넣어준다.
commands.properties
- url=핸들러 주소
- url은 인식하기 편하게 지정해준다. url로 불러올 핸들러 주소만 명확하다면 오케이.
/csv/load.do=handler.CsvHandler
/json/load.do=handler.JsonHandler
/xml/load.do=handler.XmlHandler
index
- commands.properties에 적은 url을 적어준다.
- url로 불러올 클래스가 핸들러 클래스이기 때문에 현 프로젝트 주소를 반영하는 ${pageContext.request.contextPath} 꼭 적어주기.
- jsp로의 이동은 필요 없다~
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>공공데이터 활용</h3>
<a href="${pageContext.request.contextPath}/csv/load.do">csv 데이터 확인</a><br/>
<a href="${pageContext.request.contextPath}/json/load.do">json 데이터 확인</a><br/>
<a href="${pageContext.request.contextPath}/xml/load.do">xml 데이터 확인</a><br/>
</body>
</html>
1. CSV 파일
- 엑셀 형태의 파일.
- ","로 값이 나눠져 있음.
- 엔터(\n)로 한 객체의 정보가 나뉜다.



- 년월, 요일, 상_하행, 열차번호 등 같은 양식으로 여러 값이 들어있으므로 루프문을 돌릴 필요가 있다.
--> 루프 문 돌려 리스트에 담을 때 한 줄 당 Vo에 넣어 리스트에 넣으면 jsp에서 출력 루프문 돌릴 때 좋다.
==> VO 생성
public class Vo {
private String arg1;
private String arg2;
private String arg3;
private String arg4;
private String arg5;
private String arg6;
private String arg7;
private String arg8;
private String arg9;
private String arg10;
private String arg11;
private String arg12;
}
- Handler interface를 상속받은 Handler 클래스를 생성한다. -- 여기서 csv 파일을 파싱해서 jsp 페이지로 데이터를 전송할 것.
String path = request.getServletContext().getRealPath("/WEB-INF/files/a_utf8.csv");
FileReader fr = new FileReader(path);
char[] buf = new char[10000];
fr.read(buf);
String str = new String(buf);
String[] data = str.split("\n");
String[] titles = data[0].split(",");
ArrayList<Vo> list = new ArrayList<>();
for (int i = 1; i < data.length; i++) {
String[] vals = data[i].split(",");
if(vals.length<12) {
continue;
}
list.add(new Vo(vals[0], vals[1], vals[2], vals[3], vals[4], vals[5],
vals[6], vals[7], vals[8], vals[9], vals[10], vals[11]));
}
request.setAttribute("titles", titles);
request.setAttribute("list", list);
fr.close();
return "/csv/list.jsp";
(1) 파라메터에 담은 경로를 웹에서 사용하는 실제 경로로 반환해 String path에 담는다.
--- getServletContext() : 서블릿 클래스와 서블릿 컨테이너(톰캣) 간 통신을 위한 메소드들을 정의해둔 클래스
--- getRealPath() : getServletContext의 메서드 중 하나. 주어진 디렉토리(폴더)의 실제 실행되는 서버상의 주소를 절대경로로 알려줌.
(2) csv 파일은 문자 타입이므로 Filereader로 스트림을 생성한다. -- 파일 읽어들일 준비.
(3) char[] 배열에 파일 내용을 한 줄로 읽음
- char 은 문자 1개씩 읽는 문자타입임. 즉, char[10000]은 만 자의 문자를 한 배열에 담겠다는 뜻.
(4) path에 있는 파일을 char[] 크기만큼 읽어들여 담는다.
- 파일 내용이 10000자보다 많으면 루프를 돌려서 처리해야 한다.
(5) char[] 타입보다 String이 데이터 처리하기 편하기 때문에 String으로 변환한다.
- char[] 에는 엔터 대신 "\n"으로 표시되어 한 줄로 이어져 담겨있다. -> String에도 한 줄로 담겨진다.
(6) Stirng[] 에 한 줄의 String 값을 "\n"으로 split해서 각 방에 한 줄 씩 정보를 담는다.
(7) 그 중 0번방에 들어간 맨 윗 줄은 정보값의 인덱스이기 때문에 ","로 split해서 다른 String[]에 담는다.
(8) for 문을 돌리기 전에 값을 담을 ArrayList를 생성한다.
(9) 1번방부터 마지막방까지 루프를 돌며 ","로 split해서 Vo에 넣어 list에 넣는다.
- (정보 종류는 12개) ","로 split한 값을 담은 배열의 길이가 12개 이하이면 (== 공백) 무시한다.
(10) 인덱스 배열과 이하 정보값을 담은 리스트를 request에 담아 jsp로 보낸다.
- db에 넣고 싶으면 Dao 클래스를 만들어 Insert 메소드 만들기~
(11) 파일을 다 읽었으므로 입력스트림을 닫아준다.
(12) 이동할 jsp 페이지 주소를 return 한다.
총코드
package handler;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import csv.Vo;
// csv 파일 파싱해서 웹 페이지에 데이터를 출력
public class CsvHandler implements Handler {
@Override
public String process(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
// 웹에서 사용될 실제 주소로 변경
String path = request.getServletContext().getRealPath("/WEB-INF/files/a_utf8.csv");
try {
// 문자단위로 읽는 스트림 생성
FileReader fr = new FileReader(path);
// 파일에서 읽은 데이터 저장할 배열 생성
char[] buf = new char[10000]; // 한 줄로 읽어들일 값 크기 설정(전체데이터를 한 줄로 읽을것.)
// buf 크기만큼 파일에서 읽어서 buf에 저장
// 파일 내용이 10000자보다 많으면 루프를 돌려 처리해야 함.
fr.read(buf);
// char[] 보다 String이 데이터 처리하기 편함
String str = new String(buf); // 전체 데이터가 한 줄로 이어져 str에 담김
String[] data = str.split("\n"); // 엔터로 끊어서 방 하나에 한 줄씩 들어감
String[] titles = data[0].split(","); // 맨 윗줄을 ,로 끊어 title[] 방에 담음
ArrayList<Vo> list = new ArrayList<>();
for (int i = 1; i < data.length; i++) { // 1번 줄부터 마지막줄까지 읽어 list에 담음
String[] vals = data[i].split(",");
if(vals.length<12) {
continue;
}
list.add(new Vo(vals[0], vals[1], vals[2], vals[3], vals[4], vals[5],
vals[6], vals[7], vals[8], vals[9], vals[10], vals[11]));
}
// db에 넣고 싶으면 dao insert 호출해서 담기~
// jsp 페이지로 값 보내기
request.setAttribute("titles", titles);
request.setAttribute("list", list);
fr.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "/csv/list.jsp";
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>대전 열차 시간표</h3>
<table border="1">
<tr>
<c:forEach var="t" items="${titles}">
<th>${t }</th>
</c:forEach>
</tr>
<c:forEach var="vo" items="${list }">
<tr><td>${vo.arg1}</td><td>${vo.arg2}</td><td>${vo.arg3}</td><td>${vo.arg4}</td>
<td>${vo.arg5}</td><td>${vo.arg6}</td><td>${vo.arg7}</td><td>${vo.arg8}</td>
<td>${vo.arg9}</td><td>${vo.arg10}</td><td>${vo.arg11}</td><td>${vo.arg12}</td></tr>
</c:forEach>
</table>
</body>
</html>
2. JSON 파일


- 파일을 받으면 우선 데이터가 어떻게 들어가있는지 파악부터 해야 한다.
- 이 파일은 크게 보면 { } 로 객체임을 알 수 있음.
- 객체는 키:값 형태로 되어있음. 지금 같은 경우는
{ "주소" : { "주소" : [ { 키 : 값, 키 : 값 } , [ { 키 : 값, 키 : 값} ] , .... },
"주소" : { "주소" : [ { 키 : 값, 키 : 값 } , [ { 키 : 값, 키 : 값} ] , .... },
"주소" : { "주소" : [ { 키 : 값, 키 : 값 } , [ { 키 : 값, 키 : 값} ] , .... } }
- 값에 객체가 또 들어가있고.. 그 객체의 값에 배열이 들어가있고.. 그 배열 각각이 객체인.. 아주 복잡한 구조로 되어있다.
{
"http://data.ex.co.kr:80/link/serviceAreaFoods/B00099" : {
"http://data.ex.co.kr:80/link/def/salePrice" : [ {
"type" : "literal" ,
"value" : "₩7,000"
}
] ,
"http://data.ex.co.kr:80/link/def/batchMenu" : [ {
"type" : "literal" ,
"value" : "영양더덕산채비빔밥"
}
] ,
"http://data.ex.co.kr:80/link/def/serviceAreaName" : [ {
"type" : "literal" ,
"value" : "산청"
}
] ,
"http://data.ex.co.kr:80/link/def/routeName" : [ {
"type" : "literal" ,
"value" : "통영대전ㆍ중부고속도로"
}
] ,
"http://www.w3.org/2000/01/rdf-schema#label" : [ {
"type" : "literal" ,
"value" : "영양더덕산채비빔밥"
}
] ,
"http://data.ex.co.kr:80/link/def/direction" : [ {
"type" : "literal" ,
"value" : "통영"
}
]
}
,
.
.
.
"http://data.ex.co.kr:80/link/serviceAreaFoods/B00170" : {
"http://data.ex.co.kr:80/link/def/salePrice" : [ {
"type" : "literal" ,
"value" : "₩6,000"
}
] ,
"http://data.ex.co.kr:80/link/def/batchMenu" : [ {
"type" : "literal" ,
"value" : "베이컨 김치 볶음밥"
}
] ,
"http://data.ex.co.kr:80/link/def/serviceAreaName" : [ {
"type" : "literal" ,
"value" : "공주"
}
] ,
"http://data.ex.co.kr:80/link/def/routeName" : [ {
"type" : "literal" ,
"value" : "당진영덕고속도로"
}
] ,
"http://www.w3.org/2000/01/rdf-schema#label" : [ {
"type" : "literal" ,
"value" : "베이컨 김치 볶음밥"
}
] ,
"http://data.ex.co.kr:80/link/def/direction" : [ {
"type" : "literal" ,
"value" : "청원"
}
]
}
}
- 이때는 당황~하지~않고~ 반복되는 값이 무엇인지 파악하고 Vo를 만들어준다.
-- 어차피 반복문 돌릴게 눈에 훤하니까!
public class FoodVo {
private String label;
private String price;
private String area;
private String routeName;
private String direction;
}
- 그 다음엔 자연스럽게 데이터를 파싱할 핸들러 클래스를 만든다.
String path = request.getServletContext().getRealPath("/WEB-INF/files/serviceAreaFoods.json");
FileReader fr = new FileReader(path);
JSONParser parser = new JSONParser();
JSONObject obj = (JSONObject) parser.parse(fr);
Iterator iter = obj.keySet().iterator();
ArrayList<FoodVo> list = new ArrayList<>();
while(iter.hasNext()) {
String key = (String) iter.next();
// 음식 객체 하나를 꺼냄
JSONObject o = (JSONObject) obj.get(key);
// 음식명 추출
JSONArray arr = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/batchMenu");
JSONObject jsonlabel = (JSONObject) arr.get(0);
String label = (String) jsonlabel.get("value");
// 가격 추출
JSONArray arr2 = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/salePrice");
JSONObject jsonprice = (JSONObject) arr2.get(0);
String price = (String) jsonprice.get("value");
// 지역명 area 추출
JSONArray arr3 = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/serviceAreaName");
JSONObject jsonarea = (JSONObject) arr3.get(0);
String area = (String) jsonarea.get("value");
// 고속도로명 routeName 추출
JSONArray arr4 = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/routeName");
JSONObject jsonroute = (JSONObject) arr4.get(0);
String route = (String) jsonroute.get("value");
// 방향 direction 추출
JSONArray arr5 = (JSONArray) o.get( "http://data.ex.co.kr:80/link/def/direction");
JSONObject jsondirect = (JSONObject) arr5.get(0);
String direct = (String) jsondirect.get("value");
list.add(new FoodVo(label, price, area, route, direct));
}
request.setAttribute("list", list);
return "/json/list.jsp";
(1) 파라메터에 담은 경로를 웹에서 사용하는 실제 경로로 반환해 String path에 담는다.
-- 파라메터에 담은 경로는~ 파일을 저장한 폴더의 절대경로를 적으면 된다.
(2) JSON 파일도 문자 파일이기 때문에 FileReader로 입력 스트림을 열어준다.
JSONParser parser = new JSONParser();
JSONObject obj = (JSONObject) parser.parse(fr);
(3) JSON을 파싱하기 위해 파서를 생성하고, path에 있는 파일을 파싱해 객체에 담는다.
- 위의 코드는 JSON.parse(txt) 와 같다.
- 해당 JSON 파일은 객체 타입이므로 {} JSONObject를 먼저 열어준 것!
(4) 객체의 키를 반복자로 읽어와 String에 담고, 그 키와 매칭된 값(음식 객체 하나)을 JSONObject에 담는다.
- 구조가 { 키 : 값{ 키 : 값[ {키:값, 키:값}], 키 : 값[{키:값, 키:값}] .... }}
{ "http://data.ex.co.kr:80/link/serviceAreaFoods/B00099" :
{ "http://data.ex.co.kr:80/link/def/salePrice" : [ { "type" : "literal" , "value" : "₩7,000" } ] , "http://data.ex.co.kr:80/link/def/batchMenu" : [ { "type" : "literal" , "value" : "영양더덕산채비빔밥" } ] ,
(5) 음식 객체는 { 주소 : [ { 키 : 값, "value" : 값 } ], ... } 이렇게 구성되어 있기때문에
1. 주소(키)와 매칭된 값(배열)을 JSONArray에 담는다.
2) 그 배열의 0번방(객체) 값을 JSONObject에 담는다.
3) 그 객체의 두 쌍 중에 "value"와 매칭돤 값을 String에 담는다.
----- 이 구조를 Vo 개수만큼 하고 Vo에 넣어 리스트에 담는다.
(6) 리스트를 jsp로 전달하기 위해 request에 담는다.
(7) 이동할 jsp 페이지 주소를 return한다.
총 코드
package handler;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import json.FoodVo;
public class JsonHandler implements Handler {
@Override
public String process(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
String path = request.getServletContext().getRealPath("/WEB-INF/files/serviceAreaFoods.json");
try {
FileReader fr = new FileReader(path);
JSONParser parser = new JSONParser();
JSONObject obj = (JSONObject) parser.parse(fr); // json.parse(txt); 와 같음
Iterator iter = obj.keySet().iterator();
ArrayList<FoodVo> list = new ArrayList<>();
while(iter.hasNext()) {
String key = (String) iter.next();
// 음식 객체 하나를 꺼냄
JSONObject o = (JSONObject) obj.get(key);
// 음식명 추출
JSONArray arr = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/batchMenu");
JSONObject jsonlabel = (JSONObject) arr.get(0);
String label = (String) jsonlabel.get("value");
// 가격 추출
JSONArray arr2 = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/salePrice");
JSONObject jsonprice = (JSONObject) arr2.get(0);
String price = (String) jsonprice.get("value");
// 지역명 area 추출
JSONArray arr3 = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/serviceAreaName");
JSONObject jsonarea = (JSONObject) arr3.get(0);
String area = (String) jsonarea.get("value");
// 고속도로명 routeName 추출
JSONArray arr4 = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/routeName");
JSONObject jsonroute = (JSONObject) arr4.get(0);
String route = (String) jsonroute.get("value");
// 방향 direction 추출
JSONArray arr5 = (JSONArray) o.get( "http://data.ex.co.kr:80/link/def/direction");
JSONObject jsondirect = (JSONObject) arr5.get(0);
String direct = (String) jsondirect.get("value");
list.add(new FoodVo(label, price, area, route, direct));
}
request.setAttribute("list", list);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "/json/list.jsp";
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>고속도로 휴게소 지역 음식 리스트</h3>
<table border="1">
<tr><th>음식명</th><th>가격</th><th>지역명</th><th>고속도로명</th><th>방향</th></tr>
<c:forEach var="vo" items="${list}">
<tr>
<td>${vo.label}</td><td>${vo.price}</td><td>${vo.area}</td><td>${vo.routeName}</td><td>${vo.direction}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
3. XML 파일


- XML 파일은 태그로 값이 나눠져 있다. --- 없는 태그를 정의해서 사용함.
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book>
<bookid>1</bookid>
<title>aaaa</title>
<author>아무개</author>
<price>1000</price>
</book>
<book>
<bookid>2</bookid>
<title>데이터찾기</title>
<author>신세경</author>
<price>2000</price>
</book>
<book>
<bookid>3</bookid>
<title>데이터요청</title>
<author>장국영</author>
<price>3000</price>
</book>
<book>
<bookid>4</bookid>
<title>데이터활용</title>
<author>김태희</author>
<price>4000</price>
</book>
</books>
- 파싱할 데이터 종류 만큼 Vo를 만들어 주고 -- 반복문 돌릴거니까~
public class BookVo {
private int num;
private String title;
private String author;
private int price;
}
- XML 파일을 파싱할 핸들러 클래스를 만들어준다.
String path = request.getServletContext().getRealPath("/WEB-INF/files/data.xml");
FileInputStream fi = new FileInputStream(path);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(fi);
Element root = doc.getDocumentElement();
NodeList list = root.getChildNodes();
ArrayList<BookVo> datas = new ArrayList<>();
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i);
NodeList infos = child.getChildNodes();
if (infos.getLength() == 0) { // 값 이외의 공백 제거
continue;
}
BookVo vo = new BookVo();
for (int j = 0; j < infos.getLength(); j++) {
Node info = infos.item(j);
String tagName = info.getNodeName();
switch (tagName) {
case "bookid":
vo.setNum(Integer.parseInt(info.getTextContent()));
break;
case "title":
vo.setTitle(info.getTextContent());
break;
case "author":
vo.setAuthor(info.getTextContent());
break;
case "price":
vo.setPrice(Integer.parseInt(info.getTextContent()));
break;
}
}
datas.add(vo);
}
request.setAttribute("datas", datas);
return "/xml/list.jsp";
(1) 파라메터에 담은 경로를 웹에서 사용하는 실제 경로로 반환해 String path에 담는다.
(2) CSV와 JSON이 문자 파일인 것과는 다르게 XML은 바이트 타입이라 FileInputStream으로 입력 스트림을 열어준다.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // instance 생성
DocumentBuilder builder = factory.newDocumentBuilder(); // DocumentBuilder 객체 생성
Document doc = builder.parse(fi); // xml파싱
(3) XML 파일은 DOM으로 파싱한다. DocumentBuilderFactory 클래스로 XML 문서에서 DOM 오브젝트 트리를 생성하는 parser를 얻을 수 있다. XML 파일에서 Dom document instance를 얻기 위해서는 DocumentBuilder 가 필요하다.
- 파일을 DocumentBuilder 로 파싱해서 Document에 넣어준다.
-- Document, Element, Node 모두 Dom 용어다.
여기서 Node와 Element의 차이점을 알아보자면,
- 돔은 Node의 계층구조로 이루어져 있고 Node는 텍스트, 주석, 요소 등 많은 유형을 포함한다.
- 요소는 Node 중 하나로, <p>, <body>, <div> 등 태그를 사용해 작성된 Node를 뜻한다.
Element root = doc.getDocumentElement();
(4) root 요소를 뽑는다.
- root 요소란 최상단에 위치한 태그를 뜻한다. 이번 경우에는 <books> 이다.
즉, 이 태그 안의 값을 추출하겠다는 선전포고이므로 가장 바깥 태그를 먼저 불러오는 것.
NodeList list = root.getChildNodes();
(5) 자식 노드를 추출한다. -- <book> 태그 모두 추출
- getChildNodes() 는 배열을 반환한다. 이 반환값을 NodeList에 넣는다.
- <book> 태그 사이의 정보값을 담을 BookVo 리스트도 생성해준다.
Node child = list.item(i);
(5-1) for문을 NodeList 길이만큼 돌리면서 각 노드를 추출한다. -- <book></book> 사이 태그 모두 추출
- item(i) 는 NodeList에서 i번째 노드(i번째 <book>태그값)를 추출한다.
- 추출한 노드(<book>)의 자식 노드(<bookid>, <title>, <author>, <price>)들을 추출해서 NodeList에 담는다.
String tagName = info.getNodeName();
switch (tagName) {
case "bookid":
vo.setNum(Integer.parseInt(info.getTextContent()));
break;
(5-2) for문을 NodeList 길이만큼 돌리면서 각 노드의 값을 추출한다. -- <bookid>, <title>, <author>, <price>의 사잇값
- getNodeName()으로 태그명을 추출해서 switch 문으로 반복문을 돌린다.
- getTextContent()로 태그 사이값을 추출해 vo에 담는다.
- (5) 에서 생성한 리스트에 vo를 담아준다.
- 이 리스트를 request에 담아 jsp 페이지로 전달한다.
- 이동할 jsp 주소를 return 한다.
총 코드
package handler;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import xml.BookVo;
public class XmlHandler implements Handler {
@Override
public String process(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
String path = request.getServletContext().getRealPath("/WEB-INF/files/data.xml");
try {
FileInputStream fi = new FileInputStream(path);
// DocumentBuilder 객체를 주는 factory 객체 생성
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// DocumentBuilder 객체 생성
DocumentBuilder builder = factory.newDocumentBuilder();
// xml파싱
Document doc = builder.parse(fi);
// 1. root 요소를 뽑는다. --> <books>
Element root = doc.getDocumentElement();
// 2. 자식 노드 추출 --> <book>태그 모두 추출
NodeList list = root.getChildNodes(); // 배열
ArrayList<BookVo> datas = new ArrayList<>();
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i); // item(i) : nodelist에서 i번째 노드 추출 <book></book>
// <book>의 자식 노드들 추출 -- <bookid><title><author><price>
NodeList infos = child.getChildNodes();
if (infos.getLength() == 0) { // 값 이외의 공백 제거
continue;
}
BookVo vo = new BookVo();
for (int j = 0; j < infos.getLength(); j++) {
Node info = infos.item(j);
String tagName = info.getNodeName(); // getNodeName() : 태그명 추출
switch (tagName) {
case "bookid":
vo.setNum(Integer.parseInt(info.getTextContent()));
break;
case "title":
vo.setTitle(info.getTextContent());
break;
case "author":
vo.setAuthor(info.getTextContent());
break;
case "price":
vo.setPrice(Integer.parseInt(info.getTextContent()));
break;
}
// System.out.println(vo);
// String val = info.getTextContent(); // getTextContent() : 태그 사이 값
// System.out.println(tagName + " : " + val);
}
datas.add(vo);
}
request.setAttribute("datas", datas);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "/xml/list.jsp";
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>xml 데이터 로드</h3>
<table border = "1">
<tr><th>책id</th><th>제목</th><th>저자</th><th>가격</th></tr>
<c:forEach var="vo" items="${datas }">
<tr><td>${vo.num }</td><td>${vo.title }</td><td>${vo.author}</td><td>${vo.price}</td></tr>
</c:forEach>
</table>
</body>
</html>
https://intheham.tistory.com/79
[공공데이터] 2. URL로 불러와 파싱 (XML-기상청, 버스노선)
https://intheham.tistory.com/78 [공공데이터] 1. 다운받은 파일 파싱 (csv, json, xml) 공공데이터를 활용하는 방법에는 1. 공공데이터 사이트에서 파일을 다운받아 파싱 2. 온라인에서 바로 파싱 이번에는 1.
intheham.tistory.com
공공데이터를 활용하는 방법에는
1. 공공데이터 사이트에서 파일을 다운받아 파싱
2. 온라인에서 바로 파싱
이번에는 1. 다운받은 파일을 파싱하는 법을 알아보자.

0. 파일 넣기
- 우선 다운받은 파일을 프로젝트의
src/webapp/WEB-INF 에 파일을 만들어서 넣어준다.
commands.properties
- url=핸들러 주소
- url은 인식하기 편하게 지정해준다. url로 불러올 핸들러 주소만 명확하다면 오케이.
/csv/load.do=handler.CsvHandler
/json/load.do=handler.JsonHandler
/xml/load.do=handler.XmlHandler
index
- commands.properties에 적은 url을 적어준다.
- url로 불러올 클래스가 핸들러 클래스이기 때문에 현 프로젝트 주소를 반영하는 ${pageContext.request.contextPath} 꼭 적어주기.
- jsp로의 이동은 필요 없다~
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>공공데이터 활용</h3>
<a href="${pageContext.request.contextPath}/csv/load.do">csv 데이터 확인</a><br/>
<a href="${pageContext.request.contextPath}/json/load.do">json 데이터 확인</a><br/>
<a href="${pageContext.request.contextPath}/xml/load.do">xml 데이터 확인</a><br/>
</body>
</html>
1. CSV 파일
- 엑셀 형태의 파일.
- ","로 값이 나눠져 있음.
- 엔터(\n)로 한 객체의 정보가 나뉜다.



- 년월, 요일, 상_하행, 열차번호 등 같은 양식으로 여러 값이 들어있으므로 루프문을 돌릴 필요가 있다.
--> 루프 문 돌려 리스트에 담을 때 한 줄 당 Vo에 넣어 리스트에 넣으면 jsp에서 출력 루프문 돌릴 때 좋다.
==> VO 생성
public class Vo {
private String arg1;
private String arg2;
private String arg3;
private String arg4;
private String arg5;
private String arg6;
private String arg7;
private String arg8;
private String arg9;
private String arg10;
private String arg11;
private String arg12;
}
- Handler interface를 상속받은 Handler 클래스를 생성한다. -- 여기서 csv 파일을 파싱해서 jsp 페이지로 데이터를 전송할 것.
String path = request.getServletContext().getRealPath("/WEB-INF/files/a_utf8.csv");
FileReader fr = new FileReader(path);
char[] buf = new char[10000];
fr.read(buf);
String str = new String(buf);
String[] data = str.split("\n");
String[] titles = data[0].split(",");
ArrayList<Vo> list = new ArrayList<>();
for (int i = 1; i < data.length; i++) {
String[] vals = data[i].split(",");
if(vals.length<12) {
continue;
}
list.add(new Vo(vals[0], vals[1], vals[2], vals[3], vals[4], vals[5],
vals[6], vals[7], vals[8], vals[9], vals[10], vals[11]));
}
request.setAttribute("titles", titles);
request.setAttribute("list", list);
fr.close();
return "/csv/list.jsp";
(1) 파라메터에 담은 경로를 웹에서 사용하는 실제 경로로 반환해 String path에 담는다.
--- getServletContext() : 서블릿 클래스와 서블릿 컨테이너(톰캣) 간 통신을 위한 메소드들을 정의해둔 클래스
--- getRealPath() : getServletContext의 메서드 중 하나. 주어진 디렉토리(폴더)의 실제 실행되는 서버상의 주소를 절대경로로 알려줌.
(2) csv 파일은 문자 타입이므로 Filereader로 스트림을 생성한다. -- 파일 읽어들일 준비.
(3) char[] 배열에 파일 내용을 한 줄로 읽음
- char 은 문자 1개씩 읽는 문자타입임. 즉, char[10000]은 만 자의 문자를 한 배열에 담겠다는 뜻.
(4) path에 있는 파일을 char[] 크기만큼 읽어들여 담는다.
- 파일 내용이 10000자보다 많으면 루프를 돌려서 처리해야 한다.
(5) char[] 타입보다 String이 데이터 처리하기 편하기 때문에 String으로 변환한다.
- char[] 에는 엔터 대신 "\n"으로 표시되어 한 줄로 이어져 담겨있다. -> String에도 한 줄로 담겨진다.
(6) Stirng[] 에 한 줄의 String 값을 "\n"으로 split해서 각 방에 한 줄 씩 정보를 담는다.
(7) 그 중 0번방에 들어간 맨 윗 줄은 정보값의 인덱스이기 때문에 ","로 split해서 다른 String[]에 담는다.
(8) for 문을 돌리기 전에 값을 담을 ArrayList를 생성한다.
(9) 1번방부터 마지막방까지 루프를 돌며 ","로 split해서 Vo에 넣어 list에 넣는다.
- (정보 종류는 12개) ","로 split한 값을 담은 배열의 길이가 12개 이하이면 (== 공백) 무시한다.
(10) 인덱스 배열과 이하 정보값을 담은 리스트를 request에 담아 jsp로 보낸다.
- db에 넣고 싶으면 Dao 클래스를 만들어 Insert 메소드 만들기~
(11) 파일을 다 읽었으므로 입력스트림을 닫아준다.
(12) 이동할 jsp 페이지 주소를 return 한다.
총코드
package handler;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import csv.Vo;
// csv 파일 파싱해서 웹 페이지에 데이터를 출력
public class CsvHandler implements Handler {
@Override
public String process(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
// 웹에서 사용될 실제 주소로 변경
String path = request.getServletContext().getRealPath("/WEB-INF/files/a_utf8.csv");
try {
// 문자단위로 읽는 스트림 생성
FileReader fr = new FileReader(path);
// 파일에서 읽은 데이터 저장할 배열 생성
char[] buf = new char[10000]; // 한 줄로 읽어들일 값 크기 설정(전체데이터를 한 줄로 읽을것.)
// buf 크기만큼 파일에서 읽어서 buf에 저장
// 파일 내용이 10000자보다 많으면 루프를 돌려 처리해야 함.
fr.read(buf);
// char[] 보다 String이 데이터 처리하기 편함
String str = new String(buf); // 전체 데이터가 한 줄로 이어져 str에 담김
String[] data = str.split("\n"); // 엔터로 끊어서 방 하나에 한 줄씩 들어감
String[] titles = data[0].split(","); // 맨 윗줄을 ,로 끊어 title[] 방에 담음
ArrayList<Vo> list = new ArrayList<>();
for (int i = 1; i < data.length; i++) { // 1번 줄부터 마지막줄까지 읽어 list에 담음
String[] vals = data[i].split(",");
if(vals.length<12) {
continue;
}
list.add(new Vo(vals[0], vals[1], vals[2], vals[3], vals[4], vals[5],
vals[6], vals[7], vals[8], vals[9], vals[10], vals[11]));
}
// db에 넣고 싶으면 dao insert 호출해서 담기~
// jsp 페이지로 값 보내기
request.setAttribute("titles", titles);
request.setAttribute("list", list);
fr.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "/csv/list.jsp";
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>대전 열차 시간표</h3>
<table border="1">
<tr>
<c:forEach var="t" items="${titles}">
<th>${t }</th>
</c:forEach>
</tr>
<c:forEach var="vo" items="${list }">
<tr><td>${vo.arg1}</td><td>${vo.arg2}</td><td>${vo.arg3}</td><td>${vo.arg4}</td>
<td>${vo.arg5}</td><td>${vo.arg6}</td><td>${vo.arg7}</td><td>${vo.arg8}</td>
<td>${vo.arg9}</td><td>${vo.arg10}</td><td>${vo.arg11}</td><td>${vo.arg12}</td></tr>
</c:forEach>
</table>
</body>
</html>
2. JSON 파일


- 파일을 받으면 우선 데이터가 어떻게 들어가있는지 파악부터 해야 한다.
- 이 파일은 크게 보면 { } 로 객체임을 알 수 있음.
- 객체는 키:값 형태로 되어있음. 지금 같은 경우는
{ "주소" : { "주소" : [ { 키 : 값, 키 : 값 } , [ { 키 : 값, 키 : 값} ] , .... },
"주소" : { "주소" : [ { 키 : 값, 키 : 값 } , [ { 키 : 값, 키 : 값} ] , .... },
"주소" : { "주소" : [ { 키 : 값, 키 : 값 } , [ { 키 : 값, 키 : 값} ] , .... } }
- 값에 객체가 또 들어가있고.. 그 객체의 값에 배열이 들어가있고.. 그 배열 각각이 객체인.. 아주 복잡한 구조로 되어있다.
{
"http://data.ex.co.kr:80/link/serviceAreaFoods/B00099" : {
"http://data.ex.co.kr:80/link/def/salePrice" : [ {
"type" : "literal" ,
"value" : "₩7,000"
}
] ,
"http://data.ex.co.kr:80/link/def/batchMenu" : [ {
"type" : "literal" ,
"value" : "영양더덕산채비빔밥"
}
] ,
"http://data.ex.co.kr:80/link/def/serviceAreaName" : [ {
"type" : "literal" ,
"value" : "산청"
}
] ,
"http://data.ex.co.kr:80/link/def/routeName" : [ {
"type" : "literal" ,
"value" : "통영대전ㆍ중부고속도로"
}
] ,
"http://www.w3.org/2000/01/rdf-schema#label" : [ {
"type" : "literal" ,
"value" : "영양더덕산채비빔밥"
}
] ,
"http://data.ex.co.kr:80/link/def/direction" : [ {
"type" : "literal" ,
"value" : "통영"
}
]
}
,
.
.
.
"http://data.ex.co.kr:80/link/serviceAreaFoods/B00170" : {
"http://data.ex.co.kr:80/link/def/salePrice" : [ {
"type" : "literal" ,
"value" : "₩6,000"
}
] ,
"http://data.ex.co.kr:80/link/def/batchMenu" : [ {
"type" : "literal" ,
"value" : "베이컨 김치 볶음밥"
}
] ,
"http://data.ex.co.kr:80/link/def/serviceAreaName" : [ {
"type" : "literal" ,
"value" : "공주"
}
] ,
"http://data.ex.co.kr:80/link/def/routeName" : [ {
"type" : "literal" ,
"value" : "당진영덕고속도로"
}
] ,
"http://www.w3.org/2000/01/rdf-schema#label" : [ {
"type" : "literal" ,
"value" : "베이컨 김치 볶음밥"
}
] ,
"http://data.ex.co.kr:80/link/def/direction" : [ {
"type" : "literal" ,
"value" : "청원"
}
]
}
}
- 이때는 당황~하지~않고~ 반복되는 값이 무엇인지 파악하고 Vo를 만들어준다.
-- 어차피 반복문 돌릴게 눈에 훤하니까!
public class FoodVo {
private String label;
private String price;
private String area;
private String routeName;
private String direction;
}
- 그 다음엔 자연스럽게 데이터를 파싱할 핸들러 클래스를 만든다.
String path = request.getServletContext().getRealPath("/WEB-INF/files/serviceAreaFoods.json");
FileReader fr = new FileReader(path);
JSONParser parser = new JSONParser();
JSONObject obj = (JSONObject) parser.parse(fr);
Iterator iter = obj.keySet().iterator();
ArrayList<FoodVo> list = new ArrayList<>();
while(iter.hasNext()) {
String key = (String) iter.next();
// 음식 객체 하나를 꺼냄
JSONObject o = (JSONObject) obj.get(key);
// 음식명 추출
JSONArray arr = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/batchMenu");
JSONObject jsonlabel = (JSONObject) arr.get(0);
String label = (String) jsonlabel.get("value");
// 가격 추출
JSONArray arr2 = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/salePrice");
JSONObject jsonprice = (JSONObject) arr2.get(0);
String price = (String) jsonprice.get("value");
// 지역명 area 추출
JSONArray arr3 = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/serviceAreaName");
JSONObject jsonarea = (JSONObject) arr3.get(0);
String area = (String) jsonarea.get("value");
// 고속도로명 routeName 추출
JSONArray arr4 = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/routeName");
JSONObject jsonroute = (JSONObject) arr4.get(0);
String route = (String) jsonroute.get("value");
// 방향 direction 추출
JSONArray arr5 = (JSONArray) o.get( "http://data.ex.co.kr:80/link/def/direction");
JSONObject jsondirect = (JSONObject) arr5.get(0);
String direct = (String) jsondirect.get("value");
list.add(new FoodVo(label, price, area, route, direct));
}
request.setAttribute("list", list);
return "/json/list.jsp";
(1) 파라메터에 담은 경로를 웹에서 사용하는 실제 경로로 반환해 String path에 담는다.
-- 파라메터에 담은 경로는~ 파일을 저장한 폴더의 절대경로를 적으면 된다.
(2) JSON 파일도 문자 파일이기 때문에 FileReader로 입력 스트림을 열어준다.
JSONParser parser = new JSONParser();
JSONObject obj = (JSONObject) parser.parse(fr);
(3) JSON을 파싱하기 위해 파서를 생성하고, path에 있는 파일을 파싱해 객체에 담는다.
- 위의 코드는 JSON.parse(txt) 와 같다.
- 해당 JSON 파일은 객체 타입이므로 {} JSONObject를 먼저 열어준 것!
(4) 객체의 키를 반복자로 읽어와 String에 담고, 그 키와 매칭된 값(음식 객체 하나)을 JSONObject에 담는다.
- 구조가 { 키 : 값{ 키 : 값[ {키:값, 키:값}], 키 : 값[{키:값, 키:값}] .... }}
{ "http://data.ex.co.kr:80/link/serviceAreaFoods/B00099" :
{ "http://data.ex.co.kr:80/link/def/salePrice" : [ { "type" : "literal" , "value" : "₩7,000" } ] , "http://data.ex.co.kr:80/link/def/batchMenu" : [ { "type" : "literal" , "value" : "영양더덕산채비빔밥" } ] ,
(5) 음식 객체는 { 주소 : [ { 키 : 값, "value" : 값 } ], ... } 이렇게 구성되어 있기때문에
1. 주소(키)와 매칭된 값(배열)을 JSONArray에 담는다.
2) 그 배열의 0번방(객체) 값을 JSONObject에 담는다.
3) 그 객체의 두 쌍 중에 "value"와 매칭돤 값을 String에 담는다.
----- 이 구조를 Vo 개수만큼 하고 Vo에 넣어 리스트에 담는다.
(6) 리스트를 jsp로 전달하기 위해 request에 담는다.
(7) 이동할 jsp 페이지 주소를 return한다.
총 코드
package handler;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import json.FoodVo;
public class JsonHandler implements Handler {
@Override
public String process(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
String path = request.getServletContext().getRealPath("/WEB-INF/files/serviceAreaFoods.json");
try {
FileReader fr = new FileReader(path);
JSONParser parser = new JSONParser();
JSONObject obj = (JSONObject) parser.parse(fr); // json.parse(txt); 와 같음
Iterator iter = obj.keySet().iterator();
ArrayList<FoodVo> list = new ArrayList<>();
while(iter.hasNext()) {
String key = (String) iter.next();
// 음식 객체 하나를 꺼냄
JSONObject o = (JSONObject) obj.get(key);
// 음식명 추출
JSONArray arr = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/batchMenu");
JSONObject jsonlabel = (JSONObject) arr.get(0);
String label = (String) jsonlabel.get("value");
// 가격 추출
JSONArray arr2 = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/salePrice");
JSONObject jsonprice = (JSONObject) arr2.get(0);
String price = (String) jsonprice.get("value");
// 지역명 area 추출
JSONArray arr3 = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/serviceAreaName");
JSONObject jsonarea = (JSONObject) arr3.get(0);
String area = (String) jsonarea.get("value");
// 고속도로명 routeName 추출
JSONArray arr4 = (JSONArray) o.get("http://data.ex.co.kr:80/link/def/routeName");
JSONObject jsonroute = (JSONObject) arr4.get(0);
String route = (String) jsonroute.get("value");
// 방향 direction 추출
JSONArray arr5 = (JSONArray) o.get( "http://data.ex.co.kr:80/link/def/direction");
JSONObject jsondirect = (JSONObject) arr5.get(0);
String direct = (String) jsondirect.get("value");
list.add(new FoodVo(label, price, area, route, direct));
}
request.setAttribute("list", list);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "/json/list.jsp";
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>고속도로 휴게소 지역 음식 리스트</h3>
<table border="1">
<tr><th>음식명</th><th>가격</th><th>지역명</th><th>고속도로명</th><th>방향</th></tr>
<c:forEach var="vo" items="${list}">
<tr>
<td>${vo.label}</td><td>${vo.price}</td><td>${vo.area}</td><td>${vo.routeName}</td><td>${vo.direction}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
3. XML 파일


- XML 파일은 태그로 값이 나눠져 있다. --- 없는 태그를 정의해서 사용함.
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book>
<bookid>1</bookid>
<title>aaaa</title>
<author>아무개</author>
<price>1000</price>
</book>
<book>
<bookid>2</bookid>
<title>데이터찾기</title>
<author>신세경</author>
<price>2000</price>
</book>
<book>
<bookid>3</bookid>
<title>데이터요청</title>
<author>장국영</author>
<price>3000</price>
</book>
<book>
<bookid>4</bookid>
<title>데이터활용</title>
<author>김태희</author>
<price>4000</price>
</book>
</books>
- 파싱할 데이터 종류 만큼 Vo를 만들어 주고 -- 반복문 돌릴거니까~
public class BookVo {
private int num;
private String title;
private String author;
private int price;
}
- XML 파일을 파싱할 핸들러 클래스를 만들어준다.
String path = request.getServletContext().getRealPath("/WEB-INF/files/data.xml");
FileInputStream fi = new FileInputStream(path);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(fi);
Element root = doc.getDocumentElement();
NodeList list = root.getChildNodes();
ArrayList<BookVo> datas = new ArrayList<>();
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i);
NodeList infos = child.getChildNodes();
if (infos.getLength() == 0) { // 값 이외의 공백 제거
continue;
}
BookVo vo = new BookVo();
for (int j = 0; j < infos.getLength(); j++) {
Node info = infos.item(j);
String tagName = info.getNodeName();
switch (tagName) {
case "bookid":
vo.setNum(Integer.parseInt(info.getTextContent()));
break;
case "title":
vo.setTitle(info.getTextContent());
break;
case "author":
vo.setAuthor(info.getTextContent());
break;
case "price":
vo.setPrice(Integer.parseInt(info.getTextContent()));
break;
}
}
datas.add(vo);
}
request.setAttribute("datas", datas);
return "/xml/list.jsp";
(1) 파라메터에 담은 경로를 웹에서 사용하는 실제 경로로 반환해 String path에 담는다.
(2) CSV와 JSON이 문자 파일인 것과는 다르게 XML은 바이트 타입이라 FileInputStream으로 입력 스트림을 열어준다.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // instance 생성
DocumentBuilder builder = factory.newDocumentBuilder(); // DocumentBuilder 객체 생성
Document doc = builder.parse(fi); // xml파싱
(3) XML 파일은 DOM으로 파싱한다. DocumentBuilderFactory 클래스로 XML 문서에서 DOM 오브젝트 트리를 생성하는 parser를 얻을 수 있다. XML 파일에서 Dom document instance를 얻기 위해서는 DocumentBuilder 가 필요하다.
- 파일을 DocumentBuilder 로 파싱해서 Document에 넣어준다.
-- Document, Element, Node 모두 Dom 용어다.
여기서 Node와 Element의 차이점을 알아보자면,
- 돔은 Node의 계층구조로 이루어져 있고 Node는 텍스트, 주석, 요소 등 많은 유형을 포함한다.
- 요소는 Node 중 하나로, <p>, <body>, <div> 등 태그를 사용해 작성된 Node를 뜻한다.
Element root = doc.getDocumentElement();
(4) root 요소를 뽑는다.
- root 요소란 최상단에 위치한 태그를 뜻한다. 이번 경우에는 <books> 이다.
즉, 이 태그 안의 값을 추출하겠다는 선전포고이므로 가장 바깥 태그를 먼저 불러오는 것.
NodeList list = root.getChildNodes();
(5) 자식 노드를 추출한다. -- <book> 태그 모두 추출
- getChildNodes() 는 배열을 반환한다. 이 반환값을 NodeList에 넣는다.
- <book> 태그 사이의 정보값을 담을 BookVo 리스트도 생성해준다.
Node child = list.item(i);
(5-1) for문을 NodeList 길이만큼 돌리면서 각 노드를 추출한다. -- <book></book> 사이 태그 모두 추출
- item(i) 는 NodeList에서 i번째 노드(i번째 <book>태그값)를 추출한다.
- 추출한 노드(<book>)의 자식 노드(<bookid>, <title>, <author>, <price>)들을 추출해서 NodeList에 담는다.
String tagName = info.getNodeName();
switch (tagName) {
case "bookid":
vo.setNum(Integer.parseInt(info.getTextContent()));
break;
(5-2) for문을 NodeList 길이만큼 돌리면서 각 노드의 값을 추출한다. -- <bookid>, <title>, <author>, <price>의 사잇값
- getNodeName()으로 태그명을 추출해서 switch 문으로 반복문을 돌린다.
- getTextContent()로 태그 사이값을 추출해 vo에 담는다.
- (5) 에서 생성한 리스트에 vo를 담아준다.
- 이 리스트를 request에 담아 jsp 페이지로 전달한다.
- 이동할 jsp 주소를 return 한다.
총 코드
package handler;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import xml.BookVo;
public class XmlHandler implements Handler {
@Override
public String process(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
String path = request.getServletContext().getRealPath("/WEB-INF/files/data.xml");
try {
FileInputStream fi = new FileInputStream(path);
// DocumentBuilder 객체를 주는 factory 객체 생성
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// DocumentBuilder 객체 생성
DocumentBuilder builder = factory.newDocumentBuilder();
// xml파싱
Document doc = builder.parse(fi);
// 1. root 요소를 뽑는다. --> <books>
Element root = doc.getDocumentElement();
// 2. 자식 노드 추출 --> <book>태그 모두 추출
NodeList list = root.getChildNodes(); // 배열
ArrayList<BookVo> datas = new ArrayList<>();
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i); // item(i) : nodelist에서 i번째 노드 추출 <book></book>
// <book>의 자식 노드들 추출 -- <bookid><title><author><price>
NodeList infos = child.getChildNodes();
if (infos.getLength() == 0) { // 값 이외의 공백 제거
continue;
}
BookVo vo = new BookVo();
for (int j = 0; j < infos.getLength(); j++) {
Node info = infos.item(j);
String tagName = info.getNodeName(); // getNodeName() : 태그명 추출
switch (tagName) {
case "bookid":
vo.setNum(Integer.parseInt(info.getTextContent()));
break;
case "title":
vo.setTitle(info.getTextContent());
break;
case "author":
vo.setAuthor(info.getTextContent());
break;
case "price":
vo.setPrice(Integer.parseInt(info.getTextContent()));
break;
}
// System.out.println(vo);
// String val = info.getTextContent(); // getTextContent() : 태그 사이 값
// System.out.println(tagName + " : " + val);
}
datas.add(vo);
}
request.setAttribute("datas", datas);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "/xml/list.jsp";
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>xml 데이터 로드</h3>
<table border = "1">
<tr><th>책id</th><th>제목</th><th>저자</th><th>가격</th></tr>
<c:forEach var="vo" items="${datas }">
<tr><td>${vo.num }</td><td>${vo.title }</td><td>${vo.author}</td><td>${vo.price}</td></tr>
</c:forEach>
</table>
</body>
</html>
https://intheham.tistory.com/79
[공공데이터] 2. URL로 불러와 파싱 (XML-기상청, 버스노선)
https://intheham.tistory.com/78 [공공데이터] 1. 다운받은 파일 파싱 (csv, json, xml) 공공데이터를 활용하는 방법에는 1. 공공데이터 사이트에서 파일을 다운받아 파싱 2. 온라인에서 바로 파싱 이번에는 1.
intheham.tistory.com