파싱

유요한·2022년 7월 15일

파싱(XML & JSON)

목록 보기
1/1

파싱(Parsing)이란?

  • 파싱은 어떤 페이지(문서, html 등)에서 내가 원하는 데이터를 특정 패턴이나 순서로 추출하여 정보로 가공하는 것을 말하는 것이다. 다이아몬드가 많이 나오는 위치로 이동을 일단 한 후에 돌을 많이 캔다음에 다이아몬드만 뽑아서 보석으로 가공하는것과 비슷하다.
  • parsing은 구문 분석이라고 합니다. 문장이 이루고 있는 구성 성분을 분해하고 분해된 성분의 위계 관계를 분석하여 구조를 결정하는 것입니다. 즉, 데이터를 분해, 분석하여 원하는 형태로 조립하고 다시 빼내는 프로그램을 말한다. 웹상에서 주어진 정보를 내가 원하는 형태로 가공하여 서버에서 불러들이는 것이다.

이러한 parsing 기법은 XML parsingJSON parsing이 있다.


XML 설명

XML이란?

XML은 데이터를 저장하고 전달할 목적으로 만들어졌으며, 저장되는 데이터의 구조를 기술하기 위하고 HTML과 매우 비슷한 문자 기반의 마크업 언어이다. XML은 수 많은 응용 분야에서 데이터를 저장하고 전달하는 중요한 역할을 맡고 있습니다. 이 언어는 사람과 기계가 동시에 읽기 편한 구조로 되어 있습니다. 그러나 XML은 HTML처럼 데이터를 보여주는 것이 아닌 데이터를 저장하고 전달할 목적으로 만들어졌습니다. 또한 XML 태그는 사용자가 직접 정의할 수 있습니다.

XML 특징

  1. XML은 다른 목적의 마크업 언어를 만드는데 사용되는 다목적 마크업 언어이다.
  2. XML은 다른 시스템끼리 다양한 종류의 데이터를 손쉽게 교환할 수 있도록 해줍니다.
  3. XML은 새로운 태그를 만들어 추가해도 계속해서 동작하므로 확장성이 좋습니다.
  4. XML은 데이터를 보여주지 않고 데이터를 전달하고 저장하는 것만을 목적으로 합니다.
  5. XML은 텍스트 데이터 형식의 언어로 모든 XML 문서는 유니코드 문자로만 이루어집니다.

XML의 구성





XML의 용도는?

XML은 워드 프로세싱과 같은 일반적인 생산성 도구에서 책 출판 소프트웨어 및 복잡한 응용 프로그램 구성 시스템에 이르기까지 수천 가지 애플리케이션 기본 기술입니다.

데이터 전송
XML을 사용하여 동일한 데이터를 서로 다른 형식으로 저장하는 두 시스템 간에 데이터를 전송할 수 있습니다. 예를들어, 웹 사이트에서는 날짜를 MM/DD/YYYY 형식으로 저장하지만 회계 시스템은 날짜를 DD/MM/YYYY 형식으로 저장합니다. XML을 사용하여 웹 사이트에서 회계 시스템으로 데이터를 전송할 수 있습니다. 개발자는 다음을 자동으로 변환하는 코드를 작성할 수 있습니다.

  • 웹 사이트 데이터를 XML 형식으로
  • XML 데이터를 회계 시스템 데이터로
  • 회계 시스템 데이터를 다시 XML 형식으로
  • XML 데이터를 다시 웹 사이트 데이터로

XML 스키마란 무엇인가?

XML 구문 분석기란 무엇인가?

XML을 사용하면 어떤 이점이 있나요?

  1. 비즈니스 간 트랜잭션 지원
    회사가 다른 회사에 상품이나 서비스를 판매하는 경우 두 기업은 비용, 사양 및 배송 일정과 같은 정보를 교환해야 합니다. XML(Extensible Markup Language)을 사용하면 필요한 모든 정보를 전자적으로 공유하고 사람의 개입 없이 복잡한 거래를 자동으로 성사시킬 수 있습니다.

  2. 데이터 무결성 유지
    XML을 사용하면 데이터 설명과 함께 데이터를 전송하여 데이터 무결성 손실을 방지할 수 있습니다. 이 설명 정보를 사용하여 다음을 수행할 수 있습니다.

  • 데이터 정확성 확인
  • 다양한 사용자를 위해 자동으로 데이터 표시 사용자 지정
  • 여러 플랫폼에 걸쳐 일관되게 데이터 저장
  1. 검색 효율성 향상
    검색 엔진과 같은 컴퓨터 프로그램은 다른 유형의 문서보다 더 효율적이고 정확하게 XML 파일을 정렬하고 분류할 수 있습니다. 예를 들어, mark라는 단어는 명사일 수도, 동사일 수도 있습니다. XML 태그를 기반으로 검색 엔진은 관련 검색 결과에 대해 mark를 정확하게 분류할 수 있습니다. 따라서 XML은 컴퓨터가 자연어를 보다 효율적으로 해석할 수 있도록 합니다.

  2. 유연한 애플리케이션 설계
    XML을 사용하면 애플리케이션 디자인을 편리하게 업그레이드하거나 수정할 수 있습니다. 많은 기술, 특히 최신 기술에는 기본 제공 XML 지원이 함께 제공됩니다. XML 데이터 파일을 자동으로 읽고 처리할 수 있으므로 전체 데이터베이스를 다시 포맷하지 않고도 변경할 수 있습니다.

