1. DOM 개념 이해하기
1-1. DOM(Document Object Model:문서 객체 모델) 이란?
1) DOM은 HTML과 XML 문서를 위한 API(Application Programming Interface )로서
문서의 물리적 구조(XML)와 문서(HTML)가 접근/다루어지는 방법을 정의한다.
한마디로 물리적구조(XML)와 서술형 문서HTML의 연관관계를 이해하고 활용하기 위한 것이다. 라는 말이다. XML이 목차라는 예시로 들어질 때 물리구조(목차)를 보고 원하는 페이지로 바로 갈 수 있지 않는가. 즉 XML을 활용해 HTML을 구성/활용할 수 있게 하는 문서 객체 모델.
2) DOM의 목적
(1) 다양한 환경과 애플리케이션에서 사용 = 표준적인 프로그래밍 인터페이스
(2) HTML이나 XML등 웹 문서의 내용과 구조, 그리고스타일 정보의 검색 또는 수정이 가능
다양한 환경과 애플리케이션에서 사용되는 xml의 목적을 그대로 반영해 xml을 적극 활용할 수 있는 프로그램 인터페이스를 제공한다로 바꿀 수 있다. 추가로 HTML을 다루는 것 포함(제한적이다)
3) DOM 문서를 이용한 XML 문서 생성 과정
(1) XML 문서를 OPEN
(2) XML 문서를 Parsing을 통한 Tree형식 구성
(3) DOM API를 이용해 XML의 Element, Text, Attribute등의 내용을 조작(추가,삭제,갱신)
(4) 조작한 XML 문서를 프로그램이 마무리하여 새로운 문서(HTML)를 생성 혹은 갱신
번역선가.. 이런 군소리는 자제.
1-2. DOM Level
1) DOM 스펙은 W3C에서 Level 단위로 만들어지고 있는데,
처음에 만든 권고안 DOM Level 1, 현재는 DOM Level 3 권고안까지 만들어진 상태이다.
2) DOM 레벨에 관한 정보
⊙ DOM Level 1 : core, HTML, 그리고 XML 문서모델에 대한 내용이다.
레벨1은 문서에 대하여 항해(navigation)하거나 조작(manipulation)하는 기능을 포함
⊙ DOM Level 2 : 스타일 쉬트를 지원하고 정보를 조작하는 기능을 정의(포함).
또한 문서에 대한 풍부한 질의 기능과 이벤트 모델에 대한 정의 기능도 포함 (???)
⊙ DOM Level 3 : 윈도우즈 환경 하에서 사용가능한 사용자 인터페이스를 기술 포함.
이를 이용하여 사용자는 문서의 DTD를 조작하는기능과 보안 레벨까지 정의할 수 있다.
(Level에 대한 상세 내용은 따로 정리할 필요가 있다. 정리한다면 Link를 달겠음)
1-3. DOM 기반 Parser
1) DOM 기반 파서는 DOM API 라는 프로그램 라이브러리를 사용한다.여러 언어로 작성되어 있으며 보통 무료로 다운 받을 수 있다. 여러 응용 프로그램-인터넷 익스플로러 6(msxml 3.0 기본 내장) 에서 파서를 이미 내장하고 있다.
2) 대표적인 DOM 기반 파서 (지원버전 : DOM Level 2 SAX 2.0)
⊙ JAXP : 썬 마이크로시스템의 파서(Java API for XML Parsing)
⊙ XML4J : IBM의 파서(XML Parser for Java)
http://www.alphaworks.ibm.com/tech/xml4j
⊙ Xerces : 아파치의 파서(Xerces Java Parser) http://xml.apache.org/
⊙ msxml : 마이크로소프트 파서 http://msdm.microsoft.com/xml
1-4. DOM 구조와 원리
DOM은 XML 문서의 노드들을 트리로 구성하고, 트리 구조로서 XML 문서를 다룸
1) DOM을 이용한 XML 문서변환
XML 문서를 응용프로그램이 파싱 요청을 하면 XML 파서에 의해 해석한 후
DOM 인터페이스를 이용, 응용프로그램과 정보를 서로 전달하여 XML문서를 조작
2) XML 문서와 DOM 트리구조
(1) XML 문서
<?xml version="1.0" encoding="euc-kr" ?>
<책>
<제목>XML 정복</제목>
<발행년도>2004년 발행</발행년도>
</책>
-> 좀 이상한게 있는데.. 원본이 이상한건지 상위 xml 데이터 문서는 데이터의 modeling차원으로 아래와 같이 값을 부여할 수 있다.
<?xml version="1.0" encoding="euc-kr" ?>
<책>
<제목 분류="컴퓨터">XML 정복</제목>
<발행년도 분류="발행">2004년 발행</발행년도>
</책>
(2) XML 객체 (명칭을 영문으로 다시 바꿔야 하지 않을까 싶다)
⊙ Documents : 작성된 전체 문서를 대표하는 객체이다.
⊙ <책> : 2개의 하위 Element 인 <제목>과 <발행년도>를 포함한 Root 이다.
⊙ <제목> : Next Element 로 <발행년도>를 갖고 "XML 정복"라는 text객체를 소유
⊙ <발행년도> : Prev. Element로 <제목>를 갖고 "2004년 발행"이라는 text객체를 소유
⊙ XML 정복 : <제목> Element의 Text Character Data가 된다.
⊙ 2004년 발행 : <발행년도> Element의 Text Character Data가 된다.
(3) DOM 노드 트리 모델링 (모델링 된 xml을 보고 생각한다)
[ Document ] - [Element "책"] - [Element "제목"] - [NamedNodeMap "분류"]
(NodeList) (NodeList) - [Att Node "컴퓨터"]
- [Text CData "XML 정복"]
- [Element "발행년도"] - [NamedNodeMap "분류"]
- [Att Node "발행"]
- [Text CData "2004년 발행"]
- 확실한 건 XML의 정의 Modeling은 상당히 난해한 개념이 들어간다. DOM은 그걸 활용하는 방식일 뿐이다. 상단 내용은 사실 대충 알아도 그만임.
--------------------------------------------------------------------------------
아래 API, API는 역시 뭐 있는지 훑어만보고, 머리 속에 남기는 우를 범해선 안된다.
2. DOM API
2-1. DOM 인터페이스
1) W3C에 의해 추천된 프로그래밍 규격으로(표준은 아니라는 말),
프로그래머가 데이터 구조의 형태인 Html 페이지나 XML 문서를 DOM 인터페이스를 사용하여
프로그램 객체로 만들거나 수정할 수 있게 해주어, 자신들의 컨텐츠나,
객체 내에 감추어진 데이터를 가질 수 있게 됨으로써, 문서를 조작할 수 있게 해준다.
(일축하면, 데이터를 조작할 수 있는 구조로 만들어 둔다는 것)
⊙ Document
⊙ Node
⊙ Nodelist
⊙ Element
⊙ NamedNodeMap
2-2. Document
Document 는 HTML 또는 XML 문서를 나타내기 위해 사용하는데
문서 트리 구조에서 최상위 루트에 해당한다.
1) Document Interface 의 특징 (Java로 치면 그냥 Class)
(1) 엘리먼트, 텍스트노드, 주석(comments), 처리 명령(processing instructions) 등을
포함하지 않고는 Document 인터페이스가 존재할 수 없다.
(2) Document 는 이 객체들을 만드는데 필요한 메소드 요소들도 포함하며
생성된 Node 객체들은 Document와 Node를 관련짓는 속성을 가진다.
(3) Document Interface Method
⊙ Element getDocumentElement()
: Document 반환 (Root)
⊙ NodeList getElementsBytagName(String tagname)
: 해당 tagname의 Element를 NodeList로 반환
⊙ Element createElement(String tagName)
: tagname에 Element를 생성한다.
⊙ Text createTextNode(String data)
: 지정된 문자열을 가진 Text 노드를 생성하는 메소드로 인자 값으로 그 노드에 대한
데이터를 가지며 리턴 되는 값은 새로운 Text 객체이다.(뭔소린지...)
⊙ Attr createAttribute(String name)
: element에 name의 이름으로 속성을 생성한다.
2) Node 인터페이스 ( Java로 치면 그냥 DO(Data Object) )
Node 는 XML 문서에서 노드 트리의 각 요소를 접근을 위해 사용
DOM에서 가장 기본적인 자료형
(1) Node 인터페이스의 특징
Node 는 Element, Comment, Attribute등을 상속
(최하위 노드인 Text 노드는 자식을 가질 수 없다.( DOMException 발생 )
▣ 노드에 관한 정보(NodeType)
구분 노드종류 노드명 노드값
Element ELEMENT_NODE 요소명 null
Attribute ATTRIBUTE_NODE 속성명 속성값
Text TEXT_NODE #text 노드의 내용
CDATA CDATA_SECTION_NODE #cdata-section 노드의 내용
Entity ENTITY_NODE 참조된 엔티티이름 null
Entity Reference ENTITY_REFERENCE_NODE 선언된 엔티티이름 null
Processing Instruction PROCESSING_INSTRUCTION_NODE PI이름 PI이름을 제외한 전체 내용
comment COMMENT_NODE #comment 주석 내용
Document DOCUMENT_NODE #document null
Document Type DOCUMENT_TYPE_NODE 루트요소명 null
Notation NOTATION_NODE Notaion선언이름 null
DOCUMENT FRAGMENT DOCUMENT_FRAGMENT #document-fragment null
(2) Node 인터페이스의 메소드
▣ Node getFirstChild() : 현재 노드의 첫 번째 노드를 나타내고 만약 그런 노드가
없으면 null값을 반환하며 리턴값은 node이다.
▣ Node getNextSibling() : 현재 노드의 바로 다음 노드를 나타낼 때 사용되는 메소
드로서 만약 해당 노드가 없으면 null값을 반환하고, 리턴값은 node이다.
▣ short getNodeType() : 노드의 종류를 나타내는 메소드로 반환되는 값은 정수형
값을 가진다.
< 노드의 종류와 상수 값 >
멤버필드 이름 정수값 노드 종류
Node.ELEMENT_NODE
1
Element
Node.ATTRIBUTE_NODE
2
Attr
Node.TEXT_NODE
3
Text
Node.CDATA_SECTION_NODE
4
CDATASection
Node.ENTITY_REFERENCE_NODE
5
EntityReference
Node.ENTITY_NODE
6
Entity
Node.PROCESSING_INSTRUCTION_NODE
7
ProcessingInstruction
Node.COMMENT_NODE
8
Comment
Node.DOCUMENT_NODE
9
Document
Node.DOCUMENT_TYPE_NODE
10
DocumentType
Node.DOCUMENT_FRAGMENT_NODE
11
DocumentFragment
Node.NOTATION_NODE
12
Notation
▣ string getNodeName() : 해당 노드의 이름을 문자열 형으로 반환한다.
▣ string getNodeValue() : 해당 노드의 값을 반환한다.
▣ Document getOwnerDocument() : 현재 노드의 Document 객체를 반환
현재 노드가 Document이면 null값을 반환한다.
▣ Node appendChild(Node newChild)
: 새로운 노드를 추가
newChild 노드를 현재 노드의 자식 리스트의 끝에 삽입한다.
newChild가 DocumentFragment객체이면
DocumentFragment의 전체 내용이 삽입된다.
▣ Node getParentNode()
: 현재 노드의 부모 노드를 반환 (트리 구조에 포함된 Node 대상)
All nodes, except Document, DocumentFragment그리고 Attribute는
Node가 아니므로 부모 노드가 없다.
▣ Node insertBefore(Node newChild, Node refChild)
: refChild Node 이전에 newChild Node를 삽입,위치 시킨다.
refChild가 null이면 끝에 삽입되며,
newChild가 DocumentFragment이면
refChild 앞에 같은 순서로 모든 자식들이 삽입된다.
만약 newChild가 이미 트리안에 있으면 먼저 제거된 후에 삽입된다.
▣ Node replaceChild(Node newChild, Node refChild)
: 노드 refChild를 newChild로 대체한다.
만약 newChild가 이미 트리안에 있으면 먼저 제거된 후에 삽입된다.
▣ Node removeChild(Node oldChild)
: 자식 노드리스트에서 oldChild 노드를 제거한다.
현재 노드가 읽기 전용일 때에는 NO_MODIFICATION_ALLOWED_ERR 에러 발생
▣ NamedNodeMap getAttributes() : 노드의 속성리스트를 얻는다.
3) NodeList 인터페이스 ( Java로 치면 그냥 Linked DO(Data Object) )
NodeList 는 노드들의 집합이 구현되는 방법을 정의하거나 순서가 있는 노드들의 집합
(1) NodeList 인터페이스의 특징
NodeList에서의 아이템은 0부터 시작되는 정수 인덱스에 의하여 접근할 수 있으며
NodeList를 통해 얻은 노드들의 순서는 XML에서 부모노드로부터 추가한 순서가 된다.
(2) NodeList 인터페이스의 메소드
▣ int getLength() : NodeList 개수(개수 : n, index : 0 ~ (n-1))
▣ Node item(int index)
: NodeList에서 index가 가리키는 노드를 반환
범위 밖에 index의 Node 반환을 요구시 null값을 반환
4) Element 인터페이스
Element 인터페이스는 HTML 문서 또는 XML 문서의 원소(?)를 표현하기 위해 사용된다.
(1) Element 인터페이스의 특징
Attribute 객체 또는 속성값 등을 검색, HTML에서 속성값에 직접 접근
(2) Element 인터페이스의 메소드
▣ string getAttribute(String name)
: 이름이 name인 Attribute의 문자열 값 또는 default 값을 반환
만약, 기본 값이 없을 경우 빈 문자열이 된다.
▣ void setAttribute(String name, String value)
: 이름이 name인 Attr의 값을 value로 set.
name이 없으면 추가하고 있으면 값을 변경.
▣ void removeAttribute(String name)
: 이름이 name인 Attr을 제거한다.
현재 노드가 읽기 전용일 때 NO_MODIFICATION_ALLOWD_ERR 에러를 발생
5) NameNodeMap 인터페이스 (메모리 맵으로 검색기능으로 활용한다 보면 된다)
NameNodeMap 인터페이스는 NodeList의 기능과 유사한데 이름을 이용하여
노드에 접근하고 NameNodeMap을 구현하는 객체에 포함된 속성들을 추출할 때 사용한다.
(1) NameNodeMap 인터페이스의 특징
접근하려는 노드들은 이름과 0부터 시작하는 정수 인덱스 값을 이용해 추출할 수 있다.
(2) NameNodeMap 인터페이스의 메소드
▣ Node getNamedItem(String name)
: 이름이 name인 노드를 반환. 없을 경우 null을 반환
▣ Node removeNamedItem(String name)
: 이름이 name인 노드를 제거. 없을 경우 null값을 반환
특이사항 : 맵 전체에 지정한 이름의 노드가 없으면 NOT_FOUND_ERR 에러를 발생
▣ Node item(int index) : 정수를 인자로 가지며 index에 해당하는 Attr 노드 객체를 리턴하고, index에 해당하는 특성이 존재하지 않으면 null값을 리턴한다.(이거 좀 이상하다)
--------------------------------------------------------------------------------
예제는 나중에 따로 post로 정리하도록 하자. 왜? 복사해서 그냥 쓸 정도로 되야 되니까.
===== 예제코드 =====
* ch13-01.xml
<?xml version="1.0" encoding="euc-kr" ?>
<product>
<phone></phone>
</product>
* ch13-01.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>DOM페이지</TITLE>
<script language="javascript">
var objDom; //xml document객체를 담을 변수
objDom = new ActiveXObject("MSXML.DOMDocument");
objDom.load("ch13-01.xml");
//xml문서전체를 출력하는 함수
function displayXML() {
alert(objDom.xml);
}
//요소를 추가하는 함수
function appendElement(){
var objText; //텍스트 노드를 저장할 변수
var objNode; //요소 노드를 저장할 변수
//1.새로운 텍스트 노드를 생성
objText = objDom.createTextNode("SCH-X147");
//2. 새로운 요소 노드를 생성
objNode = objDom.createElement("Model");
//3.새로만든 요소노드에 새로 만든 텍스트 노드를 추가
objNode.appendChild(objText);
//추가하고자 하는 위치의 요소노드를 얻어옴
var HPobjNode;
HPobjNode = objDom.documentElement.firstChild; //product/phone
//4.새로만든 요소를 추가
HPobjNode.appendChild(objNode);
alert(objDom.xml);
}
</script>
</HEAD>
<BODY>
<p>DOM예제</p><hr>
<input style="width:300px" type="button" value="XML문서보기" onclick="displayXML();"><br>
<input style="width:300px" type="button" value="새로운 요소추가하기" onclick="appendElement();">
</BODY>
</HTML>
===== 예제코드2 =====
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>DocumentFragment인터페이스</TITLE>
<script language="javascript">
var objDom; //xml document객체를 담을 변수
objDom = new ActiveXObject("MSXML.DOMDocument");
objDom.load("ch13-01.xml");
//XML문서전체를 출력하는 함수
function displayXML(){
alert(objDom.xml);
}
//DocumentFragment객체를 생성하는 함수
function createDocumentFrag(){
var docFrag; //DocumentFragment객체를 담을 변수
var objNode; //노드를 담을 변수
var objText; //텍스트 노드를 담을 변수
// 1.DocumentFlagment생성
docFrag = objDom.createDocumentFragment();
// 2.요소노드생성
objNode = objDom.createElement("model");
// 3.텍스트노드생성
objText = objDom.createTextNode("SCH-X147");
// 4.DocumentFragment 객체에 새로 생성한 요소 노드를 추가함.
docFrag.appendChild(objNode);
// 5.DocumentFragment의 새로 추가된 요소에 텍스트 노드를 추가함.
docFrag.firstChild.appendChild(objText);
//6. Document객체의 루트요소에 생성한 DocumentFragment를 추가함.
objDom.documentElement.firstChild.appendChild(docFrag);
alert(objDom.xml);
}
</script>
</HEAD>
<BODY>
<p>DocumentFragment를 이용하여 노드를 추가</p><hr>
<input style="width:150px" type="button" value="XML문서보기" onclick="displayXML();">
<input style="width:150px" type="button" value="노드추가하기" onclick="createDocumentFrag();">
</BODY>
</HTML>
Java+XML Programming 의 Parser DOM과 SAX
목차
1. Introduction
2. 파서란 무엇인가.
3. Object Model이란 무엇인가.
4. DOM과 SAX는 왜 만들어졌는가.
5. DOM은 무엇인가..
6. SAX는 무엇인가.
7. 언제 DOM을 쓸 것인가.
8. 언제 SAX를 쓸 것인가.
9. DOM과 SAX은 어떻게 사용하나.
10. 맺음말
지난 달 연재에서 독자들은 XML/Java technology가 각각 어떠한 장점을 가지고 있고 둘이 같이 사용될 때의 시너지 효과 등을 살펴보았다. XML/Java technology는 이미 3-tier 웹 애플리케이션에서 자리를 잡아가고 있다. 결국, 각 tier간의 데이터는 XML format으로 될 것이며, 이 XML format 데이터를 다루는 로직을 구현하는 데는 Java technology가 사용 될 전망이다. 따라서, 웹 애플리케이션은 XML format으로 구성된 데이터를 파싱(Parsing)을 하는 작업을 수반하게 된다. 여기에 사용되는 것이 XML Parser인데, 대표적인 Parser로는 IBM의 XML4J, Oracle의 XDK(XML Developer's Kit), Sun의 JAXP가 있다. 이 Parser를 구현하는데 DOM(Document Object Model)과 SAX(Simple API for XML)가 사용된다. 이번 연재에서는 이 두 파서(parser)의 장점과 단점을 비교를 중심으로, 각 Parser의 특성이 어디에 어떠한 식으로 사용되는지에 대해 자세히 다룰 것이다.
박동문 (아주대학교 정보및컴퓨터 공학부 Database연구실)
Email : Minerva@doit.ajou.ac.kr
1. Introduction
자바 프로그래머로써, XML 문서를 다룰 기회가 있었다면 아마 문서 안에 담겨진 정보를 얻어내기 위해 코딩하는 것이 쉽지 않음을 경험했을 것이다. 왜냐하면 XML 문서는 단순히 텍스트 파일이고 개발자는 애플리케이션에서 사용되는 XML 문서의 정보를 해석하고 필요로하는 정보를 축출하기위해 별도의 텍스트 파일 리더(text file reader)를 작성해야 하기 때문이다. 개발하는 애플리케이션의 용도에 맞게 계속 XML 리더를 고쳐야 하는 작업은 아마도 개발자에게는 시간도 많이 걸리고 꽤 번거로운 일일 것이다. W3C는 이러한 개발자의 노력과 시간을 줄이고자“XML document reader”혹은 XML 파서(parser)와 같은 표준을 제안하게 된 것이다. 다행인 것은 SUN, Datachannel, IBM 등의 많은 회사들이 무료로 XML 파서를 제공하고 있다는 것이다. 물론 이 파서들은 자바로 만들어 졌다.
2. 파서(Parser)란..?
파서(Parser)는 Java+XML 프로그래밍이라는 전체적인 구도에서 보면 작은 부분에 지나지 않지만 매우 중요한 역할을 한다. XML문서를 다루는 (웹)애플리케이션의 개발자라면, XML 문서(일반적으로 관계형 데이터베이스-Relational Database System, Object Database System에 저장되어 있는 것)안에 있는 정보에 접근을 해야하는데 Java XML parser가 이 역할을 해준다. 파서의 대표적인 종류로 두 가지가 있는데, 그것이 바로 SAX(Simple API for XML)와 DOM(Document Object Model)이다. SAX와 DOM 모두 XML 문서의 정보에 접근할 수 있게 애플리케이션을 개발하도록 API를 제공한다.
SAX와 DOM 각각의 API는 제법 다른 특성을 가지고 있다. SAX는 소프트웨어나 컴퓨터 자체에 의해서 생성된 데이터 같은 정보를 읽어 들이는 프로그램에 적당하고, 반면 DOM은 문서에 저장된 정보를 읽어 들이는 경우에 적합하다. 그렇기 때문에 개발 환경에서 XML 문서가 컴퓨터가 만들어낸 데이터(computer generated data)를 포함하고 있다면 SAX를 사용해서 읽는 것이 쉽고, XML이 문서를 포함하고 있을 경우에는 DOM을 사용해서 읽는 것 이 쉽다.
이렇듯 파서는 XML 문서와 개발자의 Java program 중간에서 문서의 데이터에 접근 가능하게 한다. 이 데이터를 파서로 읽어들이면, 그것은 정보에 보다 쉽게 접근하고 수정할 수 있도록 “object model”의 형태로 저장되어야 한다. 뒤에 자세히 다루겠지만 이 “object model”은 XML 문서에 나타난 데이터 메모리 안에서 표현하는 것이다. 만약 object model을 수정해서 XML 문서 정보의 변경이 있었다면 XML 문서의 소스(persistent layer : 일반적으로 데이터베이스)에 다시 저장하는 과정이 필요하다. 그렇기 때문에 번거롭지만 개발자는 object model을 XML로 바꾸어 주는 코드를 별도로 작성을 해야 한다. 변경된 사항을 데이터베이스에 저장할 때는 객체로 저장하기보다는 XML문서 순수의 포멧으로 저장하는 것이 좋다. 왜냐하면 XML 순수의 포맷으로 저장함으로 해서 시스템 디자인과 구현의 선택에 구애 받지않는 유연성(flexibility)을 얻을 수 있기 때문이다(XML 데이터를 Java를 이용해 읽고 쓰고 함으로서 가능해진다.).
3. Object Model이란..?
웹 애플리케이션을 할 때 정보를 저장할 데이터베이스 시스템을 정하고, 이 데이터베이스에 접근해서 XML 문서를 다룰 Interface(자바로 구현한)를 생성했으면 이제 source(Database)에서 가져온 XML 문서에 있는 정보를 표현할 object model을 생성해야 한다. 문서 정보의 복잡도에 따라 걸리는 시간은 좌우되고 source에서 가져온 문서의 정보는 DOM이나 SAX 파서에 의해서 object model의 모습으로 변환된다.
일반적으로 “Object Model”라 함은 XML 문서의 정보를 표현하기 위해 정의된 클래스(혹은 인터페이스)의 집합을 말한다. SAX를 사용한다면 개발자는 그들의 구미에 맞는 custom object model을 생성하기위해 DocumentHandler implementation 클래스를 만들어야 한다. DOM을 이용하면 default object model(Document Object Model)이 제공이 되지만, 개발자에게 필요한 custom object model을 만들려면 별도의 코딩이 필요하다.
object model이 생성되었으면 XML 문서 정보의 표현은 된 것이고 이제 남은 것은 XML 문서 정보와 사용자간에 상호작용을 할 수 있도록 하는 또 다른 클래스(사용자 인터페이스 : UI)를 만드는 것이다. 개발자는 서블릿 중심(HTML이나 웹 based)이나 스윙(Swing based) 중심으로 사용자 인터페이스 레이어를 만들 수 있다. 또한 수정된 정보를 source 데이터베이스에 저장할 때는 object model을 다시 XML 포멧으로 변환 해서 저장하면 된다.
4. DOM과 SAX는 왜 만들어 졌는가..
W3C(World Wide Web Consortium)는 개발자들이 XML을 다루기 쉽도록 프로그래밍 언어에 독립적인 인터페이스의 집합을 정의함으로써 XML 문서에 접근하고 수정하는 것을 지원하고 있다. 이번 연재 Introduction 부분에서 이미 언급했듯이 XML의 인코딩과 저장 포맷의 표준의 필요성 뿐만 아니라 개발자들이 XML 문서의 정보를 다룰 수 있도록 어떠한 표준이 필요했던 점에 부응한 것이다. SAX는 이전에 가능하던 XML 파서보다는 훨씬 향상된 것이고 상당히 낮는 수준의 API이다. 한편, DOM은 모든 XML 문서의 default object model을 제공하는 높은 수준의 API이다. SAX와 DOM은 모두 개발자가 그들의 프로그램에 XML 문서를 처리하는 파서(parser)를 별도로 만들지 않아도 되도록 하기위해서 고안이 됐다. 다시 말해, 정보를 XML 문서로 저장하고 SAX나 DOM API를 이용함으로써 프로그램에 무료로 Parser를 쓸 수 있게 되는 것이다. 현재 SAX와 DOM은 여러 가지의 언어를 지원하고 있고 지원하는 언어로는 Java, C++, Perl, Python 등이 있다. 이로써 SAX와 DOM은 상호 운용성(interoperatability), 플랫폼, 기기에 독립적인 컴퓨팅이라는 목표를 지향한다.
5. DOM(Document Object Model)이란 무엇인가..
XML의 장점은 지난 5월호에서 이미 살펴보았다. 그 장점들 중 가장 두드러지는 것이 XML 문서 안에 나타나는 정보 구조를 표현할 수 있다는 점이다. 구조화된 XML 문서의 형태를 보면 그것의 엘리먼트가 또 다른 엘리먼트를 포함하고 있는 것을 많이 볼 수 있다.(그림 1 참고) 그림1 의 XML 문서를 파일이라고 생각하는 대신 각 태그를 트리(tree)의 노드(node)라고 생각하고 XML 문서의 구조를 구성해 보면 그림 1의 Document Object Model과 같은 모습이 된다.
(그림 1)
XML document
<?xml version=”1.0”>
<weather>
<city name=”서울”>
<temperature>
<low>
<Fahrenheit>32</ Fahrenheit>
<centigrade>0</centigrade>
</low>
<high>
<Fahrenheit>100</ Fahrenheit>
<centigrade>212</centigrade>
</high>
</temperature>
<rain>30%</rain>
<wind speed measure=m/sec>5</wind speed>
</city>
<city name=”수원”>
….
</city>
</weather>
Documents Object Model (tree 형태의 계층적인 구조)
*document
- node 날씨
- node 수원
- - node 온도
- - node 최고기온
- - node 최저기온
- - node 비올 확률
- - node 풍속
- node 서울
- node 온도
- node 최고기온
- node 최저기온
- node 비올 확률
- node 풍속
그림에서 보듯이“날씨”가 XML 문서 태그들의 트리로 보여짐을 알 수 있다. XML문서가 하나의 트리로 보이면 검색을 비롯한 문서에 접근하는게 매우 쉬울것이다. 이러한 방법으로 XML 문서를 다루기위해 나온 것이 바로 DOM이다. Document Object Model(DOM) Level 1 Recommendation은 W3C Committee에서 잘 구성된 XML이나 HTML 문서를 지원하기위한 언어에 중립적인 인터페이스(language neutral Interface)로 고안되었다.
DOM(Document Object Model) XML parser는 애플리케이션이나 servlet 안에서 XML 문서를 어떠한 자바 객체의 집합으로 변형시켜 메모리에 저장하는 자바 프로그램이다. 이 말은 XML 문서를 파일 스트림이 아닌 객체로 다룸을 뜻한다. 한편 DOM 프로토콜(메커니즘)은 “random access”프로토콜이라고도 알려져 있다. 왜냐하면 DOM을 사용하면 XML 데이터의 어떠한 부분에라도 임의로 접근해서 수정, 제거, 새로운 데이터의 삽입할 수 있는 기능성이 제공되기 때문이다. DOM은 트리 형태의 구조를 가지고 있고 이 트리의 각 노드는 XML 구조의 특정한 컴포넌트를 포함한다. 트리를 구성하는 가장 일반적인 노드의 타입으로는 엘리먼트(element : XML 데이터의 한 단위로 태그로 구분이 된다. 각 엘리먼트는 중첩될 수도 있다.) 노드와 텍스트(text : 각 태그 사이에 들어가는 text) 노드 두 가지가 있다. DOM이 XML 문서의 구조와 정보를 기반으로 노드를 구성하고 계층적인 object model의 형태로 접근이 가능하다.(그림1 참고) 즉, XML 문서를 수정할 때 직접 XML을 다룰 필요가 없고 메모리에 저장되어 있는 object model을 다루면 되는 것이다. 결국 object model을 표현한 노드와의 상호작용이 곧 XML 문서와의 상호작용이 된다. 그렇기 때문에 DOM에서 지원하는 메소드(APIs)를 사용하면 각 노드의 참조, 생성, 삭제, 수정과 그 내용의 변경을 쉽게 할 수 있다. 일단 XML 문서의 정보가 트리 형태로 표현되므로 트리를 가시화 하기위해 GUI를 첨가하게 되면 사용자의 입장에서는 문서의 구조와 정보를 한 눈에 파악할 수 있고 그것의 수정 또한 쉽게 할 수 있다.
DOM은 XML 문서의 정보에 상관없이 Document object를 만들 때 XML 문서(통계적인 데이터나 품목의 리스트, 혹은 단순히 텍스트와 같은 어떠한 정보든지 상관이 없음)에 따라서 노드의 트리 형태로 만든다. 즉, DOM을 사용하면 XML 문서의 정보에 접근하기 위해서 트리 모델을 사용할 수 밖에 없다. 그런데 원래 XML 자체가 계층적인 구조를 가지고 있기 때문에 이러한 방식은 매우 자연스럽게 돌아간다. 이런 이유로 DOM은 통계적인 데이터이든 품목의 리스트 든지 상관없이 모든 정보를 트리에 집어 넣는 것이다. 이러한 계층적인 구성은 파일 시스템과 유사하다. 파일 시스템의 계층 구조를 보면 폴더는 그 안에 파일을 포함할 수 있고 또 다른 폴더를 포함하기도 한다. (그림 1)을 보면 각 엘리먼트의 노드는 또 다른 노드 즉, 자식노드(child node)를 가지는 것을 볼 수 있다. 이 자식 노드는 텍스트 값이나 또 다른 노드를 가진다. 그렇기 때문에 만일 특정한 값(예를 들면 “<풍속 단위=’m/sec’>5</풍속>”)에 대한 접근이 필요할 때는 엘리먼트 노드에 대한 검색은 불필요하다. 위에서 언급했듯이 엘리먼트는 텍스트 데이타와 다른 엘리먼트를 가질 수 있기 때문에, DOM을 사용할 때는 엘리먼트 노드의 값을 가져오기 위해서는 별도의 작업이 수반된다. 대게, XML 문서가 순수한 데이터를 가지고 있으면 그것을 블록화해서 하나의 문자열(String)로 표현하는 것이 적당하고, DOM은 각 엘리먼트가 가진 값으로 그 문자열을 리턴한다. 만약에 XML 문서에 저장되는 데이터가 문서일 경우 잘 동작하지 않을것이다. 순수한 데이터, 이를테면 데이터베이스의 테이블과 같은 데이터에서 엘리먼트의 시퀀스는 그렇게 중요하지 않다. DOM은 XML 문서의 모든 데이터를 document로 간주하기 때문에, XML 문서를 읽어서 엘리먼트의 시퀀스를 보관해둔다. Document Object Model(DOM)이라고 불리는 이유도 여기에서 근거한다.
DOM은 단지 W3C에서 정의한 자바 인터페이스에 지나지 않는다. 그리고 이 인터페이스의 구현은 제공되지 않기 때문에 XML 파서를 쓰기 위해서는 구현은 개발자 스스로 해야 한다. 왜냐하면 XML 파서는 플랫폼과 언어에 중립적이기 때문이다. 이러한 W3C의 정책은 보다 낳은 XML 파서의 구현이 나올 수 있도록 유도하는 것이고 이렇게 되면 XML 문서와 자바프로그램은 어떠한 파서에도 구애 받지 않는 것이다.
개발자가 DOM을 이용해서 XML 문서에 저장된 정보를 Java object model로 저장하려고 한다면야 SAX는 전혀 고려를 할 필요가 없겠지만 DOM으로 처리하지 못할 경우에는 SAX 쪽에 눈을 돌려 볼 수 있겠다. 만약 특정 용도에 쓰여질 “Custom object model”을 생성할 필요가 있는 개발이라면 DOM을 사용해도 무관하지만 SAX를 사용하는 것이 훨씬 유용하다. 이렇게 되면 독자들에게는 언제 DOM을 쓰고 언제 SAX를 쓰지 말아야 할지 의문이 생길 것이다. 다음 단락에서 SAX를 다룬 후에 DOM과 SAX가 언제 쓰이는지 자세히 다루겠다.
6. SAX(Simple API for XML)란 무엇인가..
SAX는 사실상 W3C에서 만들어졌다기 보다는 XML-DEV 메일링 리스트의 공동 프로젝트를 통해서 만들어진 상품이다. SAX는 노드의 트리형태가 아닌 이벤트의 시퀀스로 XML 문서의 정보에 접근한다. 그래서 “serial-access 혹은 event-driven 프로토콜(메카니즘) ”이라 불기도 한다, 왜냐하면 이 기술은 핸들러를 SAX parser와 함께 등록한 후에 파서가 XML문서를 파싱하다가 XML tag를 만나면 그 태그에 대응하는 함수를 호출 하는 구조를 가졌기 때문이다. 더불어, DOM 처럼 object model의 tree를 만드는 과정이 필요없다. 이런 특징 때문에 XML 문서를 읽거나 쓰는 속도가 빠른 편이다. 그렇기 때문에 SAX를 사용하는 servlet이나 네트워크-오리엔네트오리엔티드 프로그램에서는 XML 문서의 처리를 위한 XML 데이터의 전송과 수신에 있어서 DOM을 사용하는것 보다 낳은 성능을 기대할 수 있다. SAX는 현재 XML 문서를 다루는 메카니즘 중에 제일 빠르고 가장 적게 메모리를 사용하기 때문이다.
SAX는 다음과 같은 일들이 필요하다.
- 특정한 object model을 생성할 때
- 특정 SAX 이벤트를 생성해서 object model을 생성할 때
DOM에서는 이러한 과정이 필요치 않다. 왜냐하면 DOM 은 이미 object model 를 노드의 트리형태로 정보를 표현하기 때문이다. DOM의 경우, 파서가 거의 모든 일을 다 한다. XML 문서를 읽어들이고, Java object model 을 생성해서 이 object model(Document object)을 참조할 수 있도록 해서 이것의 조작을 도와준다. SAX가 괜히 Simple API for XML (역주 “XML을 위한 쉬운 API”)라고 칭해진게 아니다. SAX는 파서에게 많은 것을 기대하지 않는다. 단지 SAX 파서는XML 문서를 읽어들여서 어떤 태그를 만나면 그에 따라 이벤트를 생성한다. 개발자의 입장에서는 XML document handler class를 만들어 SAX 파서가 생성한 이벤트를 잡아내서 그것에 따른 처리를 해주기만 하면 되는 것이다. 즉 모든 태크마다 이벤트를 생성하고 그에 따라 object model 안에 새로운 object가 만들어지는 것이다.
위에서도 언급했듯이, SAX는 object model이 단순하다면 런타임(run time)에는 매우 빠르다.그러한 반면, XML 데이터를 읽으면서 각각의 태그마다 파서가 이벤트를 생성해야 하기 때문에 DOM에 비해 보다 많은 프로그래밍 작업이 필요하다.
SAX 파서에 의해서 발생되는 SAX 이벤트의 종류를 보면 정말 단순하다. SAX는 모든 open tag, close tag, #PCDATA 부분, CDATA 부분에 대해서 이벤트를 발생시킨다. 그러면 document handler 는 발생된 이벤트를 잡아서 해석하고 특정용도의 custom object model을 생성한다. 여기서 이벤트의 해석과 각 이벤트의 발생 순서는 매우 중요하다.
7. 언제 DOM을 써야하나..
XML 문서가 문서 데이터를 포함하는 경우, (이를테면 XML 포맷으로 저장된 Framemaker document) DOM 이 제일 적당한 솔루션이라고 할 수 있다. DOM을 설명할 때에 언급했지만, DOM은 XML 문서안의 정보를 노드의 트리 형태로 표현하기 때문에 문서의 구조를 한 눈에 알 수 있어 쉽게 작업할 수 있다. DOM은 만약 문서 정보 관리 시스템(Document Information Management System)을 개발 중이라면, 그 상품은 아마도 수많은 문서 데이터를 다루어야 한다. 한 예로 “DataChannel”이라는 회사의 “DataChannel RIO”라는 상품이 있는데, 그것은 문서 소스(워드나 엑섹 문서)의 정보의 인덱싱과 구성할 수 있다. 이러한 제품을 개발할 때라면 DOM을 사용해서 XML 문서의 정보를 처리하는게 적당하다. 또한 XML문서가 데이터베이스에 저장되어 있는 경우에도, DOM을 이용해 프로그래밍하면 유용하다. 데이터베이스의 스키마(schema : 데이터베이스의 구조)를 DOM object로 표현하기위해 우선 XML로 스키마를 명시하고, XSL을 사용해 XML을 HTML 포맷으로 변환시키면 모든 것이 해결된다. 이렇게 되면데이터베이스의 스키마는 가시적이게되고 갱신도 가능하게된다. 데이터베이스에 있는 정보를 갱신하고 싶을 때는데이터베이스의 (DOM)스키마 트리를 검색해서 변경하고 싶은 스키마와 일치하는 컬럼의 이름을 찾아 그것으로 쿼리를 하면 된다.
종합하면, DOM 파서를 쓰는 것이 좋은 경우는
- XML 문서의 구조적인 접근이 필요할 때
- XML 문서의 특정 부분을 옮겨 다닐 필요가 있을 때
- XML 문서의 정보를 한 눈에 알고 싶을 때
8. 언제 SAX를 써야할까..
한편 어떤 경우에 SAX를 사용하는게 좋을까? XML 문서가 기계만 읽을 수 있는(machine readable, generated data)데이터일 때에는 SAX API를 사용해서 XML 문서 정보에 접근하는게 좋다. 다음과 같은 것들이 기계가 생산한 데이터다.
- 자바 객체의 특성이 XML 포멧으로 저장되어있는 것
- SQL, XQL, OQL과 같이 택스트 기반의 쿼리 언어가 만들어낸 질의
- 질의해서 생성된 관계형 데이터베이스 테이블의 reault set
이러한 기계가 만들어낸 데이터는 대게 개발자만의 구조체나 클래스(object model)를 만들어야하는 정보다. 만약 전화번호부가 XML 문서로 되어있다면 이 파일은 워드프로세서 문서라기보다는 순수한 데이터를 포함하는 문서(XML로 인코딩된 텍스트)일 것이다. 이런 데이터라면, 사용자만의 구조체나 object model을 생성해야 한다. SAX는 XML 문서에 저장된 데이터를 기반으로한 custom object model을 만들 수 있는 핸들러 클래스를 생성한다. SAX Document handler는 전화번호 정보가 포함된 XML 문서를 읽어서 문서 정보에 접근할 수 있는 전화번호부 클래스(이게 바로 custom object model이다 그림 2 참고)를 만든다. 전화번호부 클래스는 person 클래스를 포함하고, person 클래스는 이름과 전화번호라는 스트링형태의 객체를 포함할 것이다. 이와 같이 특정 용도에 사용될 object model의 생성이 필요한 경우에는 SAX를 사용하는 것이 좋다.
(그림 2) 전화번호부의 customized object model
*전화번호부 클래스
-- person 클래스 -+- 이름 (string 객체)
+- 전화번호 (string 객체)
SAX model을 사용하는 것이 유용한 경우.
- XML 문서 전체가 아닌 어느 한 부분만 읽을 경우(SAX는 memory를 적게 차지하기 때문이다.)
- 한 개 혹은 몇 개의 엘리먼트만 축출할 때
- 같은 에러의 처리
- 유효성 처리
- 이미 존재하는 데이터의 변환
9. DOM과 SAX를 어떻게 사용하나..
Java와 XML technology를 사용한 애플리케이션을 개발하고 있다면, 그 애플리케이션의 구조는 대게 다음과 비슷한 형태를 가질 것이다. (그림 3)
(그림 3) XML + java web application model
layer 1 - XML 문서 – source (DB : xml source layer)
XML 문서의 저장장소
relational dbms or object dbms
| xml
|
layer 2 - Internet (Communication layer : RMI, servlet, CORBA/IIOP)
| xml 포멧의 문서 이동
|
layer 3 – XML Parser layer (translate)
XML 파서 written in java (SAX&DOM) 를 이용해서
xml이 document object로 변환된다.
|
|
layer 4 – Java Application layer (java classs)
document object를 swing이나 awt를 이용해서 보여지고
그리고 document object의 수정-> xml문서 정보의 수정
DOM과 SAX는 폭넓고 유용한 기능성을 제공하지만 이 DOM과 SAX Parser를 이용하려면 기본적으로 parser의 구현에 대해 어느 정도의 지식이 필요하다. Java 플랫폼에서의 DOM과 SAX의 기능성은 파서의 구현에 있어서 선택의 여지를 준다. 이제 DOM과 SAX의 plugability 메커니즘을 “Java.xml.parsers”를 이용해서 살펴보도록 하겠다.
9.1 SAX Plugability
SAX Plugability 클래스는 SAXParser 구현과 XML 문서의 파싱을 위한 org.xml.sax.HandlerBase API를 지원함으로써 애플리케이션의 구현이 수월하도록 프로그래머에게 여러 가지 메소드를 제공한다. 파서가 XML 문서를 파싱하는 동안, 파서는 HandlerBase의 도움을 받아서 메소드를 호출한다.
SAXParser 객체를 초기화 하려면 개발자는 먼저 SAXParserFactory 인스턴스를 초기화 해야한다. SAXParserFactory 인스턴스는 SAXParserFactory 클래스에 있는 newInstance 메소드를 호출 함으로서 초기화된다. 이 메소드는 SAXParserFactory 구현 클래스를 로드하고 초기화하기 위해 javax.xml.parsers.SAXParserFactory 시스템 속성을 참고한다. 만약 javax.xml.parser.SAXParserFactory 시스템 속성이 정의되어 있지 않을 때에는 플랫폼 디폴트의 SAXParserFactory 인스턴스가 리턴된다. 만약 런타임에서 SAXParserFactory 구현 클래스가 설명된 javax.xml.parsers.SAXParserFactory 속성이 로드 되지 않거나 초기화가 안되면 FactoryConfigurationError가 발생된다.
SAXParserFactory 인스턴스는 임의로 애플리케이션 프로그래머가 factory의 setNamespaceAware와 setValidateing 메소드를 이용해서 네임스페이스(namespace)나 유효성을 정해주는 것으로 설정한다. 애플리케이션 프로그래머가 세팅하는 데로 파서가 설정되지 않을 때는 ParserConfigurationException이 발생된다.
(Example)
다음은 특정 URL로부터 XML 컨텐트를 어떻게 파싱하는지 보여주는 예제이다.
SAXParser Parser;
HandlerBase handler = new MyApplicationHandlerBase();
SAXParserFactory factory = SAXParserFactory.netInstance();
Try{
Parser = factory.netSAXParser();
Parser.parse ( “http://myserver/mycontent.xml”, handler );
}catch (SAXException se){
//에러 핸들링
}catch (IOException ioe){
//에러 핸들링
}catch (ParserConfigurationException pce){
//에러 핸들링
}
다음 코드는 SAX 파서의 네임스페이스(namespace aware) 유효성(validating)을 설정해주는 예제이다.
SAXParser Parser;
HandlerBase handler = new MyApplicationHandlerBase();
SAXParserFactory factory = SAXParserFactory.newInstance();
Factory.setNamespaceAware(ture);
Factory.setValidating(true);
Try{
Parser = factory.newSAXParser();
Parser.parser( “http://myserver/mycontent.xml”, handler);
}catch (SAXException se){
//에러 핸들링
}catch (IOException ioe){
//에러 핸들링
}catch (ParserConfigurationException pce){
//에러 핸들링
}
9.2 DOM Plugability
DOM Plugability 클래스는 개발자가 XML 문서를 파싱하고 DocumentBuilder를 구현함으로써 org.w3c.dom.Document 객체를 생성할 수 있도록 한다. DocumentBuilder 인스턴스를 생성하기 위해서 애플리케이션 프로그래머는 먼저 DocumentBuilderFactory 인스턴스를 포함하고 있어야 한다. 이 DocumentBuilderFactory 인스턴스는 DocumentBuilderFactory 클래스에 있는 newInstance 메소드를 이용해서 초기화 된다. 이 메소드는 DocumentBuilderFactory 구현 클래스를 로드하고 초기화하기위해 “java.xml.parsers.DocumentBuilderFactory” 시스템 속성을 참조한다. 만약 javax.xml.parsers.DocumentBuilderFactory 시스템 속성이 정의되어있지 않을때엔 플랫폼 디폴트의 DocumentBuilderFactory 인스턴스가 리턴된다.
만약 런타임에서 DocumentBuilderFactory 구현 클래스를 정의한 javax.xml.parsers.DocumentFactory 속성이 로드되지 않거나 초기화되지 않을 경우 FactoryConfigurationError가 발생된다. 이 에러 메시지에는 발생한 문제점에 대한 설명과 대처방안이 설명되어있다.
DocumentBuilderFactory 인스턴스는 임의로 애플리케이션 프로그래머가 factory의 setNamespaceAware와 setValidating 메소드를 이용해서 네임스페이스와 유효성을 설정한다. 이때 DocumentBuilder 구현 인스턴스는 factory로부터 얻는다. 만약 factory를 애플리케이션 프로그래머가 설정할 수 없을 때는 ParserConfigurationException이 발생된다.
다음 예제는 SAX의 예제와 같이 어떻게 특정 URL의 XML 문서를 파싱하는지 보여준다.
DocumentBuilder Builder;
DocumentBuilderFactory factory;
DocumentBuilderFactory.netInstance();
String location = “http://myserver/mycontent.xml”;
Try{
Builder = factory.newDocumentBuilder();
Document document = builder.parse(location);
}catch(SAXException se){
//에러 핸들링
}catch(IOException ioe){
//에러 핸들링
}catch(ParserConfigurationException pce){
//에러 핸들링
}
다음 어떻게 factory를 설정해 주는지 나타난 예제이다.
DocumentBuilder Builder;
DocuementBuilderFactory factory = DocumentBuilderFactory.newInstance();
String location = “http://myserver/mycontent.xml”;
Try{
Builder = factory.newDocumentBuilder();
Document document = builder.parse(location);
}catch(SAXException se){
//에러 핸들링
}catch(IOException ioe){
//에러 핸들링
}catch(ParserConfigurationException pce){
//에러 핸들링
}
10.4 DOM의 사용법
DOM은 몇 가지의 자바 인터페이스를 정의하는데 다음이 가장 일반적인 인터페이스이다.
- Node : DOM의 가장 기초적인 데이터 타입
- Element : 엘리먼트 타입
- Attr : 엘리먼트의 속성
- Text : 엘리먼트나 그것의 속성을 나타내는 실질적인 컨텐트
- Document : 전체 XML 문서를 표현하는 것으로 DOM tree라고도 한다.
다음은 DOM을 사용할 때 가장 많이 사용하게 될 메소드들이다.
- Document.getDocumentElement()
: XML 문서의 루트(root)엘리먼트를 리턴한다.
- Node.getFirstChild() 와 Node.getLastChild()
: 주어지는 노드의 처음과 마지막 노드를 리턴한다.
- Node.getNextSibling()과 Node.getPreviousSibling()
: 주어진 노드의 전과 다음 노드를 리턴한다.
- Node.getAttribute(attrName)
: 주어진 노드에 파라미터로 들어온 attrName을 가진 속성(attribute)을 리턴한다.(예를 들어 id라는 이름의 속성을 얻으려면 getAttribute(“id”) 를 사용하면된다.)
DOM을 사용하기 위해서 해야 할 일을 코드와 함께보도록 하자.
1.Parser 객체를 생성.
try{
-> DomParser parser = new DOMParser(); // Parser 객체를 생성한다.
Parser.parse(url);
Doc = parser.getDocument();
}
파서를 사용하려면 파서 객체의 생성이 불가피하다. 여기서는 DOMParser를 이용해 parser 객체를 생성하고 DOM 인터페이스의 구현을 한다. 이 과정을 try 블록에 넣은 이유는 특정한 환경에서 발생할 수 있는 예외 상황(유효하지 않은 URI, DTD가 없는 것, XML 문서가 유효하지 않거나 “well-formed”가 아닌 경우 등)을 잡아내서 처리하기 위함이다.
2. Parser 객체를 이용해서 XML 문서를 파싱한다.
try{
DomParser parser = new DOMParser();
-> parser.parse(url); // url에 있는 xml 문서를 파싱한다.
-> doc = parser.getDocument(); //Document 객체를 생성한다.
}
…
if(doc != null) //Document 객체가 있으면
-> processDOMTree(doc); //DOM 트리를 만든다.
XML 문서의 파싱은 겨우 한 줄로 끝이 난다. 파싱이 끝나면, 파서가 생성한 Document 객체를 얻을 수 있다. 그 다음은 할 일은 XML 문서에서 정보를 얻을 수 있도록 Document 객체를 이용해 DOM 트리를 만드는 것이다.
3. Parser 객체로부터 생성된 Document 객체(DOM 트리)를 처리한다.
Public void processDOMTree(Node node)
{
int nodeType = Node.getNodeType();
switch(nodeType)
{
case DOCUMENT_NODE:
-> processDOMTree(((Document)node).GetDocumentElement())
…
case ELEMENT_NODE:
…
NodeList children = node.getChildNodes();
if(children != null){
for(int i=0 ; i<children.getLength(); i++)
-> processDOMTree(children.item(i);
}
……
이제 XML 문서의 파싱은 끝났고, DOM 트리를 만드는 일만 남았다. 트리를 만드는 과정은 각 노드의 타입을 얻고 그 타입에 따라서 트리를 구성한다. 코드를 자세히 살펴보면 알겠지만 위 코드는 재귀적인 구조를 가지고 있다. 왜냐하면 특정 노드 안에 또 다른 노드가 있을 수 있기 때문에 이를 처리하기 위함이다. 만약에 전화번호부를 XML로 만들었다면 거기에 포함된 엔트리의 수는 수백만이 넘을지도 모르지만 각 레이어의 레벨이 많지 않기 때문에 스택 오버플로우(stack overflow)는 걱정하지 않아도 된다.
9.5 SAX의 사용법
SAX API는 몇 개의 이벤트의 정의한다. 개발자는 자바를 이용해서 원하는 모든 이벤트를 다룰 수 있다. 만약 어떤 타입의 이벤트를 다루기 싫다면 그것을 위해 별도의 코딩을 할 필요가 없다. 그저 발생되는 이벤트를 무시하면 파서는 그것을 취급하지 않기때문이다.
이제 SAX에서 사용되는 이벤트를 보도록 하겠다. 이 이벤트들은 org.xml.sax 패키지 안에 있는 HandlerBase 클래스의 한 부분이다.
- startDocument
: 문서의 시작을 알림
- endDocument
: 문서의 끝을 알림.
- startElement
: 엘리먼트의 시작을 알림, 파서는 이 이벤트를 시작태그를 만날 때 마다 발생시킨다.
- endElement
: 엘리먼트의 끝을 알린다.
- characters
: DOM의 text 노드와 유사하게 character 데이터를 가진것
- ignorableWhitespace
: 공백을 무시하고자 할때 사용된다. 모든 공백노드는 무시된다.
- warning, error, fatalError
: 이 세가지 이벤트들은 파싱 에러를 말한다.
- setDocumentLocator
: SAX locator 객체의 저장을 허락하는 이벤트이다.
SAX API는 사실상 네 가지 이벤트 핸들링 인터페이스로 구분이 된다. EntityHandler, DTDHandler, DocumentHandler, ErrorHandler 로 정의가 되는데, 이 모든 인터페이스는 HandlerBase에 의해 정의된다. 대부분의 Java code는 HandlerBase 클래스를 확장한다.
SAX 이벤트를 다루기위해 SAX 메소드를 사용해야한다. 다음이 가장 일반적으로 많이 사용되는 SAX 메소드이다. 위에서 살펴본 이벤트와 일치한다.
- startDocument(), endDocument()
- startElement(String name, AttributeList attrs)
- endElement(String name)
- characters(char ch[], int start, int length)
SAX Parser의 사용도 DOM parser의 사용법과 유사하다.
Parser 객체를 생성한다.
SAXParser parser = new SAXParser(); //파서를 생성
parser.setDocumentHandler(this);
parser.setErrorHandler(this);
try{
parser.parse(uri);
}
구조는 DOM 예제와 같은데 여기서는 우선 Parser 객체의 생성을 DOMParser 대신 SAXParser를 사용한다. 여기서 주지할만한 것은 XML 문서를 파싱하는데 setDocumenthandler와 setErrorHandler 메소드를 사용한다는 것이다.
XML 문서를 파싱한다.
SAXParser parser = new SAXParser();
parser.setDocumentHandler(this);
parser.setErrorHandler(this);
try{
parser.parse(uri); //URI에 있는 xml문서를 파싱한다.
}
SAX Parser 객체가 생성이 됐으면 문서를 파싱한다. Try 블록으로 처리한것은 에러가 발생할 경우 그것을 잡아내기 위함이다.
SAX 이벤트를 처리한다.
Public void startDocument()
…
public void startElement(String name, AttributeList attrs)
…
public void characters(char ch[], int start, int length)
…
public void ignorableWhitespace(char ch[], int start, int length)
….
XML 문서에서 생성되는 SAX 이벤트 처리하는 SAX 이벤트 핸들러를 SAXParser 객체가 호출하면서 파싱은 진행된다. Document의 시작을 체크하고, 각 엘리먼트를 이름과 속성에 따라 구분한다. Characters로 글자의 컨텐트, 시작, 길이를 체크한다. 공백은 무시할 수 있다.
DOM은 문서의 모든 정보를 표현하기위해 java 객체로 만들고 그 DOM 트리를 저장하려면 제법 많은 양의 메모리가 사용된다. 그러나 파서로 생성된 대부분의 객체들은 한번도 사용되지 못하고 쓰이지 않는다. 이렇기 때문에 SAX로 필요한 이벤트만 찾아서 그것에 따른 이벤트 핸들링을 해주면 훨씬 효율적인 것이다.
맺음말
지금까지 첫번째 연재에서 Java+XML programming의 소개를 했고, 이번 연재에서는 Java+XML programming의 핵심 부분인 DOM과 SAX parser의 소개, 각각의 특성, 사용방법을 알아보았다. 다음 연재는 본격적인 예제를 통해서 Java/XML technology를 다른 응용분야에 적용할 수 있는 가능성을 제시해 보려한다.
Reference
[1] Should I use SAX or DOM (Nazmul Idris)
[2] Introduction to XML, Java, databases and the Web(Nazmul Idris)
[3] XML APIs for Databases (Ramnivas Laddad)
[4] XML for the absolute beginner (Mark Johnson)
[5] Database systems (thomas connolly, Carolyn begg, anne strachan)
[6] java XML Application categories (Nazmul Idris)
[7] Introduction to DOM
[8] Java API for XML Parsing Version 1.0
[9] IBM developerWorks turorial
[10]Java makes the most of XML
[11]Why XML is Meant for Java
[12]XML and Java Technology Tackle Enterprise Application Integration
[13]XML JavaBeans, Part1
UNIX 사양 알아내기 (0) | 2007.11.12 |
---|---|
UNIX 명령어 정리 (0) | 2007.11.12 |
JDK 톰캣 Linux 설치 (0) | 2007.11.12 |
아스키 코드표 (0) | 2007.11.12 |
트랙백이란? (1) | 2007.11.11 |