JSON이란? 속성-값 쌍 또는 키-값 쌍으로 이루어진 데이터 오브젝트를 전달하기 위해 인간이 읽을 수 있는 텍스트를 사용하는 개방형 표준 포맷이다. 비동기 브라우저/서버 통신 을 위해, 넓게는 XML을 대체하는 주요 데이터 포맷이다.

XML이란? W3C에서 개발된, 다른 특수한 목적을 갖는 마크업 언어를 만드는데 사용하도록 권장하는 다목적 마크업 언어이다. 

 

1) JSON 파싱

mvnrepository.com/artifact/org.json/json

 

Maven Repository: org.json » json

JSON is a light-weight, language independent, data interchange format. See http://www.JSON.org/ The files in this package implement JSON encoders/decoders in Java. It also includes the capability to convert between JSON and XML, HTTP headers, Cookies, and

mvnrepository.com

 

위 MavenRepository에 들어가서 JSON을 파싱하여 사용하기 위한 라이브러리를 다운받아서 프로젝트에 등록한다.

 

 

		//StringBuffer를 쓴 이유는? String은 불변의 특징이 있으므로, 너무 많은 문자열 상수를 만들어내지 않기 위해
		StringBuffer sb = new StringBuffer();
		sb.append("{");
		sb.append("\"name\":\"hyuk\"");
		sb.append("}");
        
        //sb에 담겨진 표기는, 실제 JSON 객체는 아니므로, 파싱단계를 거쳐 JSON 객체로 전환해야 한다!!
		//JSON파서는 자바 자체적으로 지원하지 않으므로 외부 라이브러리를 이용하여 파싱업무를 시도하자!!
		//주로 무료 기반(오픈소스)의 외부 라이브러는 아파치 재단에서 운영되는 maven 사이트 이용하자!
		JSONParser jsonParser = new JSONParser();//구문을 분석하는 파서객체 생성
		
		try {
			JSONObject obj = (JSONObject)jsonParser.parse(sb.toString());//파싱시작!!
			//파싱이 완료된 이후부터는 더이상 문자열이 아닌, json 객체로 사용하면 된다!!
			//JSON은 키와 밸류의 형태!!!
			System.out.println(obj.get("name"));//get(키값)
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}

JSONParser를 이용하여 파싱을 하여 JSONObject 객체로 반환받아서 JSON데이터의 키값을 이용하여 값을 얻어올 수 있다!!

위 코드의 출력결과

2) XML 파싱

XML 파싱은 JSON과 다르게 좀 더 복잡하다..

- jAVA에서 제공하는 SAXParser라는 추상 클래스를 제공한다.

- SAXParser는 SAXParserFactory의 newSAXParser()메서드를 이용하여 인스턴스를 얻을 수 있다.

- SAXParserFactory는 추상클래스로 SAXParserFactory의 static메서드인 newInstance()를 이용하여 인스턴스를 얻을 수 있다.

- SAXParser는 DefaultHandler를 상속받는 핸들러클래스를 재정의하여 파싱할 수 있다...

- 말만 들어도 복잡하다..

<?xml version="1.0" encoding="UTF-8"?>
<pets>
	<pet>
		<type>dog</type>
		<name>뽀미</name>
		<age>9</age>
		<gender>여</gender>
	</pet>
	<pet>
		<type>cat</type>
		<name>나비</name>
		<age>3</age>
		<gender>여</gender>
	</pet>
</pets>

이러한 XML파일이 있다. 파싱을 하기 위해

/*
	XML의 모든 노드에서 이벤트가 발생할때마다 아래의 핸들러 객체의 메서드를 
	알맞게 오버라이드하면 됨.
*/
package day1113.xml;

import java.util.ArrayList;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class MyHandler extends DefaultHandler {
	ArrayList<Pet> petList;
	Pet pet;
	boolean isType;
	boolean isName;
	boolean isAge;
	boolean isGender;

	// 문서가 시작되면 호출됨
	@Override
	public void startDocument() throws SAXException {
		System.out.println("문서를 시작합니다");
	}

	// 여는 태그 만났을때 호출됨 <태그> (/가 없는 태그)
	@Override
	public void startElement(String uri, String localName, String tag, Attributes attributes) throws SAXException {
		// TODO Auto-generated method stub
		System.out.print("<" + tag + ">");

		// 여러 태그 중 pets를 만나면 ArrayList를 생성하자!!
		if (tag.equals("pets")) {
			petList = new ArrayList<Pet>();
		} else if (tag.equals("pet")) { // 하나의 pet 인스턴스 생성할 타임이다!!
			pet = new Pet();
		} else if (tag.equals("type")) { // ???
			// 시작 태그를 지금 지나가고 있음을 알려주자!!!
			isType = true;
		} else if (tag.equals("name")) { // ???
			isName = true;
		} else if (tag.equals("age")) { // ???
			isAge = true;
		} else if (tag.equals("gender")) { // ???
			isGender = true;
		}

	}

	// 태그와 태그사이의 데이터를 만났을 때 호출
	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		String data = new String(ch, start, length);
		System.out.print(data);
		if(isType) {
			pet.setType(data);			
		}else if(isName) {
			pet.setName(data);
		}else if(isAge) {
			pet.setAge(Integer.parseInt(data));
		}else if(isGender) {
			pet.setGender(data);
		}
	}

	// 닫는 태그를 만났을 때
	@Override
	public void endElement(String uri, String localName, String tag) throws SAXException {
		System.out.print("</" + tag + ">");
		
		if (tag.equals("pet")) { // 이 시점에 하나의 Pet이 완성된 시점이므로, 리스트에 담아두자!!
			petList.add(pet);
		} else if (tag.equals("type")) { // ???
			// 실행부가 지나가고 있는 위치를 알려주는 모든 논리값들을 다시 초기화!!
			isType = false;
		} else if (tag.equals("name")) { // ???
			// 실행부가 지나가고 있는 위치를 알려주는 모든 논리값들을 다시 초기화
			isName = false;
		} else if (tag.equals("age")) { // ???
			// 실행부가 지나가고 있는 위치를 알려주는 모든 논리값들을 다시 초기화
			isAge = false;
		} else if (tag.equals("gender")) { // ???
			// 실행부가 지나가고 있는 위치를 알려주는 모든 논리값들을 다시 초기화
			isGender = false;
		}
	}

	// 문서가 끝날 때
	@Override
	public void endDocument() throws SAXException {
		System.out.println("문서를 종료합니다");
		System.out.println("결과 보고서 : 총 " + petList.size() + "가 존재합니다.");
		for(Pet pet : petList) {
			System.out.println("type : " + pet.getType());
			System.out.println("name : " + pet.getName());
			System.out.println("age : " + pet.getAge());
			System.out.println("gender : " + pet.getGender());
			System.out.println("-------------------------------------------");
		}
	}
}

