본문 바로가기

머리쓰기

[Java2XML] SAX 구현 방법 정리

- 다음 자료는 SDS 온라인 강의 자료를 기초로 작성하였습니다. 이전에 XML 관련 파싱 프로그램 개발시에는 라이브러리를 가져다 쓰기만해서 코드에 대한 이해도가 많이 떨어졌었는데, 공부를 통해서 정리를 하니 XML 관련한 코드 개
발시에 많이 도움이 될듯 하네요. 역시 프로그래밍에는 많이 공부한 사람이 잘하게 되어 있는 것 같네요. :-)


  • 목 적
다음은 SAX를 이용한 XML 문서 처리 방법을 알아본다. 이때 사용되어지는 Handler를
알아보고 구현 방법을 알아본다.


  • SAX에 대해서
SAX는 XML 문서를 맨 앞부터 순차적으로 읽어 가면서 요소, 속성 그리고 텍스트가 인식될
때마다 이벤트를 발생한다. 각 이벤트가 발생할 때마다 등록된 핸들러의 정해진 메소드들이
호출되는 방법으로 문서를 처리 한다.

구현 순서는 다음과 같다.

1. 목적에 맞는 이벤트를 처리할 핸들러 메소드들을 작성한다.
2. SAX 객체를 생성한다.
3. 생성된 SAX 객체와 핸들러 객체를 통해 XML 문서를 읽어 들인다.


  • 핸들러(인터페이스)별 메소드 설명
- org.xml.sax.ContentHandler
    SAX의 핵심으로, 일반적인 문서 이벤트를 처리한다. 문서의 시작, 요소의 시작과 끝, 요소가
    포함하는 내용의 문자를 만날 때 호출된다.
   
    + void characters(char[] ch, int start, int length)
        문자데이터가 인식되면 호출된다.
    + void endDocument()
        문서의 끝이 인식되면 호출된다.
    + void endElement(String namespaceURI, String localName, String qName)
        요소의 종료가 인식되면 호출된다.
    + void endPrefixMapping(String prefix)
        prefix-URI 이름 공간의 종료가 인식되면 호출된다.
    + void ignorableWhitespace(char[] ch, int start, int length)
        요소 내용에서 무시 가능한 공백이 인식되면 호출된다.
    + void processingInstruction(String target, String data)
        PI가 인식되면 호출된다.
    + void setDocumentLocator(Locator locator)
        이벤트가 발생된 위치 정보를 알려 주는 객체 전달 시 호출된다.
    + void skippedEntity(String name)
        스킵된 엔티티가 인식되면 호출된다.
    + void startDocument()
        문서의 시작이 인식되면 호출된다.
    + void startElement(String namespaceURI, String localName, String qName, Attributes atts)
        요소의 시작이 인식되면 호출된다.
    + void startPrefixMapping(String prefix, String uri)
        prefix-URI 이름 공간의 시작이 인식되면 호출된다.
       
- org.xml.sax.DTDHandler
    기본적인 파싱에 있어 요구되는 DTD 이벤트를 핸들링하기 위해 호출된다. 즉 표기법과 파싱되지
    않는 엔티티(entity)선언을 만날 때 호출 된다.

    + void notationDecl(String name, String pulbicId, String systemId)
        DTD 선언 이벤트가 인식되면 호출된다.
    + void unparsedEntityDecl(String name, String publicId, String systemId, String notationName)
        파싱되지 않는 엔티티 선언 이벤트가 인식되면 호출된다.
               
- org.xml.sax.EntityResolver
    외부 엔티티를 참조하기 위하여 호출된다. 만일 문서에 외부 엔티티 참조가 없다면, 이 인터페이스는
    필요 없다.

    + InputSource resolveEntity(String publicId, String systemId)
        확장 엔티티 처리와 관련된 기능을 처리한다.
       
- org.xml.sax.ErrorHandler
    에러를 처리하기 위해 사용된다. 파서는 모든 경고와 에러를 처리하기 위해 이 핸들러를 사용한다.

    + void error(SAXParseException exception)
        복구 가능한 오류 발생시 호출된다.
    + void fatalError(SAXParseException exception)
        복구 불가능한 오류 발생시 호출된다.
    + void warning(SAXParseException exception)
        경고 오류 발생시 호출된다.
       

  • 핸들러(인터페이스)의 구현 최소화
    각 핸들러 구현시 많은 메소드가 존재하기 때문에 구현시에 모든 메소드를
    오버라이드 구현하기에는 많은 일이 필요하게 된다.
   
    그래서 불필요한 메소드에 대한 구현 할 필요 없도록 하나의 클래스에 모든
    인터페이스를 상속해 필요한 메소드만 구현 할 수 있도록 하나의 클래스를
    만들었으며 클래스명은 다음과 같다.
   
    org.xml.sax.helpers.DefaultHandler
   
    위 클래스를 이용해 자신에게 필요한 메소드만 오버라이드 하면 된다.
   
   
  • Sample code
- SAXHandlerSample.java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

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;


public class SAXHandlerSample {

    /**
     * @param args
     * @throws SAXException
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws FileNotFoundException
     */
    public static void main(String[] args) throws ParserConfigurationException, SAXException, FileNotFoundException, IOException {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser sp = spf.newSAXParser();
       
        // Create handler
        SampleHandler handler = new SampleHandler();
        sp.parse(new FileInputStream("C:\\DEV\\workspace\\ws01\\Java2XML\\src\\Sample.xml"), handler);
    }
}

class SampleHandler extends DefaultHandler {
    StringBuffer sb = new StringBuffer();
    boolean isPrint = false;
   
    @Override
    public void startDocument() throws SAXException {
        System.out.println("Start XML Document");
    }
   
    @Override
    public void endDocument() throws SAXException {
        System.out.println("End XML Document");
    }
   
    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        System.out.println("Start : " + qName);
    }
   
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        System.out.println("End : " + qName);
    }
   
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        String str = new String(ch, start, length);
        if (str.trim().length() != 0) {
            System.out.println(str);
        }
    }   
}


- Sample.xml
<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <Child>Child 01</Child>
    <Child>Child 02</Child>
</Root>

  • 실행시 결과 화면
Start XML Document
Start : Root
Start : Child
Child 01
End : Child
Start : Child
Child 02
End : Child
End : Root
End XML Document