본문 바로가기

XML & WebServices

SAX(Simple API for XML)

SAX(Simple API for XML)
DOM & SAX

DOM은 XML 문서를 트리 구조로 취급 하므로 다루기 용이하다. 그러나 XML 문서 전체를 읽어 트리로 조립하기에 커다란 XML 문서를 다루는기에는 용이 하지 못한 부분도 있다.
그래서 XML 문서를 다루는 방법으로 DOM과 함께 SAX라고 불리는 방법이 주로 사용 된다.


DOM은 XML 문서 전체를 읽어 들이므로 문서안을 찾으면서 문서의 일부분에 대해 조작을 할 수 있지만 문서 전체를 읽음 으로서 효율성은 저하
SAX의 경우 앞부분 부터 순서대로 읽어 들여 처리하므로 요소나 텍스트를 단순히 추출하는것은 간단하나 문서의 일부분을 조작하는 것은 DOM에 비해 복잡하다.


XML 문서를 앞에서 부터 읽어 들여 거기에 등장하는 요소나 텍스트에 따라 처리를 하는 구조
SAX에서는 XML 문서내 요소의 시작이나 종료를 찾거나, 텍스트가 출현 했을때 핸들러라고 불리는 구조로 그 뜻을 통지한다.
Java의 경우 핸들러를 나타내는 클래스에 문서의 각 부분을 처리하는 메소드를 정의해 두면 문서의 해당 부분이 나타 났을때 메소드가 호출되어 처리된다.
SAX에는 1998년에 규격이 확정된 SAX1과 2000년에 확정된 SAX2가 있다. SAX2는 SAX1에 네임스페이스 기능이 추가 되었다.


앞에서 본 것과 같이 어떤 부분을 찾았을때 자동으로 처리가 행해지는 구조를 이벤트 처리 방식(Event-Driven)이라고 한다. SAX에서는 핸들러를 등록해 두는데 이는 자동으로 호출 된다.
어떤 이름의 메소드가 호출되는가라고 하는 것은 SAX의 규격으로 정의되어 있다.
결국 SAX로 XML 문서를 다루는 애플리케이션을 개발 할 때는 DefaultHandler 클래스를 상속한 핸들러클래스를 작성 하여 적절한 메소드를 기술한다. 그런다음 이 핸들러를 XML 파서에 등록 한다.  


핸들러 소개

  --> startDocument()
            --> startElement()
 
                          --> startElement()


승용차 --> charaters()

--> endElement()

--> endDocument()


SAX의 경우 XML 문서를 순서대로 읽어 들여 처리 하는 구조이다.
문서를 앞 부분 부터 읽어 들이면 다양한 요소나 속성, 텍스트등이 등장 한다. SAX에서는 문서 안의 어떤 부분이 발견 되었을때 핸들러(Handler)라고 불리는 구조에 그 정보를 통지 하도록 되어 있다.  
따라서 프로그램 내부에 핸들러를 기술 함으로서 문서의 각 부분에 따라 처리하는 코드를 작성 하는것이 가능 하다.


car5.xml



승용차
150


트럭
500





SaxExam1.java
import java.io.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

class SaxExam1 {
public static void main(String[] args) throws Exception{
//SAX를 준비한다.
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();

//핸들러를 작성한다.
ExamHandler1 eh = new ExamHandler1();
//핸들러를 등록하여 문서를 읽어 들인다
sp.parse(new FileInputStream("car5.xml"), eh);
}
}
// 핸들러 클래스
// java.org.sax.helpers.DefaultHandler를 상속
class ExamHandler1 extends DefaultHandler{
//문서의 시작
public void startDocument() {

System.out.println("XML 문서가 시작 되었습니다...");
}
//문서의 종료
public void endDocument() {
System.out.println("XML 문서가 종료 되었습니다...");
}
}




핸들러 내에 정의해두면 호출되는 메소드

