Ping Guo, Julie Basu, Mark Scardina, K. Karun
Java 애플리케이션에 맞는 올바른 구문 분석 기술 선택.
XML이 널리 채택되면서 XML 문서의 효율적인 구문 분석이 점점 더 중요해지고 있습니다. 특히 대규모 볼륨을 처리하도록 되어 있는 애플리케이션에서는 XML 데이타를 효율적으로 구문 분석하는 방법이 매우 중요합니다. 잘못된 구문 분석은 과도한 메모리 사용과 처리 시간으로 인해 확장성을 저해할 수 있습니다.
여러 유형의 XML 구문 분석기를 사용할 수 있습니다. 그렇다면 이 중에서 여러분의 상황에 맞는 구문 분석기는 무엇일까요? 이 문서에서는 널리 사용되는 세 가지 XML 구문 분석 기술을 설명하고 애플리케이션의 요구 사항에 따라 올바른 기술을 선택하는 방법을 살펴보도록 하겠습니다.
Java에 대한 다음 세 가지 XML 구문 분석 기술이 널리 사용되고 있습니다.
- W3C의 완전한 표준인 DOM(Document Object Model)
- 널리 채택된 최초의 Java로된 XML용 API이자 사실상 표준인 SAX(Simple API for XML)
- JSR-173에서 소개된 유력한 새 구문 분석 모델인 StAX(Streaming API for XML)
이러한 각 기술은 장점과 단점을 갖고 있습니다.
이 문서의 예제에서는 책 카탈로그를 설명하는 다음 XML 문서 books.xml가 사용됩니다.<catalog> <!—Sample —> <book id="101"> <title>XML in a Nutshell</title> <author>Elliotte Rusty Harold, W. Scott Means</author> <price>39.95</price> </book> <book id="121"> <title>Who Moved My Cheese</title> <author>Spencer, M.D. Johnson, Kenneth H. Blanchard</author> <price>19.95</price> </book> </catalog>
DOM 구문 분석
DOM은 전체 구문 분석 트리를 메모리에 작성하는 트리 기반의 구문 분석 기술입니다. DOM은 전체 XML 문서에 대한 완전한 동적 액세스를 허용합니다.
그림1은 DOM 구문 분석 모델의 트리와 유사한 구조를 보여 줍니다. Document는 모든 DOM 트리의 루트이며 루트는 최소한 하나 이상의 자식 노드(Child Node), 즉 루트 요소(예제 코드에서는 카탈로그 요소)를 가집니다. 또 다른 노드는 DTD 선언을 위한 DocumentType이며 이 문서의 예제에서는 이 노드가 정의되지 않습니다. 카탈로그 요소는 자식 노드를 가지며 그 아래에 또 다른 자식 노드가 있습니다. 자식 노드는 요소, 텍스트, 주석, 처리 명령 등이 될 수 있습니다.
그림 1: DOM 트리 |
다음 예제는 DOM API의 작동 방법을 보여 줍니다. 이 예제 코드는 카탈로그에 대한 이전 XML 문서에서 모든 책 제목을 출력합니다.
DOMParser parser = new DOMParser(); parser.parse("books.xml"); Document document = parser.getDocument(); NodeList nodes = document.getElementsByTagName("title"); for(int i = 0; i < nodes.length(); i ++)
{ Element titleElem =(Element)nodes.item(i); Node childNode = titleElem.getFirstChild(); if (childNode instanceof Text)
{ System.out.println("Book title is: " + childNode.getNodeValue()); } }
이 프로그램은 XML 파일 이름을 가져오고 DOM 트리를 만든 다음 getElementsByTagName() 메소드를 사용하여 모든 DOM 요소 노드에서 제목 요소를 찾습니다. 그런 다음 제목 요소 목록을 반복하고 getFirstChild() 메소드를 사용하여 요소의 시작과 끝 태그 사이에 포함된 텍스트를 가진 첫 번째 자식 노드를 검사하여 각 제목 요소와 관련된 텍스트 정보를 출력합니다.
DOM을 사용하는 것은 이와 같이 간단합니다. 전체 트리가 메모리에 만들어지기 때문에 XML 문서를 임의로 액세스할 수 있습니다. DOM API를 사용하면 자식 노드를 추가하거나 노드를 업데이트 또는 삭제하는 등의 노드 수정 작업을 수행할 수 있습니다.
메모리 트리 구조는 우수한 탐색 지원을 제공하지만 몇 가지 고려해야 할 구문 분석 전략 문제를 갖고 있습니다. 첫째로, 부분 구문 분석이 불가능하기 때문에 전체 XML 문서를 한 번에 구문 분석해야 합니다. 둘째로, 전체 문서를 로드하고 전체 트리 구조를 메모리에 작성하는 것은 적지 않은 부담이 될 수 있습니다(특히 문서가 큰 경우). 일반적으로 DOM 트리는 문서보다 훨씬 크기 때문에 많은 메모리를 소비할 수 있습니다. 셋째로, 일반 DOM 노드 유형은 상호 운용성 이점을 갖고 있지만 객체 유형 바인딩을 수행할 때는 최적의 선택이 아닐 수 있습니다.
특정 종류의 애플리케이션은 다른 애플리케이션보다 DOM 구문 분석에 더 적합합니다. DOM 구문 분석은 애플리케이션이 XML 문서에 대한 임의 액세스 권한을 가져야 할 경우에 적합합니다. 이에 대한 적절한 예로, 템플릿을 처리하면서 전체 파일을 반복적으로 탐색해야 하는 XSL 프로세서를 들 수 있습니다. DOM을 사용하면 문서를 업데이트할 수 있기 때문에 데이타를 수정해야 하는 XML 편집기와 같은 애플리케이션에도 편리합니다.
SAX 구문 분석
SAX는 XML 처리를 위한 이벤트 반응형 푸시(push) 모델입니다. SAX는 W3C 표준이 아니지만 대부분의 SAX 구문 분석기가 호환되는 방식으로 구현하는 매우 잘 알려진 API입니다. DOM과 같이 전체 문서의 트리 표현을 작성하는 대신 SAX 구문 분석기는 문서를 읽을 때 일련의 이벤트를 발생시킵니다. 이러한 이벤트는 문서 내용에 대한 액세스를 제공하는 이벤트 처리기로 푸시됩니다. 다음과 같은 세 가지 기본 유형의 이벤트 처리기가 있습니다.
- XML DTD 내용을 액세스하기 위한 DTDHandler
- 구문 분석 오류에 대한 하위 수준 액세스를 위한 ErrorHandler
- 문서 내용을 액세스하기 위한 ContentHandler(가장 일반적으로 사용되는 유형)
그림 2는 SAX 구문 분석기가 콜백 메커니즘을 통해 이벤트를 보고하는 방법을 보여 줍니다. 이 구문 분석기는 입력 문서를 읽은 다음 문서를 처리하는 동안 각 이벤트를 MyContentHandler로 푸시합니다.
그림 2: 문서를 일련의 이벤트로 애플리케이션에 보고하는 SAX |
다음 예제는 이전 DOM 예제와 동일한 작업을 수행합니다. 즉, 책의 제목 정보를 출력합니다.
우선, DefaultHandler 클래스에 기반하고, 여러분이 원하는 이벤트 유형에 대한 메소드를 대체하는 ContentHandler 구현 클래스를 작성합니다. 이 코드는 DefaultHandler 클래스의 나머지 이벤트를 모두 버립니다. 사용자 정의된 ContentHandler 클래스는 콜백 메소드를 제공하며 상태 관리를 수행함으로써 제목 요소뿐만 아니라 시작 요소 이벤트, 종료 요소 이벤트 및 문자 이벤트를 비롯한 모든 요소를 처리해야 합니다.
public class MyContentHandler extends DefaultHandler
{
boolean isTitle;
public void startElement(String uri, String localName,
String qName, Attributes atts)
{
if (localName.equals("title"))
isTitle = true;
}
public void endElement(String uri, String localName,
String qName)
{
if(localName.equals("title"))
isTitle = false;
}
public void characters(char[ ] chars, int start, int length)
{
if(isTitle)
System.out.println(new String(chars, start, length));
}
}
그런 다음 사용자 정의된 ContentHandler를 SAX 구문 분석기로 설정하면 구문 분석기는 XML 문서를 처리하기 시작합니다. SAX 구문 분석기는 문서를 처음부터 끝까지 읽는 동안 이벤트를 생성하여 ContentHandler로 푸시합니다.
SAXParser saxParser = new SAXParser();
MyContentHandler myHandler = new MyContentHandler();
saxParser.setContentHandler(myHandler);
saxParser.parse(new File("books.xml"));
DOM과 비교하여 SAX 구문 분석기는 뛰어난 성능 이점을 제공합니다. SAX 구문 분석기는 XML 문서의 내용에 대한 효율적인 하위 수준 액세스를 제공합니다. SAX 모델은 전체 문서를 메모리로 한 번에 로드할 필요가 없기 때문에 메모리 소비량이 적다는 큰 이점이 있으므로, SAX 구문 분석기가 시스템 메모리보다 큰 문서를 구문 분석할 수 있습니다. 또한 DOM에서와 같이 모든 노드에 대한 객체를 만들 필요가 없습니다. 마지막으로 SAX "푸시" 모델은 ContentHandler가 하나씩 차례대로 사용되는 파이프라인이 아니라 여러 개의 ContentHandler가 등록되고 이벤트를 병렬로 받을 수 있는 브로드캐스트 컨텍스트에서 사용할 수 있습니다.
SAX의 단점은 모든 수신 이벤트를 처리하기 위해 이벤트 처리기를 구현해야 한다는 것입니다. 개발자는 애플리케이션 코드에서 해당 이벤트 상태를 유지 관리해야 합니다. SAX 구문 분석기가 DOM의 부모/자식 지원과 같은 메타 정보를 전달하지 않으므로 문서 계층에서 구문 분석기가 있는 위치를 추적해야 합니다. 따라서 문서가 복잡해질수록 애플리케이션 논리가 더 복잡해집니다. 전체 문서를 메모리로 한 번에 로드할 필요가 없지만 SAX 구문 분석기는 여전히 DOM과 마찬가지로 전체 문서를 구문 분석해야 합니다.
SAX가 직면한 가장 큰 문제는 XPath가 제공하는 것과 같은 내장된 문서 탐색 지원이 없다는 점일 것입니다. 이는 원패스(one-pass) 구문 분석과 함께 결합되어 임의 액세스 지원이 없다는 것을 의미합니다. 또한 이 제한은 네임 스페이스에 존재합니다. 즉, 상속된 네임 스페이스를 가진 요소는 주석 처리할 수 없습니다. 이러한 제한으로 인해 SAX는 문서를 조작 또는 수정하는 경우에 적합하지 않습니다.
Oracle XML Developer Kit는 Java, C 및 C++ 개발을 위한 XML 구문 분석기를 제공합니다. 이러한 구문 분석기는 각각 기업에 맞게 구현된 DOM 및 SAX 인터페이스를 제공합니다. 또한 Java용 StAX 구문 분석기의 기술 사전 검토를 확인할 수도 있습니다. 이러한 구성 요소는 Oracle Technology Network의 XML Technology Center(otn.oracle.com/kr/tech/xml)에서 다운로드할 수 있습니다. |
SAX 구문 분석은 문서의 내용을 단지 한 번에 읽어야 하는 애플리케이션에 큰 이점을 제공할 수 있습니다. 대부분의 B2B 및 EAI 애플리케이션은 최종으로 수신하는 측에서 모든 데이타를 검색하는 캡슐화 형식으로 XML을 사용합니다. 이 경우에는 SAX의 효율성과 높은 처리 능력으로 인해 SAX가 DOM보다 훨씬 더 유리합니다. SAX 2.0에는 간편하게 문서 하위 집합을 출력하거나 간단한 문서 변환을 수행할 수 있는 내장된 필터링 메커니즘이 있습니다. 마지막으로 SAX 구문 분석은 DTD 및 XML 스키마에 대한 검증에 매우 유용합니다. 실제로 Oracle은 SAX 구문 분석기를 내부적으로 사용하여 이 검증을 수행함으로써 DOM을 사용할 때보다 적은 메모리를 사용하면서 더 높은 효율성을 실현합니다.
StAX 구문 분석
StAX는 SAX와 마찬가지로 이벤트 반응형 모델을 사용하는 새로운 구문 분석 기술입니다. 그러나 StAX는 SAX의 푸시 모델을 사용하는 대신 풀(pull) 모델을 이벤트 처리에 사용합니다. 콜백 메커니즘을 사용하는 대신 StAX 구문 분석기는 애플리케이션에 의해 요청되었을 때 이벤트를 반환합니다. 또한 StAX는 사용자에게 친숙한 읽기/쓰기를 위한 API를 제공합니다.
SAX가 여러 다른 유형의 이벤트를 ContentHandler에 반환하는 것과 달리 StAX는 자체 이벤트를 애플리케이션에 반환하며 심지어 이벤트를 객체로 제공할 수도 있습니다.
그림 3은 애플리케이션이 이벤트를 요청하면 StAX 구문 분석기가 필요에 따라 XML 문서에서 내용을 읽은 후에 이벤트를 애플리케이션에 반환하는 방법을 보여 줍니다.
그림 3: 이벤트를 보고할 것을 StAX에 요청하는 애플리케이션 |
StAX에는 StAX 읽기 프로그램(reader) 및 기록자(writer)를 작성하기 위한 팩토리가 포함되어 있으므로 애플리케이션은 특정 구현의 세부 정보를 참조하지 않고 StAX 인터페이스를 사용할 수 있습니다.
DOM 및 SAX와 달리 StAX는 두 개의 구문 분석 모델(커서 모델 및 이터레이터 모델)을 지정합니다. 커서 모델은 SAX와 마찬가지로 단순히 이벤트를 반환합니다. 이벤트를 객체로 반환하는 이터레이터 모델은 더 자연스러운 인터페이스를 제공하지만 객체 작성의 추가 오버헤드를 가집니다. 아래의 StAX 구문 분석 API 예제는 각 모델의 예를 보여 줍니다.
다음 예는 커서 모델을 사용하여 위의 XML 책 카탈로그에서 책 제목 정보를 출력합니다.
XMLStreamReader reader = XMLInputFactory .newInstance().createXMLStreamReader( new FileInputStream("books.xml")); while(reader.hasNext())
{ int eventType = reader.next(); if (eventType == XMLEvent.START_ELEMENT &&
reader.getLocalName().equals("title"))
{ reader.next(); System.out.println(reader.getText()); } }
이 예제에서 읽기 프로그램이 설정된 후 애플리케이션은 reader.next() 메소드 호출을 사용하여 다음 이벤트를 요청합니다. 이 요청에 따라 StAX 구문 분석기는 커서를 다음 이벤트 위치로 이동합니다. 이 이벤트가 "title"이라는 요소의 시작 부분을 가리킬 경우 애플리케이션 코드는 reader.next()를 한 번 더 호출하여 커서를 이동한 다음 reader.getText() 메소드 호출을 사용하여 제목 요소에 대한 텍스트를 얻습니다.
다음 예는 이벤트가 객체로 반환되는 이터레이터 모델을 사용합니다.
XMLEventReader eventReader = XMLInputFactory.newInstance()
.createXMLEventReader(new FileInputStream("books.xml"));
while(eventReader.hasNext())
{
XMLEvent event = eventReader.next();
if(event instanceof StartElement &&
((StartElement)event).getLocalName().equals("title"))
{
System.out.println( ((Characters)eventReader.next()).getData());
}
}
이 예에서 애플리케이션은 StAX 구문 분석기를 다음 이벤트 위치로 이동시키고 해당 이벤트 객체를 반환하게 하는 다음 이벤트를 요청합니다. 애플리케이션은 책 제목 정보를 반환하는 getData() 메소드를 사용하여 이벤트 객체를 통해 내용에 액세스할 수 있습니다.
OTN의 XML Center 방문 Oracle XDK 다운로드 Oracle University에서 XML에 대해 알아보기 |
StAX 커서 모델의 성능은 SAX 구문 분석의 성능과 거의 비슷합니다. 그러나 StAX의 경우 애플리케이션이 구문 분석을 제어할 수 있으므로 코드의 작성과 유지 관리가 더 용이합니다. 또한 StAX는 사용 편의성을 위해 이터레이터 모델을 제공하지만 이 경우에 이벤트 객체를 만들면 성능이 저하됩니다. 애플리케이션이 문서에서의 위치를 추적해야 하는 SAX와 달리 StAX는 요청된 이벤트만 반환하는 기능 덕분에 애플리케이션이 이러한 작업을 수행할 필요가 없습니다. 또한 예제에는 나와 있지 않지만 StAX는 SAX보다 훨씬 더 강력한 필터링 기능을 제공합니다.
DOM과 비교하여 StAX는 완전한 탐색 지원이 부족하다는 점에서 SAX와 동일한 단점을 갖고 있습니다. 그러나 어떤 이벤트를 언제 가질 것인지 애플리케이션에서 제어하기 때문에 정방향 문서 탐색은 SAX보다 StAX에서 더 용이합니다.
StAX의 문서 수정 기능은 새 문서가 작성된다는 점에서 SAX와 유사합니다. StAX의 커서 모델과 이터레이터 모델은 모두 기록(write-out) API를 제공하지만 간단한 원패스(one-pass) 변환 이상의 것을 수행하려는 경우 여전히 문서를 수정하기가 쉽지 않습니다.
StAX 구문 분석은 SAX 애플리케이션의 요구 사항을 대부분 충족하므로 SAX 구문 분석에 적합한 애플리케이션은 또한 StAX를 사용할 수도 있습니다. 또한 애플리케이션이 이름 공간에 대한 완전한 지원을 유지하면서 성능을 위해 스트리밍 모델을 활용해야 할 경우 StAX 구문 분석이 최적의 선택입니다. 마지막으로, 가져온 스키마 집합에서처럼 여러 입력을 처리하기 위해 애플리케이션은 여러 StAX 구문 분석기에서 이벤트를 요청하여 단일 컨텍스트에 넣을 수 있으므로 여러 스레드로 인한 복잡성 문제를 걱정할 필요가 없습니다. StAX는 특히 이러한 모든 기능이 필요한 웹 서비스 및 JAX-RPC의 새 영역에 유용합니다.
올바른 구문 분석 모델 선택
이 문서에서는 Java를 위한 세 가지 표준 구문 분석 기술의 작동 방법과 각 기술의 장점 및 단점, 그리고 적절한 애플리케이션에 대해 설명했습니다. 이 문서의 요점을 다음과 몇 가지 간단한 규칙으로 정리할 수 있습니다.
- 응응 프로그램이 반복적으로 전체 문서를 한 번에 탐색 또는 변경하거나 임의로 액세스해야 할 경우에만 DOM 구문 분석을 사용합니다.
- 간단한 읽기 전용 스트리밍이 필요하며 완전한 표준을 반영하는 견고한 구현을 원할 경우 SAX 구문 분석을 사용합니다.
- 완전한 이름 공간 또는 다중 문서 지원이나 객체 인터페이스가 필요한 경우 스트리밍 애플리케이션을 위한 StAX를 사용합니다.
특정 요구를 충족하는 다양한 구문 분석 모드가 존재합니다. 분산 서비스 기반의 애플리케이션이 급격히 증가함에 따라 앞으로는 최적화된 성능이 성공을 위한 필수 요소가 될 것입니다.
Ping Guo(ping.guo@oracle.com)와 Julie Basu(julie.basu@oracle.com)는 Oracle Java 및 XML 기술 그룹의 구성원입니다.
Mark Scardina(mark.scardina@oracle.com)와 K. Karun(k.karun@oracle.com)은 Oracle CORE 및 XML Development 그룹의 구성원입니다.
XML 구문 분석 기술 요약
기술 | 장점 | 단점 | 가장 적합한 경우 |
DOM 구문 분석 |
|
|
|
SAX 구문 분석 |
|
|
|
StAX 구문 분석 |
|
|
|