XML 예제


XML 파싱(parsing)하여 API 데이터 가져오기

					→ 금융상품데이터 API
  1. 파싱할 URL 준비

    먼저 파싱할 URL이 필요하다.

  1. 페이지에 접근해줄 Document객체 생성

    여기서 생성한 document객체를 통해 파싱할 url의 요소를 읽어 들인다. doc.getDocumentElement().getNodeName())를 출력하면 위 XML의 최상위 tag값을 가져온다. 여기서는 가 최상위 tag값이다.

  1. 파싱할 정보가 있는 tag에 접근

  1. list에 담긴 데이터 출력하기

전체 코드

	package test;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XmlParsing_test {

  // tag값의 정보를 가져오는 메소드
	private static String getTagValue(String tag, Element eElement) {
	    NodeList nlList = eElement.getElementsByTagName(tag).item(0).getChildNodes();
	    Node nValue = (Node) nlList.item(0);
	    if(nValue == null) 
	        return null;
	    return nValue.getNodeValue();
	}

	public static void main(String[] args) {
		int page = 1;	// 페이지 초기값 
		try{
			while(true){
				// parsing할 url 지정(API 키 포함해서)
				String url = "http://finlife.fss.or.kr/finlifeapi/annuitySavingProductsSearch.xml?auth=1db6e257b5ad61c5241a1bc1c9bc863b&topFinGrpNo=050000&pageNo="+page;
				
				DocumentBuilderFactory dbFactoty = DocumentBuilderFactory.newInstance();
				DocumentBuilder dBuilder = dbFactoty.newDocumentBuilder();
				Document doc = dBuilder.parse(url);
				
				// root tag 
				doc.getDocumentElement().normalize();
				System.out.println("Root element :" + doc.getDocumentElement().getNodeName());
				
				// 파싱할 tag
				NodeList nList = doc.getElementsByTagName("baseinfo");
				//System.out.println("파싱할 리스트 수 : "+ nList.getLength());
				
				for(int temp = 0; temp < nList.getLength(); temp++){
					Node nNode = nList.item(temp);
					if(nNode.getNodeType() == Node.ELEMENT_NODE){
						
						Element eElement = (Element) nNode;
						System.out.println("######################");
						//System.out.println(eElement.getTextContent());
						System.out.println("금융사  : " + getTagValue("kor_co_nm", eElement));
						System.out.println("상품 코드  : " + getTagValue("fin_prdt_cd", eElement));
						System.out.println("상품명 : " + getTagValue("fin_prdt_nm", eElement));
						System.out.println("연평균 수익률  : " + getTagValue("avg_prft_rate", eElement));
						System.out.println("공시 이율  : " + getTagValue("dcls_rate", eElement));
					}	// for end
				}	// if end
				
				page += 1;
				System.out.println("page number : "+page);
				if(page > 12){	
					break;
				}
			}	// while end
			
		} catch (Exception e){	
			e.printStackTrace();
		}	// try~catch end
	}	// main end
}	// class end

자바에서 XML 파싱하기

XML 파일에서 데이터를 가져오는 절차는 HTML 파일에서 데이터를 가져오는 절차와 유사합니다. XML파일 태그를 인식하기 위해서 필요한 절차는 문서의 자체 객체인 document를 가져오는 것입니다.

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;

// xml 파싱 빌드업
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();

// xml 파일을 document로 파싱하기
Document document = builder.parse("xml/sample.xml");

XML 파일의 위치는 원하는 상대 경로 혹은 절대 경로를 통해서 가져옵니다.

이제 자바가 xml파일의 document를 가지고 와서 태그를 인식할 준비가 되었습니다. 태그라는 것이 결국 document 안에 있는 요소(element)이기 대문에 이 Element를 가져와야 합니다. getDocument() 메소드를 사용하면 가장 첫번째 요소(root요소)를 가져올 수 있습니다.

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;

// root 요소 가져오기
Element root = document.getDocumentElement();
// root 요소 확인 : 첫 태그 sample
System.out.println(root.getNodeName()); 
// root 요소의 첫번째 노드는 #Text
Node firstNode = root.getFirstChild();
// 다음 노드는 customer
Node customer = firstNode.getNextSibling();
// customer 요소 안의 노드 리스트
NodeList childList = customer.getChildNodes();

root요소가 <sample> 태그이기 때문에 첫번째 Element인 root를 가져와서 getNodeName() 메소드를 이용해서 리턴된 문자열(String)을 출력하면 "sample"이라는 값을 얻을 수 있습니다.

getFirstChilde() 메소드를 사용하면 해당 요소의 첫 번째 있는 노드를 가져와서 리턴합니다.

