XML parsing

1c2·2024년 1월 25일
0

JAVA

목록 보기
12/13

데이터의 형태

  • CSV
    • comma sepaerate value
  • XML
    • 태그를 통해 데이터 형식 정의
  • Json
    • JSON(JavaScript Object Notation)d을 통해 데이터 형식 정의
  • 데이터의 형식

기본 문법

  • 문서의 시작은 <?xml version="1.0" encodong = "UTF-8"?>
  • 반드시 root element가 존재해야 한다.
    • 나머지 태그들은 Tree 형태로 구성된다.
  • 시작태그와 종료 태그는 일치해야 한다.
  • 시작 택는 key-value 구조의 속성을 가질 수 있다.
    • 속성 값은 " " 또는 ' '로 묶어서 표현한다.
  • 태그는 대소문자를 구별한다.

valid

  • xml 태그는 자유롭게 생성하기 때문에 최초 작성자의 의도대로 작서되는지 확인할 필요

    • 문서의 구조와 적절한 요소,, 속성들의 개수, 순서들이 잘 지켜졌는가?

    • DTD 또는 Schema를 이용해서 문서의 규칙 작성

    • DTD, Schema를 잘 따는 문서를 "valid 하다" 라고 함

파싱

  • 문서에서 필요한 정보를 얻기 위해 태그를 구별하고 내용을 추출하는 과정
    • 전문적인 parser 활용
  • SAX parser
    • Simple API for XML parser
    • 문서를 읽으면서 태그의 시작, 종료 등 이벤트 기반으로 처리하는 방식
  • DOM parser
    • Document Object Model parser
    • 문서를 다 읽고 난 후 문서 구조 전체를 자료구조에 저장하여 탐색하는 방식
  • SAX는 빠르고 한번에 처리하기 때문에 다양한 탐색이 어렵다.
  • DOM은 다양한 탐색이 가능하지만 느리고 무거우며 큰 문서를 처리하기 어렵다.

동작방식

  • 문서를 읽다가 발생하는 이벤트 기반으로 문서 처리
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

//import com.fasterxml.jackson.annotation.JsonIgnoreProperties;


public class BoxOffice {
    private Integer rank; // 등수
    private String movieNm; // 영화제목
    private Date openDt; // 개봉일
    private Integer audiAcc;// 누적 관객 수

    public Integer getRank() {
        return rank;
    }

    public void setRank(Integer rank) {
        this.rank = rank;
    }

    public String getMovieNm() {
        return movieNm;
    }

    public void setMovieNm(String movieNm) {
        this.movieNm = movieNm;
    }

    public Date getOpenDt() {
        return openDt;
    }

    public void setOpenDt(Date openDt) {
        this.openDt = openDt;
    }

    public Integer getAudiAcc() {
        return audiAcc;
    }

    public void setAudiAcc(Integer audiAcc) {
        this.audiAcc = audiAcc;
    }

    public Date toDate(String date) {
        Date dateObj = null;
        // TODO: 문자열 형태의 날짜를 Date로 변환해서 반환하시오.
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        try {
			dateObj = format.parse(date);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			dateObj = new Date();
		}
        // END
        return dateObj;
    }

    @Override
    public String toString() {
        return "[rank=" + rank + ", movieNm=" + movieNm + ", openDt=" + openDt + ", audiAcc="
                + audiAcc + "]";
    }
}

SAX parser

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

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

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

import com.ssafy.day9.a_parse.dto.BoxOffice;

public class BoxOfficeSaxParser extends DefaultHandler implements BoxOfficeParser {
    // TODO: singleton 형태로 작성해보자.
	private static BoxOfficeSaxParser parser = new BoxOfficeSaxParser();
	
	private BoxOfficeSaxParser() {
		this.list = new ArrayList<>();
	}
	
	public static BoxOfficeSaxParser getParser() {
		return parser;
	}
    // END

    // 파싱된 내용을 저장할 List
    private List<BoxOffice> list ;
    // 현재 파싱하고 있는 대상 객체
    private BoxOffice current;
    // 방금 읽은 텍스트 내용
    private String content;

