Junior Backend Developer

XML Parsing

이번 포스팅에선 JAVA에서의 XML Parsing에 대해 알아보고자 한다.


XML

  • eXtensible Markup Language
  • 데이터 저장, 교환, 공유 등에 초점을 맞춘 언어
<?xml version="1.0" encoding="UTF-8"?>
<People>
	<Person>
		<name>홍길동</name>
		<age>26</age>
		<gender>Male</gender>
	</Person>
	<Person>
		<name>김갑순</name>
		<age>30</age>
		<gender>Female</gender>
	</Person>
</People>

JAVA XML Parser

  • parsing이란, “일련의 문자열을 의미있는 토큰으로 분해하고, 그것들로 이루어진 파스트리를 만드는 과정”이다.
  • java의 xml parser는 SAXParser와 DOMParser가 있다.


DOMParser

  • DOM방식은 문서 전체를 메모리에 로드하여 원하는 노드에 바로 접근하여 추가 수정을 할 수 있다.
  • XML 문서를 읽으면 모든 element, text, attribute등에 대한 객체를 생성하고, 이를 Document 객체로 반환한다.
  • Document 객체는 DOM API에 알맞는 트리 구조의 자바 객체로 표현되어있다.
  • XML 문서가 메모리에 모두 올라가 있어서 노드들의 검색, 수정, 구조 변경이 빠르고 용이하다.

SAXParser

  • java는 SAX방식 api를 제공한다.
  • 이벤트 기반으로, 문서를 앞에서부터 순차적으로 읽어가면서 노드가 열리고 닫히는 과정에서 이벤트가 발생한다.
  • 각각의 이벤트가 발생할 때마다 수행하고자 하는 기능을 EventHandler를 사용하여 구현한다.
  • XML 문서를 메모리에 전부 로딩하고 파싱하는 것이 아니기에 메모리 사용량이 적고 가볍다.
  • 단점으로는 특정 노드를 무작위로 접근하는 random access가 어렵다는 점이다.

method

  • startElement() : 태그를 처음 만나면 발생하는 이벤트
  • endElement() : 닫힌 태그를 만나면 발생하는 이벤트
  • characters() : 태그와 태그 사이의 text를 처리하기 위한 이벤트
<?xml version="1.0" encoding="UTF-8"?>
<People>
	<person>
		<age>30</age>
		<name>홍길동</name>
		<gender>Male</gender>
		<role>Java Developer</role>
	</person>
	<person>
		<age>30</age>
		<name>김철수</name>
		<gender>Male</gender>
		<role>Designer</role>
	</person>
	<person>
		<age>21</age>
		<name>김영희</name>
		<gender>Female</gender>
		<role>FrontEnd</role>
	</person>
	<person>
		<age>28</age>
		<name>김영심</name>
		<gender>Female</gender>
		<role>MD</role>
	</person>
</People>

위 코드는 간단한 xml 파일을 불러온 것이다. 이 xml 파일을 SAXParser를 통해 파싱해보고자 한다.
먼저 xml을 파싱하여 저장할 person class를 간단히 setter와 getter를 통해 작성한다.

public class Person {
	private int age;
	private String name;
	private String gender;
	private String role;
	public Person() {
	};
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	@Override
	public String toString() {
		return "이름:"+name+" 나이:"+age+" 성별:"+gender+" 직책:"+role+"\n";
	}
}

SAXParser를 사용하려면 먼저 DefaultHandler를 상속받는 Handler클래스를 작성해야 한다.

import java.util.ArrayList;
import java.util.List;

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

public class PeopleSaxHandler extends DefaultHandler{
	
	//파싱한 사람객체를 넣을 리스트
	private List<Person> personList;
	//파싱한 사람 객체
	private Person person;
	//character 메소드에서 저장할 문자열 변수
	private String str;
	
	public PeopleSaxHandler() {
		personList = new ArrayList<>();
	}
	
	public void startElement(String uri, String localName, String name, Attributes att) {
		//시작 태그를 만났을 때 발생하는 이벤트
		if(name.equals("person")) {
			person = new Person();
			personList.add(person);
		}
	}
	public void endElement(String uri, String localName, String name) {
		//끝 태그를 만났을 때,
		if(name.equals("age")) {
			person.setAge(Integer.parseInt(str));
		}else if(name.equals("name")) {
			person.setName(str);
		}else if(name.equals("gender")) {
			person.setGender(str);
		}else if(name.equals("role")) {
			person.setRole(str);
		}
	}
	public void characters(char[] ch, int start, int length) {
		//태그와 태그 사이의 내용을 처리
		str = new String(ch,start,length);
	}
    public List<Person> getPersonList(){
		return personList;
	}
	public void setPersonList(List<Person> personList) {
		this.personList=personList;
	}
}

위에서 언급한 세 가지 메서드에 대해 이해하기 쉬운 간단한 코드를 작성해보았다.

package xml;

import java.io.File;
import java.util.List;

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

public class PersonSaxTest {
	public static void main(String[] args) {
		File file = new File("./src/xml/people.xml");
		SAXParserFactory factory = SAXParserFactory.newInstance();
		
		try {
			SAXParser parser = factory.newSAXParser();
			PeopleSaxHandler handler = new PeopleSaxHandler();
			parser.parse(file, handler);
			
			List<Person> list = handler.getPersonList();
			
			for(Person p:list) {
				System.out.println(p);
			}
		}catch(Exception e) {
			e.printStackTrace();
		}	
	}
}

file 대신 api 키로 만들어진 url 주소를 넣어도 똑같이 동작한다.
출력을 통해 xml파일을 원하는 대로 파싱하여 출력한 결과를 확인할 수 있다.


설명 출처
설명 출처2