이때, root라는 변수에 저장된 <sample> 태그의 첫 번째 node가 <customer> 태그가 아닌 #Test로 표시되는데 이는 xml파일의 빈 공백을 노드로 인식하기 때문입니다.

태그와 태그 사이의 공백을 하나의 노드로 인식하기 때문에 공백의 길이에 상관없이 하나의 노드가 됩니다.

getNextSibiling() 메서드를 이용하면 계속해서 해당 요소의 다음 노드를 리턴하게 됩니다.

첫 공백 노드에서 다음 노드인 <customer> 태그 노드에 오게 되면 getChildeNodes() 메서드를 이용해서 <customer> 태그 안의 노드들을 리스트로 리턴 받을 수 있습니다.

이제 customer 태그 안에 있는 태그들의 모든 데이터를 가져올 수 있습니다.

for(int i = 0; i < childList.getLength(); i++) {
	Node item = childList.item(i);
	if(item.getNodeType() == Node.ELEMENT_NODE) { // 노드의 타입이 Element일 경우(공백이 아닌 경우)
		System.out.println(item.getNodeName());
		System.out.println(item.getTextContent());
	} else {
		System.out.println("공백 입니다.");
	}
}

XML 문서

<!--XML 문서 내용 -->
<response>
	<header>
		<resultCode>00</resultCode>
			<resultMsg>NORMAL_CODE</resultMsg>
	</header>
	<body>
		<items>
			<item>
				<pm25Grade1h>2</pm25Grade1h>
				<pm10Value24>55</pm10Value24>
				<so2Value>0.002</so2Value>
			</item>
			<item>
				<pm25Grade1h>2</pm25Grade1h>
				<pm10Value24>57</pm10Value24>
				<so2Value>0.002</so2Value>
			</item>
		</items>
<numOfRows>10</numOfRows>
<pageNo>1</pageNo>
<totalCount>23</totalCount>
</body>
</response>

XML 파싱 및 태그의 값 가져오기

//XML 요청 url
String url = "http://api.adfafadsfasdfadf";

//XML 파싱
DocumentBuilderFactory dbFactoty = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactoty.newDocumentBuilder();
Document doc = dBuilder.parse(url);

//item이라는 태그의 element들 가져오기
NodeList nList = doc.getElementsByTagName("item");
Node nNode = nList.item(0);

if (nNode.getNodeType() == Node.ELEMENT_NODE) {
    Element eElement = (Element) nNode;
    getTagValue("so2Value", eElement);
}
  • DocumentBuilderFactory : 어플리케이션으로 XML 문서로부터 DOM 객체 트리를 생성하는 파서를 취득할 수 있는 팩토리 API를 정의합니다.
  • DocumentBuilder : 현재 설정되어 있는 파라미터를 사용해 새로운 DocumentBuilder 인스턴스를 작성합니다.
    이 클래스의 인스턴스를 취득하면, 다양한 입력 소스로부터 XML 문서를 구문 분석 할 수 있습니다. 이러한 입력 소스에는 InputStream, File, URL 및 SAX InputSource가 있습니다.
  • Document : HTML 문서 또는 XML 문서 전체를 나타냅니다.

XML 파싱 및 내용 출력하기

//XML문서 요청 url
String url = "http://api.adfafadsfasdfadf";

//XML 파싱
DocumentBuilderFactory dbFactoty = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactoty.newDocumentBuilder();
Document doc = dBuilder.parse(url);

//XML을 Strig으로 출력
Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
tf.setOutputProperty(OutputKeys.INDENT, "yes");
Writer out = new StringWriter();
tf.transform(new DOMSource(doc), new StreamResult(out));
System.out.println(out.toString()); 

Spring에서 XML 데이터 파싱

사용할 API는 HRD-net에서 제공하는 구직자훈련과정 목록 API와 구직자훈련과정/ 기관정보 API이다.

학원 정보 및 강좌에 대한 정보를 얻을 수 있다.

구직자훈련과정 목록 API (전체 과정의 정보 출력)

구직자훈련과정 과정/기관정보 API (한 과정의 상세정보를 출력)

  1. URL 준비
  • 각 사이트에서 API 인증키를 요청하여 받은 다음에 파싱할 URL을 작성한다.
 String url = " https://www.hrd.go.kr/jsp/HRDP/HRDPO00/HRDPOA60/HRDPOA60_1.jsp?returnType=XML&"
	     //사이트에서 발급받은 인증키
	     +"authKey=gV6TA7Ep5JFP66lYZgtEip3bkBl6av4s"
             //요청 parameters
	     +"&pageNum=1&pageSize=10&srchTraStDt=20210524&srchTraEndDt=20210824&outType=1&sort=ASC&sortCol=TR_STT_DT&crseTracseSe=C0055,C0054,C0059&srchKeco1=20"; 
  1. Document 객체 생성
  • document 객체를 통해 파싱할 URL의 데이터를 읽어온다.
  • documentInfo.getDocumentElement().getNodeName()을 출력하면 XML의 최상위 TAG값을 가져온다. 여기서는 <HRDNet>이 최상위 태그 값이다.