    @Override
    public List<BoxOffice> getBoxOffice(InputStream resource) {
        list = new ArrayList<>();
        // TODO: SAXParser를 구성하고 boxoffice.xml을 파싱하시오.
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser;
        try {
        	parser = factory.newSAXParser();
			parser.parse(resource, this);
		} catch (SAXException |ParserConfigurationException | IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
        // END
        return list;
    }

    // TODO: 필요한 매서드를 재정의 하여 boxOffice.xml을 파싱하시오.
    @Override
    public void startDocument() throws SAXException{
    	System.out.println("문서 시작");
    }
    @Override
    public void endDocument() throws SAXException{
    	System.out.println("문서 끝");
    }
    @Override
    public void startElement(String uri, String locaName, String qName, Attributes attributes)throws SAXException {
    	if(qName.equals("dailyBoxOffice")) {
    		current = new BoxOffice();
    	}
    }
    @Override
    public void endElement(String uri, String locaName, String qName) {
    	if(qName.equals("rank")) {
    		current.setRank(Integer.parseInt(content));
    	} else if(qName.equals("movieNm")) {
    		current.setMovieNm(content);
    	} else if (qName.equals("openDt")) {
    		current.setOpenDt(current.toDate(content));
    	} else if(qName.equals("audiAcc")) {
    		current.setAudiAcc(Integer.parseInt(content));
    	} else if(qName.equals("dailyBoxOffice")) {
    		list.add(this.current);
    		this.current = null;
    	}
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException{
    	this.content = String.valueOf(ch, start, length);
    }
    
    // END
}

DOM parser

동작 방식

  • 문서를 완전히 메모리에 로딩 후 필요한 내용 찾기
  • DOM Tree
    • 문서를 구성하는 모든 요소를 Node(태그, 속성, 값)로 구성
    • 태그들은 root 노드(주소록)을 시작으로 부모-자식의 관계 구성

유용한 API들

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

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 com.ssafy.day9.a_parse.dto.BoxOffice;

public class BoxOfficeDomParser implements BoxOfficeParser {

    private static BoxOfficeDomParser parser = new BoxOfficeDomParser();

    public static BoxOfficeDomParser getParser() {
        return parser;
    }

    private BoxOfficeDomParser() {
        System.out.println("DOM parser");
    }

    private List<BoxOffice> list;

    @Override
    public List<BoxOffice> getBoxOffice(InputStream resource) {
        list = new ArrayList<>();
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 문서 로딩 완료 --> 원하는 요소들 골라내기
            Document doc = builder.parse(resource);
            // 최 상위 element
            Element root = doc.getDocumentElement();
            parse(root);
        } catch (IOException | ParserConfigurationException | SAXException e) {
            e.printStackTrace();
        }
        return list;
    }

    private void parse(Element root) {
        // TODO: root에서 dailyBoxOffice를 추출한 후 BoxOffice를 생성해 list에 저장하시오.
    	NodeList list = root.getElementsByTagName("dailyBoxOffice");
    	for(int i= 0;i < list.getLength();i++) {
    		Node child = list.item(i); //boxoffice 정보
    		BoxOffice bo = getBoxOffice(child);
    		this.list.add(bo);
    	}
        // END
    }

    private static BoxOffice getBoxOffice(Node node) {
        BoxOffice boxOffice = new BoxOffice();
        // TODO: node 정보를 이용해서 BoxOffice를 구성하고 반환하시오.
        NodeList subNodes = node.getChildNodes();
        for(int i = 0;i < subNodes.getLength();i++) {
        	Node sub = subNodes.item(i);
        	if(sub.getNodeName().equals("rank")) {
        		boxOffice.setRank(Integer.parseInt(sub.getTextContent()));
        		
        	} else if(sub.getNodeName().equals("MovieNm")) {
        		boxOffice.setMovieNm(sub.getTextContent());
        	
        	} else if (sub.getNodeName().equals("audiAcc")) {
        		boxOffice.setAudiAcc(Integer.parseInt(sub.getTextContent()));
        	}
        		
        }
        
        // END
        return boxOffice;
    }
}

Json

  • Javascript Object Notation (자바스크립트에서의 객체 표현법)
  • 간결한 문법, 단순한 텍스트 적은 용량으로 대부분의 언어, 대부분의 플랫폼에서 사용 가능

0개의 댓글