187 lines
6.3 KiB
Markdown
187 lines
6.3 KiB
Markdown
# **XML SAX Parser 쉽게 배우기**
|
|
|
|
## **1. SAX Parser란?**
|
|
SAX(Simple API for XML) Parser는 XML 문서를 **한 줄씩 읽으며 이벤트 기반으로 처리하는 방식**이다.
|
|
|
|
✔ **장점**:
|
|
- XML 문서를 **메모리에 전부 로드하지 않음 → 메모리 효율적**
|
|
- **빠르게 읽기 가능**
|
|
|
|
✔ **단점**:
|
|
- **문서 내 특정 요소를 수정하거나 추가하기 어려움**
|
|
- **XML을 트리 형태로 다루지 않음 → 앞에서 읽은 데이터 유지 불가**
|
|
|
|
**➡ 적절한 사용 사례:**
|
|
- **대용량 XML 파일을 빠르게 읽을 때**
|
|
- **읽기 전용(XML을 수정할 필요가 없는 경우)**
|
|
|
|
---
|
|
|
|
## **2. 주요 메서드 정리**
|
|
|
|
| 메서드 | 설명 |
|
|
|-----|----|
|
|
| `SAXParserFactory.newInstance()` | `SAXParserFactory` 객체 생성 |
|
|
| `SAXParserFactory.setNamespaceAware(true)` | 네임스페이스 인식 설정 |
|
|
| `SAXParserFactory.setValidating(true)` | XML 유효성 검사 설정 |
|
|
| `SAXParserFactory.newSAXParser()` | `SAXParser` 객체 생성 |
|
|
| `SAXParser.parse(File file, DefaultHandler handler)` | XML 파일을 읽고 핸들러로 전달 |
|
|
| `DefaultHandler.startDocument()` | 문서의 시작을 처리 |
|
|
| `DefaultHandler.endDocument()` | 문서의 끝을 처리 |
|
|
| `DefaultHandler.startElement(String uri, String localName, String qName, Attributes attributes)` | 요소의 시작을 처리 |
|
|
| `DefaultHandler.endElement(String uri, String localName, String qName)` | 요소의 끝을 처리 |
|
|
| `DefaultHandler.characters(char[] ch, int start, int length)` | 요소의 텍스트 데이터를 처리 |
|
|
|
|
---
|
|
|
|
## **3. XML 문서 예제**
|
|
|
|
아래 XML 문서를 이용하여 SAX Parser를 적용해 보자.
|
|
|
|
```xml
|
|
<books>
|
|
<book id="1">
|
|
<title>자바 프로그래밍</title>
|
|
<author>홍길동</author>
|
|
<price>30000</price>
|
|
</book>
|
|
<book id="2">
|
|
<title>데이터베이스 개론</title>
|
|
<author>이몽룡</author>
|
|
<price>25000</price>
|
|
</book>
|
|
</books>
|
|
```
|
|
|
|
---
|
|
|
|
## **4. SAX Parser로 XML 읽기**
|
|
|
|
### **✔ SAX Parser를 사용하여 XML 데이터 출력하기**
|
|
아래 코드는 `SAXParser`를 사용하여 XML 파일을 읽고, 책 정보를 출력하는 예제이다.
|
|
|
|
```java
|
|
import org.xml.sax.*;
|
|
import org.xml.sax.helpers.DefaultHandler;
|
|
|
|
import javax.xml.parsers.*;
|
|
import java.io.File;
|
|
|
|
public class SAXParserExample {
|
|
public static void main(String[] args) {
|
|
try {
|
|
// 1. SAXParserFactory 생성
|
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
|
SAXParser saxParser = factory.newSAXParser();
|
|
|
|
// 2. 핸들러 설정
|
|
DefaultHandler handler = new DefaultHandler() {
|
|
boolean isTitle = false;
|
|
boolean isAuthor = false;
|
|
boolean isPrice = false;
|
|
|
|
// 문서의 시작
|
|
public void startDocument() {
|
|
System.out.println("XML 파싱 시작");
|
|
}
|
|
|
|
// 문서의 끝
|
|
public void endDocument() {
|
|
System.out.println("XML 파싱 종료");
|
|
}
|
|
|
|
// 요소의 시작 태그
|
|
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
|
if (qName.equalsIgnoreCase("book")) {
|
|
System.out.println("\n책 ID: " + attributes.getValue("id"));
|
|
} else if (qName.equalsIgnoreCase("title")) {
|
|
isTitle = true;
|
|
} else if (qName.equalsIgnoreCase("author")) {
|
|
isAuthor = true;
|
|
} else if (qName.equalsIgnoreCase("price")) {
|
|
isPrice = true;
|
|
}
|
|
}
|
|
|
|
// 요소의 끝 태그
|
|
public void endElement(String uri, String localName, String qName) {
|
|
if (qName.equalsIgnoreCase("title")) {
|
|
isTitle = false;
|
|
} else if (qName.equalsIgnoreCase("author")) {
|
|
isAuthor = false;
|
|
} else if (qName.equalsIgnoreCase("price")) {
|
|
isPrice = false;
|
|
}
|
|
}
|
|
|
|
// 요소 안의 텍스트 처리
|
|
public void characters(char[] ch, int start, int length) {
|
|
String text = new String(ch, start, length).trim();
|
|
if (!text.isEmpty()) {
|
|
if (isTitle) {
|
|
System.out.println("제목: " + text);
|
|
} else if (isAuthor) {
|
|
System.out.println("저자: " + text);
|
|
} else if (isPrice) {
|
|
System.out.println("가격: " + text);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// 3. XML 파일 파싱
|
|
File xmlFile = new File("books.xml");
|
|
saxParser.parse(xmlFile, handler);
|
|
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**🔹 실행 결과**
|
|
```
|
|
XML 파싱 시작
|
|
|
|
책 ID: 1
|
|
제목: 자바 프로그래밍
|
|
저자: 홍길동
|
|
가격: 30000
|
|
|
|
책 ID: 2
|
|
제목: 데이터베이스 개론
|
|
저자: 이몽룡
|
|
가격: 25000
|
|
|
|
XML 파싱 종료
|
|
```
|
|
|
|
✅ `startElement()`에서 태그 시작을 감지
|
|
✅ `characters()`에서 태그 안의 텍스트를 처리
|
|
✅ `endElement()`에서 태그 종료를 감지
|
|
|
|
---
|
|
|
|
## **5. SAX vs DOM 비교**
|
|
|
|
| 특징 | SAX Parser | DOM Parser |
|
|
|---|-----|-----|
|
|
| **메모리 사용량** | 적음 | 많음 |
|
|
| **속도** | 빠름 (한 줄씩 읽음) | 느림 (전체 로드) |
|
|
| **트리 구조 지원** | ❌ | ✅ |
|
|
| **수정 가능 여부** | ❌ (읽기 전용) | ✅ |
|
|
| **사용 사례** | 대용량 XML 읽기 | XML을 수정할 때 |
|
|
|
|
✅ **DOM Parser는 XML을 객체처럼 다루는 데 유리**
|
|
✅ **SAX Parser는 대용량 XML을 읽기만 할 때 유리**
|
|
|
|
---
|
|
|
|
## **6. 정리**
|
|
✔ **SAX Parser는 이벤트 기반으로 XML을 한 줄씩 읽으며 처리**
|
|
✔ `startElement()`와 `characters()`를 이용해 데이터를 가져올 수 있음
|
|
✔ **대용량 XML을 처리할 때 유용하지만, 수정 기능이 없음**
|
|
✔ **DOM Parser와의 차이를 이해하고 적절한 방식 선택**
|
|
|
|
✅ **읽기 전용 & 성능이 중요한 경우 SAX Parser를 사용하자!** |