Document documentInfo = null;
documentInfo = (Document) DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(url); 
documentInfo.getDocumentElement().normalize();
//Root: HRDNet
System.out.println("Root: " + documentInfo.getDocumentElement().getNodeName());
  1. 파싱할 데이터가 있는 tag에 접근하기
  • 목록 API 기준으로 파싱할 데이터가 있는 tag는 srchList이다.
  • nList에 srchList안에 있는 태그들이 담기게 된다.
    Element root = documentInfo.getDocumentElement();
    NodeList nList = root.getElementsByTagName("srchList").item(0).getChildNodes();
  1. nList에 담긴 데이터 꺼내오기
  • for문을 이용해 파싱한 데이터를 map에 저장하고 새로운 list에 저장한다.
  • getTagValue("tagName", element): "tagName"에 해당하는 데이터 가져오는 메소드
    List<Map<String, String>> list = new ArrayList<>();
      for (int i = 0; i < nList.getLength(); i++) {
        Map<String, String> map = new HashMap<>();
        Node nNode = nList.item(i);
        Element eElement = (Element) nNode;
    
        map.put("trainCd", getTagValue("trprId", eElement)); // 과정코드
        map.put("trainTitle", getTagValue("title", eElement)); // 과정명
        map.put("acadCd", getTagValue("instCd", eElement)); // 학원코드
        map.put("acadTitle", getTagValue("subTitle", eElement)); // 학원명
        map.put("telNo", getTagValue("telNo", eElement)); // 학원 전화번호
        map.put("startDate", getTagValue("traStartDate", eElement)); // 훈련시작일자
        map.put("endDate", getTagValue("traEndDate", eElement)); // 훈련종료일자
        map.put("target", getTagValue("trainTarget", eElement)); // 훈련대상
        map.put("yardMan", getTagValue("yardMan", eElement)); // 정원
        map.put("courseMan", getTagValue("courseMan", eElement)); // 수강비
        map.put("realMan", getTagValue("realMan", eElement)); // 실제 수강비
        map.put("trainDegr", getTagValue("trprDegr", eElement)); // 회차
    
        list.add(map);
      }
    }

코드의 결과!

