본문 바로가기
자바

[Java] 자바에서 XML을 파싱하는 방법 - DOM, SAX

by 책 읽는 개발자_테드 2021. 12. 14.
반응형

XML은 w3c에서 개발된 마크업 언어로, 여러 종류의 데이터를 기술하는 데 사용할 수 있다.

예시 - 주식 정보를 나타내는 XML

<?xml version="1.0" encoding="UTF-8"?>
<stocks>
    <stock>
        <symbol>Citibank</symbol>
        <price>100</price>
        <quantity>1000</quantity>
    </stock>
    <stock>
        <symbol>Axis bank</symbol>
        <price>90</price>
        <quantity>2000</quantity>
    </stock>
</stocks>

 

이러한 XML 문서를 파싱하는 방법에는 대표적으로 DOMSAX가 존재한다. 이 글에서는 두 방식의 차이와 각 방식의 자바 코드 예시를 제공한다.

 

DOM

· XML을 트리 형태의 데이터로 만든 후, 해당 데이터를 가공하는 방식으로 파싱을 진행한다.
· XML 문서를 메모리에 모두 로드한 후 파싱한다.
   - 단점: 메모리를 많이 사용한다.
   - 장점: 구현과 구조변경이 쉽다.

 

코드 예시

파싱할 xml 파일은 위의 stock 정보를 갖는 xml로 한다.

import java.io.File;
import java.nio.file.Paths;

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 DOMParserExam {
   public static void main(String[] args){
      try {
         // 파일 경로
         File stocks = new File(Paths.get("").toAbsolutePath()+"/src/main/java/숙제20211207/Stocks.xml");
         // 파일 읽기
         DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
         DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
         Document doc = dBuilder.parse(stocks);
         doc.getDocumentElement().normalize();

         System.out.println("파일출력");

         // 읽어들인 파일 불러오기
         NodeList nodes = doc.getElementsByTagName("stock");
         for (int k = 0; k < nodes.getLength(); k++) {
            Node node = nodes.item(k);

            if (node.getNodeType() == Node.ELEMENT_NODE) {
               Element element = (Element) node;
               System.out.println("Stock Symbol: " + getValue("symbol", element));
               System.out.println("Stock Price: " + getValue("price", element));
               System.out.println("Stock Quantity: " + getValue("quantity", element));
            }
         }
      } catch (Exception ex) {
         ex.printStackTrace();
      }
   }

   private static String getValue(String tag, Element element) {
      NodeList nodes = element.getElementsByTagName(tag).item(0).getChildNodes();
      Node node = (Node) nodes.item(0);
      return node.getNodeValue();
   }
}

 

SAX

· XML 문서를 라인단위로 체크하면서 파싱하는 방법이다.
· 이러한 이유로 XML 데이터를 모두 메모리에 올려 놓지 않고 파싱을 진행한다.
   - 장점: 메모리를 사용하는 공간이 DOM에 비하여 작다.
   - 단점: 구현과 구조 변경이 어렵다.
· 핸들러를 따로 구현하여 발생한 이벤트를 변수에 저장 활용하는 방식을 사용한다.   

 

코드 예시

파싱할 xml 파일은 위의 stock 정보를 갖는 xml로 한다.

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@ToString
@Getter
@Setter
public class Stock {
   private String symbol;
   private int price;
   private int quantity;
}

 


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

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

public class StocksSaxHandler extends DefaultHandler {
   //파싱한 Stock객체를 넣을 리스트
   private List<Stock> stockList;
   //파싱한 Stock 객체
   private Stock stock;
   //character 메소드에서 저장할 문자열 변수
   private String str;

   public StocksSaxHandler() {
      stockList = new ArrayList<>();
   }

   public void startElement(String uri, String localName, String name, Attributes att) {
      //시작 태그를 만났을 때 발생하는 이벤트
      if(name.equals("stock")) {
         stock = new Stock();
         stockList.add(stock);
      }
   }
   public void endElement(String uri, String localName, String name) {
      //끝 태그를 만났을 때,
      if(name.equals("symbol")) {
         stock.setSymbol(str);
      }else if(name.equals("price")) {
         stock.setPrice(Integer.parseInt(str));
      }else if(name.equals("quantity")) {
         stock.setQuantity(Integer.parseInt(str));
      }
   }
   public void characters(char[] ch, int start, int length) {
      //태그와 태그 사이의 내용을 처리
      str = new String(ch,start,length);
   }
   public List<Stock> getStockList(){
      return stockList;
   }
   public void setStockList(List<Stock> stockList) {
      this.stockList=stockList;
   }
}

 


import java.io.File;
import java.nio.file.Paths;
import java.util.List;

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

public class SAXParserExam {
   public static void main(String[] args) {
      File stocks = new File(Paths.get("").toAbsolutePath()+"/src/main/java/숙제20211207/Stocks.xml");
      SAXParserFactory factory = SAXParserFactory.newInstance();
      try {
         SAXParser parser = factory.newSAXParser();
         StocksSaxHandler handler = new StocksSaxHandler();
         parser.parse(stocks, handler);

         List<Stock> list = handler.getStockList();

         for(Stock stock:list) {
            System.out.println(stock);
         }
      }catch(Exception e) {
         e.printStackTrace();
      }
   }
}

 

출처

 

https://humble.tistory.com/23

https://sangwoo0727.github.io/java/JAVA-29_SAXParser/

반응형

댓글