startDocument 메서드는 문서시작 시 호출되는 메서드
startElement 메서드는 열린태그를 만났을 시 호출되는 메서드
characters 메서드는 태그안의 데이터를 만났을 시 호출되는 메서드
endElement 메서드는 닫는태그를 만났을 시 호출되는 메서드 
endDocument 메서드는 문서 종료 시 호출되는 메서드

위 코드를 보면 어떤 형식으로 진행되는지 이해할 수 있을 것이다..

 

아래는 재정의한 핸들러를 사용하여 xml을 파싱하는 코드)

/*
 * java로 xml를 파싱하는 방법은 크게 2가지 있다.
 * 1)DOM 방식 - html과 같은 원리...
 * 						즉, 모든 태그마다 1:1대응하는 DOM객체를 메모리에 생성해놓고 프로그래밍언어에서 필요한 객체를 접근하는 방식
 * 						예) javascript - DOM
 * 						무거운 DOM객체가 메모리에 부하를 일으킬 수 있다.. 특히 메모리크기가 pc에 비해 상대적으로 작은 디바이스의 경우 DOM방식은 적절치못하다!!
 * 2)SAX 방식 - xml문서를 이루는 엘리먼트, 텍스트 등의 모든 노드에 대한 이벤트를 발생시켜주는 방식
 * 					따라서 개발자는 적절한 자바의 객체를 메모리에 올려, xml을 대신하여 데이터를 사용하면 된다!!
 * 
*/
package day1113.xml;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;

public class XMLParseApp {
	// 실행중인 자바프로세스가 파일에 접근하기 위해서는 파일입력스트림 계열이 필요하다!
	FileInputStream fis;
	InputStreamReader reader;
	BufferedReader buffr;
	File file;
	URL url;
	URI uri;
	
	public XMLParseApp() {
		url = this.getClass().getClassLoader().getResource("res/pets.xml");
		try {
			uri = url.toURI(); // File 클래스의 생성자에서는 URL이 아닌 URI를 원하므로, 변환하자!
			fis = new FileInputStream(file = new File(uri)); //스트림얻기!! 현재 1byte씩얻는상태
			parseData(); //파싱시작!!
			
		} catch (URISyntaxException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} finally {
			if(fis!=null) {
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	//xml파싱해보자!!
	public void parseData() {
		//SAX방식의 파서는 SAXParserFactory 객체로부터 얻는다.
		SAXParserFactory factory; 
		factory = SAXParserFactory.newInstance(); //static메서드를 이용하여 인스턴스얻음
		try {
			SAXParser saxParser=factory.newSAXParser();//Factory로부터 파서의 인스턴스를 얻을 수 있다..
			saxParser.parse(fis, new MyHandler());
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void readTest() {
		try {
			
			//육안으로 확인할 때 한글이 깨질 수 있으므로, Reader로 업그레이드하자
			reader = new InputStreamReader(fis); //문자로 얻는 걸로 업그레이드
			buffr = new BufferedReader(reader);// 한 줄씩 얻는 걸로 업그레이드
			//한문자씩 읽어들이면 너무 시간이 오래걸리므로, 한줄씩 읽어 들이기
			
			//파싱은 나중에하고, 먼저 xml을 제대로 스트림으로 읽어들일 수 있는 지 체크
			String data = null;
			while(true) {
				data = buffr.readLine();
				if(data==null) break;
				System.out.println(data);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

	public static void main(String[] args) {
		new XMLParseApp();
	}
}

 

Pet클래스(VO)

/*
	한마리의 반려동물을 담게 될 VO 클래스
	VO란? Value Object의 약자로서, [로직 작성이 목적이 아닌 단지 데이터만을 보관할 용도로 사용되는 객체]를 가리키는 애플리케이션 설계 용어 중 하나!
*/
package day1113.xml;

public class Pet {
	private String type;
	private String name;
	private int age;
	private String gender;

	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
}

위 코드의 출력결과

지금봐도 너무 어렵다... 여러번 봐야할 것 같다.. ㅠ

+ Recent posts