요청 parameter에 페이지수가 나눠져 있기 때문에 총 페이지 갯수를 구하여 반복문을 이용해 모든 페이지에 접근해 가져왔습니다. 또 각 과정을 진행하는 학원에 대한 상세 주소와 폼페이지 URL은 과정/기관정보 API에서 가져야 한다. ↓

  1. 목록 API를 읽어서 List<Map<String, String>>형태로 저장
  2. 다시 반복문을 돌려 과정/기관정보 API를 읽어서 상세주소/홈페이지 URL 데이터 Map에 넣기
  3. mapper로 Map을 보내서 DB에 데이터 저장/업데이트
   private static final Logger logger = LoggerFactory.getLogger(AcadScheduler.class);
 
 @Autowired
 private AcademyMapper academyMapper;

 public static int PAGE_SIZE = 100;
 public static String URL = "https://www.hrd.go.kr/jsp/HRDP/HRDPO00/HRDPOA60/HRDPOA60_1.jsp";
 public static String URL2 = "https://www.hrd.go.kr/jsp/HRDP/HRDPO00/HRDPOA60/HRDPOA60_2.jsp";
 public static String SERVICE_KEY = "gV6TA7Ep5JFP66lYZgtEip3bkBl6av4s";


 public void update() throws Exception {    
   int result = 0;
   List<Map<String, String>> list = new ArrayList<>();

   try {
     // 학원 목록 읽어오기
     createDocument(list);

     for (Map<String, String> acadInfo : list) {
       createDetailInfo(acadInfo);

       result += academyMapper.createAcademy(acadInfo);
     }
   } catch (Exception e) {
     e.printStackTrace();
   }
   logger.info("총 학원 갯수:" + result);
 }

 //tag값 정보를 가져오는 메소드
 private static String getTagValue(String tag, Element eElement) {
   NodeList nList = null;
   Node nValue = null;
   try {
     nList = eElement.getElementsByTagName(tag).item(0).getChildNodes();
     nValue = (Node) nList.item(0);
   } catch (Exception e) {
     e.printStackTrace();
   }
   if (nValue == null)
     return null;
   return nValue.getNodeValue();
 }

 private void createDetailInfo(Map<String, String> acadInfo) {
   Document documentInfo = null;
   // 파싱할 url 지정
   String parseUrl =
       URL2 + "?returnType=XML&authKey=" + SERVICE_KEY + "&srchTrprId=" + acadInfo.get("trainCd")
           + "&srchTrprDegr=" + acadInfo.get("trainDegr") + "&outType=2&srchTorgId=default";
   try {
     documentInfo =
         (Document) DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(parseUrl);
     //root tag
     documentInfo.getDocumentElement().normalize();
     // 과정,기관정보 데이터 파싱
     parseDetailXml(documentInfo.getDocumentElement(), acadInfo);
   } catch (SAXException e) {
     e.printStackTrace();
   } catch (IOException e) {
     e.printStackTrace();
   } catch (ParserConfigurationException e) {
     e.printStackTrace();
   }

 }

 private void parseDetailXml(Element root, Map<String, String> map) {
   Node nNode = root.getElementsByTagName("inst_base_info").item(0);
   Element eElement = (Element) nNode;

   map.put("address", getTagValue("addr1", eElement)); // 상세주소
   map.put("url", getTagValue("hpAddr", eElement)); // 학원홈페이지url

 }

 private void parseXml(Element root, List<Map<String, String>> list) {
   NodeList nList = root.getElementsByTagName("srchList").item(0).getChildNodes();

   for (int i = 0; i < nList.getLength(); i++) {
     Map<String, String> map = new HashMap<>();
     Node nNode = nList.item(i);
     Element eElement = (Element) nNode;

     map.put("trainCd", getTagValue("trprId", eElement)); // 과정코드
     map.put("trainTitle", getTagValue("title", eElement)); // 과정명
     map.put("acadCd", getTagValue("instCd", eElement)); // 학원코드
     map.put("acadTitle", getTagValue("subTitle", eElement)); // 학원명
     map.put("telNo", getTagValue("telNo", eElement)); // 학원 전화번호
     map.put("startDate", getTagValue("traStartDate", eElement)); // 훈련시작일자
     map.put("endDate", getTagValue("traEndDate", eElement)); // 훈련종료일자
     map.put("target", getTagValue("trainTarget", eElement)); // 훈련대상
     map.put("yardMan", getTagValue("yardMan", eElement)); // 정원
     map.put("courseMan", getTagValue("courseMan", eElement)); // 수강비
     map.put("realMan", getTagValue("realMan", eElement)); // 실제 수강비
     map.put("trainDegr", getTagValue("trprDegr", eElement)); // 회차

     list.add(map);
   }
 }

 private void createDocument(List<Map<String, String>> list) {
   Document documentInfo = null;
   int pageNum = 1;
   SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
   Date currentDate = new Date();
   Calendar cal = Calendar.getInstance();
   cal.setTime(currentDate);
   // 현재날짜로부터 3개월뒤 날짜 설정
   cal.add(Calendar.MONTH, 3);
   String stDt = formatter.format(currentDate);
   String endDt = formatter.format(cal.getTime());
   // URL 설정
   String parseUrl = URL + "?returnType=XML&authKey=" + SERVICE_KEY + "&pageSize=" + PAGE_SIZE
       + "&srchTraStDt=" + stDt + "&srchTraEndDt=" + endDt
       + "&outType=1&sort=ASC&sortCol=TR_STT_DT&crseTracseSe=C0055,C0054,C0059&srchKeco1=20&pageNum=";

   try {
     int tot = 0, num = 1;
     while (true) {
       if (pageNum > num)
         break;
       documentInfo = (Document) DocumentBuilderFactory.newInstance().newDocumentBuilder()
           .parse(parseUrl + pageNum);
       documentInfo.getDocumentElement().normalize();
       if (pageNum == 1) {
         // 총 학원 갯수
         tot = Integer.parseInt(getTagValue("scn_cnt", documentInfo.getDocumentElement()));
         num = (tot / PAGE_SIZE) + 1;
       }
       // 목록 정보 데이터 파싱하기
       parseXml(documentInfo.getDocumentElement(), list);

       pageNum++;
     }
   } catch (SAXException e) {
     e.printStackTrace();
   } catch (IOException e) {
     e.printStackTrace();
   } catch (ParserConfigurationException e) {
     e.printStackTrace();
   }
 }

JSON

JSON(Javascript Object Notation)라는 의미의 축약어로 데이터를 저장하거나 전송할 때 많이 사용되는 경량의 data 교환 형식을 의미합니다. JSON은 자바스크립트의 객체 표기법으로부터 파생된 부분 집합입니다. 따라서 JSON 데이터는 다음과 같은 자바스크립트 객체 표기법에 따른 구조로 구성됩니다. JSON은 XML의 대안으로서 좀 더 쉽게 데이터를 교환하고 저장하기 위하여 고안되었습니다. JSON은 javascript object notation 의 약자로 자바스크립트에서 객체 인스턴스를 생성하는 또 다른 방식입니다. 객체안에는 매개변수와 값이 들어있으므로 이 자체로 데이터의 교환을 하기에 용이합니다. 네트워크와 앱 등 서로간 데이터 교환을 위해 과거에는 xml 을 사용했다면 json은 xml 이후에 등장하여 널리 사용되고 있는 형식입니다. 확장자는 .json이다. 사람과 기계 모두 이해하기 쉬우며 용량이 적어서 최근에는 XML을 대신하여 데이터 전송에 사용한다.

JSON은 Object로 되어 있는데 { }로 감싸여 있는 것을 말합니다.

또한, JSON은 텍스트 기반이므로 어떠한 프로그래밍 언어에서도 JSON 데이터를 읽고 사용할 수 있습니다.

  • JavaScript Object Notation 줄임말

  • JSON은 서버와 클라이언트 또는 컴퓨터/프로그램 사이에 데이터를 주고 받을 때 사용하는 데이터 포멧

  • 키와 값을 괄호와 세미콜론과 같이 간단한 기호로 구성하여 표현할 수 있고, 언어나 운영체제에 구애받지 않기 때문에 많이 사용됨

  • 특히 웹/앱 환경에서 Rest API를 사용하여, 서버와 클라이언트 사이에 데이터를 주고 받을때 많이 사용

  • JSON 포멧 예
    {"id":"01", "language": "Java", "edition": "third",
    "author": "Herbert Schildt"}