startDocument ? 문서의 시작 통지를 받음
endDocument ? 문서의 종료 통지를 받음
startElement(String namespaceURI, String localName, String qName, Attributes attrs ) ? 요소의 시작 통지를 받아 들인다.
endElement (String namespaceURI, String localName, String qName) ? 요소의 종료 통지를 받아 들인다.

charaters(char[] ch, int start, int length) ? 문자 데이터의 통지를 받아 들인다.
ignorableWhitespace(char[] ch, int start, int length) ? 요소내의 무시 가능한 공백 통지를 받아들인다.
processingInstruction(String target, String data) ? 처리 명령의 통지를 받아 들인다.


startPrefixMapping(String prefix, String uri) ? 접두사에 의한 네임스페이스 범위의 시작 통지를 받아 들인다.
endPrefixMapping(String prefix) ? 접두사에 의한 네임스페이스 범위의 종료 통지를 받아 들인다.






SaxExam2.java
//문서안의 요소가 등장시 요소명을 출력
import java.io.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

class SaxExam2 {
public static void main(String[] args) throws Exception{
//SAX를 준비한다.
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();

//핸들러를 작성한다.
ExamHandler2 eh = new ExamHandler2();


//문서를 읽어 들인다
sp.parse(new FileInputStream("car5.xml"), eh);
}
}

//------------------- 핸들러 클래스
class ExamHandler2 extends DefaultHandler{
//문서의 시작
public void startDocument() {
System.out.println("XML 문서가 시작 되었습니다...");
}
//문서의 종료
public void endDocument() {
System.out.println("XML 문서가 종료 되었습니다...");
}


//요소의 시작
public void startElement(String namespaceURI,  
         String localName,  
         String qName,  
         Attributes attrs) {
System.out.println(qName+"이(가) 시작됨...");
}
//요소의 종료
public void endElement(String namespaceURI,         String localName,         String qName) {
System.out.println(qName+"이(가) 종료됨...");
}
}




-------------------------------
SAX 예제 ? 텍스트의 처리
-------------------------------
핸들러 클래스에 아래 메소드를 추가

//문자데이터 추가, 텍스트 출현 시 호출
public void characters(char[] ch, int start, int length) {
String str = new String(ch, start, length);
if (str.trim().length() != 0){
System.out.println(str);
}
}




---------------------------------
SAX 예제 ? 요소의 추출
---------------------------------
SaxExam4.java(1) ? car 요소안의 name 요소전체를 추출
import java.io.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
class SaxExam4 {
public static void main(String[] args) throws Exception{
//SAX를 준비한다.
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();

//핸들러를 작성한다.
ExamHandler4 eh = new ExamHandler4();

//문서를 읽어 들인다
sp.parse(new FileInputStream("car5.xml"), eh);
System.out.println("요소 추출 완료~");
}
}
//------------------- 핸들러 클래스
class ExamHandler4 extends DefaultHandler{
StringBuffer sb = new StringBuffer();
boolean isPrint = false;
//문서의 시작시 호출
public void startDocument() {
sb.append("");
sb.append("");
}

//문서의 종료 시 호출
public void endDocument() {
sb.append("
");
//스트링 버퍼의 내용을 파일에 쓴다.
try {
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("result4.xml")));
pw.println(sb);
pw.close();
}
catch (Exception e) { }
}

//요소의 시작시 호출
public void startElement(String namespaceURI,  
                               String localName,            String qName,            Attributes attrs) {
if (qName.equals("name")){
sb.append("<" + qName + ">");
isPrint = true;
}
}
//요소의 종료시 호출
public void endElement(String namespaceURI,       String localName,  
                           String qName) {

if (qName.equals("name")){
sb.append("isPrint = false;
}
}
//문자데이터 추가, 텍스트 출현시 호출, name요소의 텍스만 추출하기 위해 isPrint 변수를 둠…
public void characters(char[] ch, int start, int length) {
String str = new String(ch, start, length);
if (str.trim().length() != 0 && isPrint == true){
sb.append(str);
}
}
}