JSON은 어디에 사용하는가?

Ajax를 사용해 데이터를 주고받을 때 그 데이터 포맷으로 JSON을 사용하는 것이다. eval()함수 하나로 해결되는 것이 JSON이다. 변수를 전달하기 위한 목적의 JSON이 Javascript 그 자체를 전달할 수 있다.

  • 브라우저 확장 프로그램 또는 웹 사이트를 포함하는 자바스크립트 기반 응용 프로그램을 작성할 때 사용된다.
  • JSON 형식은 네트워크 연결을 통해 구조화 된 데이터를 직렬화 및 전송하는데 사용된다.
  • 주로 서버와 Web 응용 프로그램 간에 데이터를 전송하는데 사용된다.
  • Web 서비스와 API.s는 공개 데이터를 제공하기 위해 JSON 형식을 사용한다.
  • 여러 프로그램 언어에서 사용할 수 있다.

JSON 특징

  • 서버클라이언트 간의 교류에서 일반적으로 많이 사용된다.
  • 자바스크립트 객체 표기법과 아주 유사하다.
  • 자바스크립트를 이용하여 JSON 형식의 문서를 쉽게 자바스크립트 객체로 변환할 수 있는 이점이 있다.
  • JSON 문서 형식은 자바스크립트 객체의 형식을 기반으로 만들어 졌다.
  • 자바스크립트 문법과 굉장히 유사하지만 텍스트 형식일 뿐이다.
  • 다른 프로그래밍 언어를 이용해서도 쉽게 만들 수 있다.
  • 특정 언어에 종속되지 않으며, 대부분의 프로그래밍 언어에서 JSON 포맷의 데이터를 핸들링 할 수 있는 라이브러리를 제공한다.

JSON 문법

  • 데이터는 속성-값 쌍으로 표현된다.
  • 중괄호는 개체를 유지하고 각각의 이름이 계속되고 있는 :(콜론), 속성-값 쌍으로 쉼표로 구분된다.
  • 대괄호는 배열과 값은 쉼표로 구분된다.

JSON과 XML 공통점






JSON과 XML의 차이점

JSON 사용 범위

XML 문서는 XML DOM을 이용하여 해당 문서에 접근합니다. 하지만 JSON은 문자열을 전송받은 후에 해당 문자열을 바로 파싱하므로, XML보다 더욱 빠른 처리속도를 보여줍니다. 따라서 HTML과 자바스크립트가 연동되어 빠른 응답이 필요한 웹 환경에서 많이 사용되고 있습니다. 하지만 JSON은 전송받은 데이터의 무결성을 사용자가 직접 검증해야 합니다. 따라서 데이터의 검증이 필요한 곳에서는 스키마를 사용하여 데이터의 무결성을 검증할 수 있는 XML이 아직도 많이 사용되고 있습니다.

JSON 문법

JSON은 자바스크립트의 객체 표기법에서 리터럴(literal)과 프로퍼티(property)를 표현하는 방법만 가져와서 사용합니다. 따라서 JSON 데이터는 모양과 규칙이 매우 단순합니다.

그로 인해 브라우저 영역에서도 쉽고 빠르게 그 의미를 해석할 수 있으며, 다른 프로그래밍 언어에서도 구현하기 쉽습니다.




JSON 객체

JSON 객체는 중괄호({})로 둘러 쌓아 표현합니다. 객체에 저장되는 프로퍼티(property)는 데이터 이름과 값의 한 쌍으로 이루어져 있습니다. 또한 JSON 객체는 쉼표를 사용하여 여러 프로퍼티를 포함할 수 있습니다. 이때 프로퍼티의 순서는 중요하지 않으며, 데이터의 이름은 문자열로 반드시 큰 따옴표("")를 사용해야 합니다.

	{
    "name": "식빵",
    "family": "웰시코기",
    "age": 1,
    "weight": 2.14
	}

객체 안의 객체

JSON에서 데이터 이름과 대응되는 값으로 숫자, 문자열, 불리언뿐만 아니라 또 다른 객체가 올 수도 있습니다. 만약 데이터의 값이 객체라면 객체 안에 객체가 포함되는 계층 구조가 형성됩니다.

	{
    "dog": {
        "name": "식빵",
        "family": "웰시코기",
        "age": 1,
        "weight": 2.14,
        "owner": {
            "ownerName": "홍길동",
            "phone": "01012345678"
        }
    }
}

위의 예제에서 가장 상위 계층의 데이터 이름은 "dog"이며, 데이터값으로 다섯 개의 또 다른 데이터를 가지고 있습니다.

그중에서 다섯 번째 데이터인 "owner" 객체는 "ownerName"과 "phone"이라는 또 다른 데이터를 가지고 있습니다.

JSON객체를 그림으로 나타내면 다음과 같다.

파싱(Parsing)

JSON 정보가 문자열로 넘어올 때 사용하는 메소드는 JSON.parse() 입니다. 문자열을 파싱하기 전에는 json 객체는 그냥 문자열로 있습니다. parsing 후에는 인스턴스가 생성되고 자바스크립트 객체로써 조작할 수 있습니다.

JSON 배열

JSON 배열은 대괄호([])로 둘러쌓아 표현합니다. 또한 JSON 배열은 쉼표를 사용하여 여러 JSON 데이터를 포함할 수 있습니다.

다음 예제는 배열의 이름이 "dog"이고, 3개의 JSON 객체를 요소로 가지는 JSON 배열의 예제입니다.

JSON 배열을 그림으로 나타내면 다음과 같습니다.

JSON 문자열

JSON에서 문자열이란 일련의 연속된 문자의 집합을 의미합니다. 이러한 문자열은 큰따옴표("") 안에 유니코드 문자들의 나열로 구성됩니다.

JSON에서 역슬래시()문자는 특정 문자와 함께 사용되어 이스케이프 시퀸스(escape sequence)로 사용됩니다. 따라서 JSON문자열에는 역슬래시()와 큰따옴표("")만을 사용할 수 있습니다.