실행 결과 ? result4.xml



승용차
트럭




----------------------------------------
SAX 예제 ? 속성의 추출
-----------------------------------------
car6.xml ? car의 속성을 추출하여 새로운 결과 XML 요소로…




승용차
150


트럭
500





SaxExam5.java
import java.io.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
class SaxExam5 {
public static void main(String[] args) throws Exception{
//SAX를 준비한다.
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();

//핸들러를 작성한다.
ExamHandler5 eh = new ExamHandler5();

//문서를 읽어 들인다
sp.parse(new FileInputStream("car6.xml"), eh);
System.out.println("속성 추출 완료~");
}
}
//------------------- 핸들러 클래스
class ExamHandler5 extends DefaultHandler{
StringBuffer sb = new StringBuffer();
//문서의 시작시 호출
public void startDocument() {
sb.append("");
sb.append("");
}

//문서의 종료시 호출
public void endDocument() {
sb.append("
");
//스트링 버퍼의 내용을 파일에 쓴다.
try {
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("result5.xml")));
pw.println(sb);
pw.close();
}
catch (Exception e) { }
}

//요소의 시작시 호출
public void startElement(String namespaceURI,       String localName,  
     String qName,  
     Attributes attrs) {
//car라는 요소 발견시 속성이 있다면 있는 동안 반복적으로속성을 요소로 변환하여 읽어 낸다.
  if (qName.equals("car")){
    for(int i=0; isb.append("<" + attrs.getQName(i) + ">");  //속성이름
sb.append(attrs.getValue(i));                       //속성값
sb.append("    }
  }
} }


실행결과 ? result5.xml



한국
미국




-------------------------------------
SAX 예제 ? 태그의 변환
-------------------------------------
car6.xml ? car의 요소를 한글 요소명으로 변환




승용차
150


트럭
500




SaxExam6.java
import java.io.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

class SaxExam6 {
public static void main(String[] args) throws Exception{
//SAX를 준비한다.
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();

//핸들러를 작성한다.
ExamHandler6 eh = new ExamHandler6();


//문서를 읽어 들인다
sp.parse(new FileInputStream("car6.xml"), eh);
System.out.println(" 요소 변환 완료~");
}
}
//------------------- 핸들러 클래스
class ExamHandler6 extends DefaultHandler{
StringBuffer sb = new StringBuffer();

//문서의 시작시 호출
public void startDocument() {
sb.append("");
}


//문서의 종료시 호출
public void endDocument() {
//스트링 버퍼의 내용을 파일에 쓴다.
try {
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("result6.xml")));
pw.println(sb);
pw.close();
}
catch (Exception e) { }
}
//요소의 시작시 호출
public void startElement(String namespaceURI,String localName, String qName,  Attributes attrs) {


//요소명을 변환 한다.
if (qName.equals("cars")){
sb.append("<차리스트>");
}
if (qName.equals("car")){
sb.append("<차>");
}
if (qName.equals("name")){
sb.append("<상품명>");
}
if (qName.equals("price")){
sb.append("<가격>");
}
}


//요소의 종료
public void endElement(String namespaceURI,  String localName,   String qName) {
//변환된 종료 태그를 만든다.
if (qName.equals("cars")){
sb.append("");
}
if (qName.equals("car")){
sb.append("");
}
if (qName.equals("name")){sb.append(""); }
if (qName.equals("price")){sb.append("");}
}


//문자데이터 추가, 텍스트 출현시 호출
public void characters(char[] ch, int start, int length) {
String str = new String(ch, start, length);
if (str.trim().length() != 0){
sb.append(str);
}
}
}


실행결과 ? result6.xml


<차리스트>
<차>
<상품명>승용차
<가격>150

<차>
<상품명>트럭
<가격>500
출처 julymorning4님의 블로그 | 오라클러
원본 http://blog.naver.com/julymorning4/100019597082