json 파서(parser)는 우선 JSON 데이터를 모두 읽어 드립니다. 위의 예제처럼 큰따옴표를 이스케이프 시퀀스(\")로 표현하지 않았다면, 식빵이라는 문자열 앞에 있는 큰따옴표에서 문자열이 모두 끝났다고 인식할 것입니다. 따라서 JSON 파서는 오류를 발생시킬 것입니다. 이처럼 문자열 내에서 큰따옴표나 역슬래시를 표현하기 위해서는 반드시 이스케이프 시퀀스를 사용하여 JSON 파서에 해당 따옴표는 문자열을 끝내는 따옴표가 아니라는 사실을 알려주어야만 합니다.

JSON 불리언

JSON null

JSON 스키마(schema)

JSON은 좀 더 쉽게 데이터를 교환하고 저장하기 위하여 만들어진 데이터 교환 표준입니다. 이때 JSON 데이터를 전송받는 측에서는 전송받은 데이터가 적법한 형식의 데이터인지를 확인할 방법이 필요합니다. 따라서 적법한 JSON 데이터의 형식을 기술한 문서를 JSON 스키마(schema)라고 합니다.


자바스크립트와 JSON

JSON은 자바스크립트의 객체 표기법을 제한하여 만든 텍스트 기반의 데이터 교환 표준입니다. 따라서 JSON 데이터는 자바스크립트가 자주 사용되는 웹 환경에서 사용하는 것이 유리합니다. 자바스크립트에서 JSON 데이터를 분석하고 사용하는 것은 매우 간단합니다.

자바스크립트는 JSON 데이터를 처리하기 위한 다음과 같은 메소드를 제공하고 있습니다.

  1. JSON.stringify()
  2. JSON.parse()
  3. toJSON()

// 자바스크립트 객체
var dog = {name: "식빵", family: "웰시코기", age: 1, weight: 2.14}; 

// 자바스크립트 객체를 문자열로 변환함.
var data = JSON.stringify(dog);                    

document.getElementById("json").innerHTML = data;	

// JSON 형식의 문자열
	var data = '{"name": "식빵", "family": "웰시코기", "age": 1, "weight": 2.14}'; 
 
// JSON 형식의 문자열을 자바스크립트 객체로 변환함.
var dog = JSON.parse(data);     

document.getElementById("json").innerHTML = dog + "<br>";

document.getElementById("json").innerHTML += dog.name + ", " + dog.family;

→ JSON.parse() 메소드는 오직 JSON 형식의 문자열만을 변환할 수 있습니다.

● 문법
YYYY-MM-DDTHH:mm:ss.sssZ
또는
±YYYYYY-MM-DDTHH:mm:ss.sssZ
● 예제
// 자바스크립트 Date 객체
var date = new Date();   
// Date 객체를 JSON 형식의 문자열로 변환함.
var str = date.toJSON(); 

 

document.getElementById("json").innerHTML = date + "<br>";

document.getElementById("json").innerHTML += str;

JSON 사용

자바스크립트에서 JSON을 사용하기 위해 다음과 같은 메소드를 제공하고 있습니다.

  1. JSON.stringify(arg)

  2. JSON.parse(arg)

두 메소드의 사용 목적은 간단합니다. 객체와 문자열로의 변환이 목적입니다.

JSON 데이터 만드는법

  1. 아래 링크로 들어간다.

    https://code.google.com/archive/p/json-simple/downloads

  2. 다운받는다.



JSON-Simple을 통해 json 객체를 다루는 법

JSON-Simple

json-simple 라이브러리는 JSON파싱을 지원합니다.
.java 파일에서 JSONObject jsonObj = new JSONObject();를 입력하고 ctrl + shift + o를 누르면 import 가능한 관련 라이브러리가 나올 것입니다. 거기서 org.json.simple.JSONObject가 나온다면 추가해주시고, 없으면 pom.xml에 dependency를 아래처럼 추가해줍니다.

<dependency>
  <groupId>com.googlecode.json-simple</groupId>
  <artifactId>json-simple</artifactId>
  <version>1.1.1</version>
</dependency>

JSON 파일 일기

json 데이터가 이미 "[{a,b,c},{d,e,f}]"와 같이 String으로 가지고 있다면 이부분은 패스해도 괜찮습니다. .json 파일에서 Reader를 통해 텍스트를 읽어 들이는 방법입니다.

import java.io.FileReader;
import org.json.simple.JSONObject;
import org.json.simple.JSONArray;
import org.json.simple.parser.JSONParser;

public class jsonFileRead{
  public static void main(String[] args) throws IOException {
      // .json 파일 READ
      Reader reader = new FileReader("File Path");
    
      // reader를 Object로 parse
      JSONParser parser = new JSONParser();
      Object obj = parser.parse(reader); 
   
      // 아래 code로 이어짐
  }
}

위 절차를 통해 file을 Object로 만드는게 우선입니다. 이제 .json파일의 형식에 따라 조금씩 다릅니다.

JSON 객체 단건일 때(JSONObject)

파일에서 읽은 값이 위와 같은 단건의 json객체라면 바로 JSONObject에 담으면 됩니다.

// 상단 코드에 이어 

// obj를 JsonObject로 cast
JSONObject jsonObj = (JSONObject)obj;

System.out.println((String)jsonObj.get("name"));  // StudyingAzae 출력

JSONObject에서 get한 뒤에는 .toString()도 가능하지만, 이는 값이 null일 때 에러가 나기때문에 nvl이나 null체크를 넣던지(String)으로 캐스팅하는 것이 좋습니다.

다건 JSON객체 일때(JSONArray)

파일에서 읽은 값이 위와 같은 다건의 json객체라면 JSONArray에 담았다가 JSONObject에 담습니다.

// 상단 코드에 이어 

// obj를 JsonArray로 cast
JSONArray jsonArr = (JSONArray)obj;

// jsonArr에서 하나씩 JSONObject로 cast해서 사용
if (jsonArr.size() > 0){
  for(int i=0; i<jsonArr.size(); i++){
      JSONObject jsonObj = (JSONObject)jsonArray.get(i);
     
      System.out.println((String)jsonObj.get("name")); 
  }
  // StudyingAzae, Soodal 출력
}

다건 JSON객체가 JSON내부에 있을 때

파일에서 읽은 값이 json안에 있는 array라면 위의 JSONObject와 JSONArray를 반복해서 사용하면 됩니다.

// 상단 코드에 이어 

// obj를 우선 JSONObject에 담음
JSONObject jsonMain = (JSONObject)obj;

// jsonObject에서 jsonArray를 get함
JSONArray jsonArr = (JSONArray)jsonMain.get("user");

// jsonArr에서 하나씩 JSONObject로 cast해서 사용
if (jsonArr.size() > 0){
  for(int i=0; i<jsonArr.size(); i++){
      JSONObject jsonObj = (JSONObject)jsonArray.get(i);
     
      System.out.println((String)jsonObj.get("name")); 
  }
  // StudyingAzae, Soodal 출력
}

JSON 형식 변환

예시

위와 같이 자바스크립트 객체를 만들었다. 이제 이 객체를 이용해서 JSON문자열로, 다시 자바스크립트 객체로 변환해보자


이거는 자바스크립트 객체를 JSON문자열로 바꾼것이고

이거는 JSON문자열에서 다시 자바스크립트로 돌려준 것이다.

여기서 의문이 들 수 있다. 왜 바꿔줘야 하는 것인가?

클라이언트와 서버간 데이터를 주고 받을 때는 JSON형식으로 주고 받는게 더 좋다고 한다. 그렇기 때문에 프론트 단에서 서버로 데이터를 보낼 때 JSON 형식으로 바꾸어 보내고, 가져올 때도 JSON형식으로 가져온뒤 다시 자바스크립트 객체로 반환하여 사용한다고 한다.


JSON형태를 자바스크립트로 사용

function jsontest() {    
//json은 키 밸류 값으로 접근이 가능합니다.    
var arr = [ "ktko", 29, "Programmer", "Computer Game"];    
var ktko = {
	"name" : "ktko",            
	"age"  : "29",            
	"job"  : "Programmer",            
	"hobby": "Computer Game"    
}       

document.write("==========Array========== <br/>");    
for(var index in arr) {
	document.write("index : " + index + ", value : " + arr[index] + "<br/>");    
}       

document.write("==========Json Object========== <br/>");
for(var data in ktko) {
	document.write("index : " + data + ", value : " + ktko[data] + "<br>");
	}
}

결과





profile
최선을 다하자!!

1개의 댓글

comment-user-thumbnail
2023년 9월 5일

파이썬으로 json, xml, html 파싱하는 법을 공부하다 이해안되는 부분이 있어 찾아봤는데, 다른 언어라도 덕분에 이해하는데 도움 됐습니다. 감사합니다

답글 달기