반응형
출처: http://www.ibm.com/developerworks/kr/xml/standards/x-soapspec.html
 난이도 : 중급

필자: W3C

2007 년 6 월 26 일

SOAP 프로토콜에서는, 인터넷 프로토콜로 연결된 시스템들간 통신에 XML을 사용할 수 있습니다. XML 정보에 표준 인벨롭(envelope)을 제공하여 네트워크 메시지들을 통해 전송될 수 있도록 하고, 메시지 바디(body)에 대한 규약도 제공합니다. SOAP의 역사를 이해하고, 웹 서비스, 서비스 지향 아키텍처(SOA), Representational State Transfer (REST)와의 관계를 이해해 봅시다.

SOAP [W3C Recommendation]은 인터넷 프로토콜을 사용하여 연결되어 있는 시스템들 간 통신에 XML을 사용하는 프로토콜이다. 많은 사람들은 SOAP을 XML 웹 서비스의 토대, XML 데이터 포맷을 사용하여 연결된 시스템간 인터랙션을 관리 및 구성하는 기술, 인터넷 통신 프로토콜로 생각하고 있다. SOAP은 원래 IBM®을 비롯한 다양한 기업에서 모인 사람들에 의해 개발되었다. 견고한 아키텍처와 상용 지원을 갖추었던 초기 XML 메시징과 유사한 기능을 제공했기 때문에 빠르게 대중화되었다. World Wide Web Consortium (W3C)으로 넘어간 SOAP의 개발은 SOAP 1.2까지 탄생시켰고, 많은 아키텍처 향상을 이룩했지만, 이에 못지않게 많은 논란의 대상이 되었다. SOAP 프로토콜은 가상 XML 페이로드를 포함하여 XML Envelope 포맷을 정의하고 있다. (실제 SOAP 메시지의 페이로드가 XML의 완전한 기능을 사용하지 못한다는 사실은 상당한 논쟁거리가 된다.)

XML 웹 서비스는 서비스 지향 아키텍처(SOA)라고 하는 일반적인 개념과 밀접하게 연관되어 있지만, 이 중 어떤 개념들도 SOAP을 대체하지는 못한다. 많은 사람들은 HTTP를 통해서 직접 미가공 XML 문서들을 교환한다는 개념을 옹호하고 있다. 이는 Representational State Transfer (REST)가 추구하는 방식이기도 하다. REST는 Roy Fielding이라고 하는 아키텍트가 명명한 웹의 아키텍처 스타일이다. REST 스타일의 웹 서비스 옹호자는 SOAP은 복잡하고, XML 페이로드를 방해하고, 웹의 강점을 충분히 활용하지 못한다고 지적하고 있다. SOAP 옹호론자들은 SOAP의 원격 프로시저 호출(RPC) 루트에서 document-literal 스타일의 SOAP으로 강조를 옮김으로써 이러한 문제를 해결해왔다. RPC 스타일에서, 전송되는 데이터는 특별한 XML 페이로드 포맷(SOAP encoding)에 개별 데이터 유형으로 마샬링 된다. document-literal 스타일에서, XML 페이로드는 보다 설명적이고 가독성 있는 자연스러운 XML 포맷으로 구성된다.

SOAP 조직

SOAP과 관련하여 많은 표준들이 만들어지고 있지만, 이 글에서는 다루지 않겠다. 다음은 SOAP 관련 표준과 관련한 리소스들이다.

SOAP의 전신에 해당하는 XML Remote Procedure Calls (XML-RPC) [community specification]는 여전히 광범위하게 사용되고 있다. XML-RPC는 XML로 인코딩 되고 HTTP를 통해 통신하는 프로시저 호출을 정의한다. 단순함(전체 스팩은 불과 10페이지 밖에 안된다.)과 대부분의 언어와 많은 애플리케이션 프레임웍이 표준 또는 쉽게 사용할 수 있는 XML RPC 구현을 갖고 있다는 사실 때문에 여전히 대중성을 확보하고 있다. 원시적인 데이터 타이핑과 문자 인코딩 지원의 부족이라는 치명적인 단점이 있다.


아는 지인이 SOAP 과 ebXML에 대한 질문을 해왔다. 현재 일하고 있는 곳에서 사용하고 있지만
개념을 확실히 알고 사용하는 것이 아니였기에 지인에게 정확한 답변을 해주지 못하였다.
이에 개념을 확실히 정리해야 겠다는 생각이 들어 자료를 정리해본다.
현재 하고 있는 일에 관한 많은 부분에 대해서 개념은 없고 사용만 하는 부분이 많다.
좀 더 하는 일에 대해 개념을 정립하고 그에 관련된 정보를 모아서 정리해야겠다.
반응형
출처:  http://www.ibm.com/developerworks/kr/library/j-jdom/

JDOM은 XML과 함께 작동하는 고유한 자바 툴킷으로서, XML 애플리케이션의 신속한 개발을 목적으로 설계되었습니다. JDOM의 디자인에는 자바 언어의 신택스부터 의미까지 포괄되어 있습니다. 하지만, 기존의 XML API보다 과연 얼마나 나을까요? 여러분이 직접 예제를 실행해 보고, 오픈 소스 프로젝트의 디자인 목표와 비교하면서 판단해 봅시다.

개발자인 여러분들도 80-20 규칙에 대해 들어봤을 것이다. 프로세스나 방법론이 모든 상황의 80 퍼센트를 차지하고, 나머지 20 퍼센트는 상황 별로(case-by-case) 다루어져야 한다. 소프트웨어 개발 세계에서 개발자가 주어진 기술을 사용하여 수행할 수 있는 일들의 80 퍼센트를 이룩하기는 매우 쉽다.

물론, 소프트웨어 제품과 표준이 80-20 규칙을 늘 따르는 것은 아니다. 특히 자바 XML 툴의 어긋난 부분은 이 규칙의 예외를 증명하고 있다. 자바 프로그래밍 세계는 수 많은 API들로 가득 차있다. 어떤 것은 자생한 것이고, 어떤 것은 대기업의 마케팅의 지원을 받기도 한다. XML의 보편성에 대한 약속으로서, 모든 새로운 태스크에는 새로운 기술이 있다. 하지만, 무엇이 접착제 역할을 하고, 여러분은 80 퍼센트의 작업을 수행하는데 적합한 툴을 어떻게 찾겠는가? JDOM은 이러한 질문을 염두 해 두고 구현된 XML API이다.

자바와 XML

여러 가지 면에서, 자바 언어는 XML을 위한 프로그래밍 언어가 되었다. Apache Software Foundation과 IBM alphaWorks의 노력으로 XML 문서의 생성, 조작, 변형, 파싱을 위한 완전한 툴 체인이 생겼다.

많은 자바 개발자들은 XML을 매일 사용하지만, Sun은 XML을 자바 플랫폼에 적용하는데 뒤쳐졌다. Java 2 플랫폼은 XML이 비즈니스 대 비즈니스 통합부터 웹 사이트 콘텐트 스트리밍에 이르기까지 모든 것에 대한 핵심 기술이 되기 전에 가치 있는 것이 되었기 때문에 Sun은 폭넓은 채택성을 획득했던 기존 XML API의 창시자가 되는 JSR 프로세스를 사용해왔다. 가장 중요한 것은 JAXP(Java API for XML Parsing)의 추가이다. 여기에는 세 개의 패키지들이 포함된다.

  • org.w3c.dom: XML을 위한 표준 프로그래밍 방식의 Document Object Model의 W3C recommendation의 자바 구현.
  • org.xml.sax: XML 파싱을 위한 이벤트 중심의 API.
  • javax.xml.parsers: 애플리케이션 개발자들이 특정 파서 구현을 설정하고 획득할 수 있도록 해주는 팩토리 구현.

이러한 패키지들의 추가가 자바 개발자들에게는 좋은 일이지만, 고급의 자바-XML 상호 운용성으로 큰 도약을 이룬 것이 아닌 기존 API 표준에 대한 일반적인 순응을 나타낸다. 핵심 자바 플랫폼에서 부족한 것은 XML 문서를 자바 객체로서 조작할 수 있는 매력적인 인터페이스이다.

JDOM을 생각해 보자. 유명한 자바 개발자이자 작가인 Brett McLaughlin과 Jason Hunter의 생각의 산물인 JDOM은 2000년 초반에 Apache 계열의 라이센스 하에서 오픈 소스 프로젝트로서 시작되었다. 폭넓은 자바 개발자 베이스로부터 기여와 피드백, 버그 픽스를 받아들였고, 자바 코드에서 XML 데이터에 액세스 하여, 조작 및 결과를 만들어 내는 완벽한 자바 플랫폼 기반의 솔루션 구현을 목표로 설정했다.






API로서의 JDOM

JDOM은 XML 문서들을 프로그래밍 방식으로 조작하는 org.w3c.dom 패키지에 대한 대안으로서 사용될 수 있다. 완벽한 대체는 아니고, 사실, JDOM과 DOM은 공존할 수 있다. 게다가, JDOM은 텍스트 인풋에서 XML을 파싱하는 것을 신경 쓰지 않는다. 파서 구현을 설정 및 실행하는데 도움이 되는 래퍼 클래스를 제공하기도 한다. JDOM은 기존 API를 기반으로 구현되었다.

대안 API의 필요성을 이해하려면, W3C DOM의 디자인 제약 조건에 대해 살펴보자.

  • 언어 독립성. DOM은 자바 언어를 염두 해 두고 설계되지 않았다. 이것의 접근 방식은 다양한 언어들 사이에서 매우 비슷한 API를 유지하지만, 자바의 이디엄에 익숙한 프로그래머에게는 성가신 API이다. 예를 들어, 자바 언어는 String 클래스가 언어에 구현되어 있지만, DOM 스팩은 고유의 Text 클래스를 정의한다.

  • 엄격한 계층. DOM의 API는 XML 스팩을 따른다. 따라서, 모든 것의 노드가 되는 XML에서, 모든 것이 확장하는 DOM에서 Node 기반 인터페이스와 Node를 리턴하는 메소드의 호스트를 찾는다. 이는 다형성의 관점에서 볼 때는 뛰어나지만, 자바 언어로 작업하기에는 불편하다. Node에서 리프(leaf) 유형으로의 변화는 장황하고 이해하기 어려운 코드를 만든다.

  • 인터페이스 중심. 퍼블릭 DOM API는 인터페이스들로만 구성된다. (한 가지 예외는 Exception 클래스이다.) W3C는 인터페이스를 정의할 때 구현을 제공하는 것에는 관심이 없다. 자바 프로그래머로서 API를 사용한다는 것은 XML 객체들을 생성할 때 어느 정도의 분리가 된다. W3C 표준은 일반적인 팩토리 클래스와 유연하지만 덜 직접적인 패턴들을 사용하기 때문이다. XML 문서들이 애플리케이션 레벨 코드가 아닌 파서에 의해서만 구현되는 특수한 경우, 이는 무관하다. 하지만, XML 사용이 널리 퍼지면서, 애플리케이션 개발자들은 XML 객체들을 프로그래밍 방식으로 구현하는 편리한 방법을 필요로 하게 되었다.

프로그래머에게, 이러한 제약 조건은 (메모리 사용과 인터페이스 규모 면에서) 무겁고 다루기 어렵다는 것을 의미한다. 반대로, JDOM은 자바 중심의, 경량의 API이다. DOM의 원리를 조정하여 위에 언급한 불편함을 해소시켰다.

  • JDOM은 자바 플랫폼 식이다. 이 API는 자바 언어의 빌트인 String 지원을 사용하기 때문에, 텍스트 값은 String으로서 언제나 사용할 수 있다. ListIterator 같은 Java 2 플랫폼 컬렉션 클래스도 활용하면서 자바 언어에 익숙한 프로그래머에게 풍부한 환경을 제공한다.

  • 계층이 없음. JDOM에서, XML 엘리먼트는 Element의 인스턴스이고, XML 애트리뷰트는 Attribute의 인스턴스이며, XML 문서는 Document의 인스턴스이다. 이 모든 것들이 XML에서 다른 개념들을 나타내기 때문에, 무정형의 "노드"로서가 아닌 고유의 유형으로서 참조된다.

  • 클래스 중심. JDOM 객체는 Document, Element, Attribute 같은 클래스들의 직접적인 인스턴스이므로, 이를 구현하는 것은 자바 언어에서 new 연산자를 사용하는 것만큼이나 쉽다. 또한 설정 할 팩토리 인터페이스가 없다. JDOM은 jar에서 직접 사용할 준비가 되어있다.





JDOM 문서 구현 및 조작

JDOM은 표준 자바 코딩 패턴을 사용한다. 가능하다면, 복잡한 팩토리 패턴 대신에 자바 new 연산자를 사용하면서, 신참 사용자들도 객체를 쉽게 조작할 수 있게 해준다. JDOM을 사용하여 XML 문서를 구현하는 방법을 살펴보자. 우리가 구현할 구조는 Listing 1과 같다. (참고자료 섹션에서 전체 코드를 다운로드 할 수 있다.)


Listing 1. 구현할 XML 문서 샘플
                

<?xml version="1.0" encoding="UTF-8"?>
<car vin="123fhg5869705iop90">
  <!--Description of a car-->
  <make>Toyota</make>
  <model>Celica</model>
  <year>1997</year>
  <color>green</color>
  <license state="CA">1ABC234</license>
</car>

주: 아래 Listing 2부터 7까지 샘플 문서를 구현할 것이다.

먼저, 루트(root) 엘리먼트를 만들고 이를 문서에 추가한다.


Listing 2. Document 구현하기
                

Element carElement = new Element("car");
Document myDocument = new Document(carElement);

이 단계는 새로운 org.jdom.Element를 만들고, 이것을 org.jdom.Document myDocument의 루트 엘리먼트로 만든다. (참고자료 섹션에서 제공하는 샘플 코드를 사용하고 있다면 반드시 org.jdom.*을 반입하라.) XML 문서는 하나의 루트 엘리먼트를 가져야 하므로, Document는 생성자에 Element를 취한다.

다음에는, vin 애트리뷰트를 추가한다.


Listing 3. Attribute 추가하기
                

carElement.addAttribute(new Attribute("vin", "123fhg5869705iop90"));

엘리먼트를 추가하는 것도 매우 단순하다. make 엘리먼트를 추가한다.


Listing 4. 엘리먼트와 하위 엘리먼트
                

Element make = new Element("make");
make.addContent("Toyota");
carElement.addContent(make);

ElementaddContent 메소드가 Element를 리턴하므로, 이를 다음과 같이 작성할 수 있다.


Listing 5. 간결한 형식으로 엘리먼트 추가하기
                

carElement.addContent(new Element("make").addContent("Toyota"));

이 문장들 모두 같은 일을 수행한다. 첫 번째 예제는 보다 읽기 쉽지만, 두 번째는 많은 엘리먼트들을 한번에 구현한다면 더욱 읽기 쉬울 것이라고 말할 수도 있겠다. 문서 구현을 완료하려면 다음과 같이 한다.


Listing 6. 나머지 엘리먼트 추가하기
                

carElement.addContent(new Element("model").addContent("Celica"));
carElement.addContent(new Element("year").addContent("1997"));
carElement.addContent(new Element("color").addContent("green"));
carElement.addContent(new Element("license")
    .addContent("1ABC234").addAttribute("state", "CA"));

license 엘리먼트의 경우, 엘리먼트의 콘텐트를 추가했을 뿐만 아니라, 여기에 애트리뷰트도 추가하면서, 라이센스가 발행되었던 상태를 지정하고 있다. Element에 대한 addContent 메소드는 Element만 리턴하기 때문에 이것이 가능하다.

주석 섹션이나 기타 표준 XML 유형을 추가하는 것도 같은 방식이다.


Listing 7. 주석 추가하기
                

carElement.addContent(new Comment("Description of a car"));

문서 조작은 비슷한 방식으로 발생한다. 예를 들어, year 엘리먼트에 대한 레퍼런스를 획득하려면, ElementgetChild 메소드를 사용한다.


Listing 8. 자식 엘리먼트에 액세스 하기
                

Element yearElement = carElement.getChild("year");

이 문은 실제로 엘리먼트 이름 year를 가진 자식 Element를 리턴한다. year 엘리먼트가 없다면, 호출은 어떤 것도 리턴하지 않는다. DOM Node Node 인터페이스 같은 것에서 리턴 값을 던질 필요가 없었다. Element의 자식 들은 단순히 Element이다. 비슷한 방식으로, 문서에서 year 엘리먼트를 제거할 수 있다.


Listing 9. 자식 엘리먼트 제거하기
                

boolean removed = carElement.removeChild("year");

이 호출은 year 엘리먼트만 제거한다. 나머지 문서는 바뀌지 않은 채로 남아있다.

엘리먼트만 제거한다. 나머지 문서는 바뀌지 않은 채로 남아있다. XMLOutputter 클래스를 사용한다.


Listing 10. JDOM을 XML 텍스트로 바꾸기
                

try {
    XMLOutputter outputter = new XMLOutputter("  ", true);
    outputter.output(myDocument, System.out);
} catch (java.io.IOException e) {
    e.printStackTrace();
}

XMLOutputter는 포맷팅 옵션을 갖고 있다. 여기에서, 우리는 부모 엘리먼트에서 두 스페이스를 들여쓰기 한 자식 엘리먼트를 원한다고 지정했고, 엘리먼트들 사이에 새로운 라인을 원한다는 것을 지정했다. XMLOutputterWriter 또는 OutputStream을 출력한다. 파일로 출력하려면 아웃풋 라인을 다음과 같이 바꾼다.


Listing 11. FileWriter를 사용하여 XML 출력하기
                

FileWriter writer = new FileWriter("/some/directory/myFile.xml");
outputter.output(myDocument, writer);
writer.close();






기존 XML 툴과 결합하기

JDOM의 재미있는 기능들 중 하나는 다른 API들과의 상호 운용성이다. JDOM을 사용하여, Stream 또는 Reader 뿐만 아니라, SAX Event Stream 또는 DOM Document로서도 문서를 출력할 수 있다. 이러한 유연성 때문에 JDOM이 이종의 환경에서 사용될 수 있고, XML을 핸들링 하는 또 다른 메소드를 이미 사용하고 있는 시스템에 추가될 수 있다. 나중에 예제에서 보겠지만, JDOM은 JDOM 데이터 구조를 인식하지 못하는 다른 XML 툴을 사용할 수 있다.

JDOM의 또 다른 사용법은 이미 존재하는 XML 데이터를 읽고 조작하는 기능이다. 잘 구성된 XML 파일을 읽는 것은 org.jdom.input의 클래스들 중 하나를 사용함으로써 수행된다. 이 예제에서, 우리는 SAXBuilder를 사용할 것이다.


Listing 12. SAXBuilder를 사용하여 XML 파일 파싱하기
                

try {
  SAXBuilder builder = new SAXBuilder();
  Document anotherDocument = 
    builder.build(new File("/some/directory/sample.xml"));
} catch(JDOMException e) {
  e.printStackTrace();
} catch(NullPointerException e) {
  e.printStackTrace();
}

Listing 2부터 7까지의 방식과 똑같이 이 프로세스를 통해 구현된 문서를 조작할 수 있다.

JDOM의 또 다른 적용은 이를 Apache의 Xalan 제품과 결합하는 것이다. (참고자료) 위 자동차 예제를 사용하여, 특정 자동차에 대한 상세를 제공하는 온라인 자동차 딜러용 웹 페이지를 구현할 것이다. 우선, 이 문서는 우리가 사용자에게 제공하고자 하는 자동차에 대한 정보를 나타낸다. 그런 다음, 이 JDOM Document를 XSL 스타일 시트로 결합하고, HTML 포맷의 결과를 서블릿의 OutputStream으로 출력할 수 있다.

이 경우, 우리가 사용할 XSL 스타일시트는 car.xsl이다.


Listing 13. 자동차 기록을 HTML로 변형하는 XSL 문서
                

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/car">
    <html>
        <head>
          <title><xsl:value-of select="make"/> <xsl:value-of select="model"/>
        </head>
        <body>
          <h1><xsl:value-of select="make"/></h1><br />
          <h2><xsl:value-of select="model"/></h2><br />
          <table border="0">
          <tr><td>VIN:</td><td><xsl:value-of select="@vin"/></td></tr>
          <tr><td>Year:</td><td><xsl:value-of select="year"/></td></tr>
          <tr><td>Color:</td><td><xsl:value-of select="color"/></td></tr>
          </table>
        </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

이제, org.jdom.Document를 DOM Document로 바꾸고, 이것을 Xalan에 제공한다. XSL과 가상의 애플리케이션 서버에서 가져온 OutputStream을 나타내는 파일도 함께 제공한다. (Listing 14)


Listing 14. JDOM과 Xalan을 사용하여 HTML 문서 생성하기
                

TransformerFactory tFactory = TransformerFactory.newInstance();

// Make the input sources for the XML and XSLT documents
org.jdom.output.DOMOutputter outputter = new org.jdom.output.DOMOutputter();
org.w3c.dom.Document domDocument = outputter.output(myDocument);
javax.xml.transform.Source xmlSource = 
  new javax.xml.transform.dom.DOMSource(domDocument);
StreamSource xsltSource = 
  new StreamSource(new FileInputStream("/some/directory/car.xsl"));

// Make the output result for the finished document using 
// the HTTPResponse OutputStream
StreamResult xmlResult = new StreamResult(response.getOutputStream());

// Get a XSLT transformer
Transformer transformer = tFactory.newTransformer(xsltSource);

// Do the transform
transformer.transform(xmlSource, xmlResult);

이 예제에서, 아웃풋은 자바 서블릿의 HTTPResponse OutputStream을 통해 체계화 된다. 하지만, 이 스트림은 XMLOutputter를 사용한 이전 예제처럼 쉽게 파일스트림이 될 수 있다. 우리는 DOMOutputter를 사용하여 Xalan용 XML 소스를 생성했다. 하지만, XMLOutputter를 사용하여 XML 문서를 String으로서 출력하고 이를 StreamSource로 만듦으로써 같은 인풋을 생성할 수 있었다. 유연성에 대해서 보자. JDOM은 그 구조를 String, SAX Event Stream, 또는 DOM Document로서 출력할 수 있다. 이는 JDOM이 인풋으로서 이러한 모델을 취할 수 있는 툴과 상호 작동할 수 있도록 해준다. (JDOM 웹 사이트에서 contrib 패키지를 참조하라. 여기에서 JDBC ResultSet-기반 빌더, XPATH 구현 같은 툴을 제공하는 JDOM 기반 유틸리티의 라이브러리를 찾을 수 있다.)

몇 줄의 코드로, JDOM은 다양한 기능을 실행한다. 우리는 XML에서 파싱하고 프로그래밍 방식으로 XML 문서를 생성하고, 그러한 문서들을 조작했고, XML 중심의 웹 페이지를 생성하는데 이를 사용했다.

Sun과 JDOM
JDOM의 공식 1.0 릴리스는 Java Community Process의 진행 과정과 발을 맞춘다. JSR-102로서 제출된 JDOM은 핵심 자바 플랫폼에 들어가도록 승인을 얻었다. 다음은 Sun 측에서 말한 부분이다. "JDOM은 이전 API들보다 사용하기가 훨씬 더 쉽기 때문에, 이 플랫폼에 매우 유용할 것이라고 생각한다." JSR에 따르면, 1.0 릴리스는 JDOM의 패키징 변화를 "org.jdom"에서 "javax.xml.tree"로 간주하고 있다. 미래는 긍정적이지만, 개발자들은 새로운 버전에 발을 맞추려면 코드를 개선해야 한다.





JDOM의 성장: 미래

이 글을 쓰고 있는 현재, JDOM 프로젝트는 Beta 6 버전을 릴리스 했다. 베타 상태임에도, JDOM은 안정적인 구현으로 입증되었다. API의 많은 부분이 안정적이고, 기존 인터페이스들에 잠재적으로 영향을 줄 많은 부분에서 작업이 진행 중이다. 따라서, 이 시점에서 진행되는 어떤 개발 프로젝트라도 JDOM을 무시해서는 안되겠다. 특정 메소드 시그너처와 특정 의미가 바뀔 것이고 핵심 자바 API에 채택될 것이기 때문이다. (Sun과 JDOM 참조)

JDOM을 위한 단기적인 TO-DO 리스트는 API를 안정화 하고 성능 부분을 평가하는 것에 초점이 맞춰졌다. 개발자들을 애먹이는 부분에는 DTD 엔터티 지원과 기타 구조들이다. XPATH 지원과 보다 직접적인 XML 데이터 소스와의 통합 등이 진행 중이다.

그래서, JDOM은 기존 XML API들보다 더 나은가? 여러분이 자바로 꿈을 꾼다면 대답은 '그렇다'이다. JDOM이 여러분이 선호하는 파서나 XML 인식 데이터베이스를 대체하는 것은 아니지만, 이것의 디자인 원리는 XML 세계에 적용될 수 있다.



참고자료

반응형
출처: http://kr.blog.yahoo.com/kwon37xi/folder/3381246.html

Java와 XML 데이터 바인딩이란 XML 파일을 자바 객체로 바꾸는 것이다.(DOM 객체로 만든다는 의미가 아니다)


예를들어 다음과 같은 XML이 있을 때
<AddressBook>
   <Person>
      <Name>홍길동</Name>
      <Address>서울</Address>
      <Phone>02-123-4567</Phone>
   </Person>
</AddressBook>
  • 위와 같은 상황에서 AddressBook, Person, Name, Address, Phone이라는 클래스를 생성해주고
  • XML 데이터를 입력하면 최상위 요소인 AddressBook의 객체가 생성되는 것이다.
  • AddressBook의 객체를 ab라고 할 때 ab.getPerson()하면 Person의 객체를 얻게 된다.
  • Person객체를 person이라 할 때 person.getName()Name객체를 리턴하거나 혹은 직접적으로 문자열 "홍길동"을 리턴하는 식이다.

클래스 생성

클래서 생성은 XML의 제약 집합(DTD, XML Schemas)로부터 자바 클래스를(가능하다면 인터페이스를) 생성하는 과정이다. XML 제약집합을 자바 클래스 정의와 동일하게 간주하면 된다.

언마샬링(Unmarshalling)

언마샬링은 XML 문서를 자바 클래스의 인스턴스로 변환하는 것을 의미한다.

단순히 XML 문서를 얻고 그 문서를 데이터 바인딩 프레임워크가 제공하는 도구나 클래스 인스턴스에 전달한 후, XML문서에 해당하는 자바 객체를 구하면 된다. 이때 생성된 자바 객체는 일반적으로 문서를 나타내는 최상의 부모 클래스의 인스턴스이다.

마샬링(Marshalling)

마샬링은 자바 객체와 이 객체에 종속적인 객체를 XML 형태로 변환하는 과정이다.

Castor

  • http://castor.exolab.org
  • 오픈 소스 XML 데이타 바인딩 프레임워크
  • Xerces 와 castor-버전-xml.jar 가 필요하다.

바잉딩 클래스 생성하기

  • XML Schemas 를 작성한다.
  • 다음을 실행하면 스키마에 따라 -package에 지정된 패키지로 클래스들이 생성된다.

    java org.exolab.castor.builder.SourceGenerator -i catalog.xsd -package javaxml2.castor
    

Unmarshall

File catalogFile = new File("catalog.xml");
InputSource is = new InputSource(new FileInputStream(catalogFile));

// Root 요소 클래스와 InputSource를 인자로 넘겨서 Unmarshalling을 수행한다.
Catalog catalog = (Catalog)Unmarshaller.unmarshal(Catalog.class, is);
  • InputSource 대신 Reader를 사용해도 되지만 문자 인코딩 문제가 발생할 수 있으므로 InputSource가 나은 것 같다.

Marshalling


// 변경된 카탈로그를 다시 파일에 저장한다.
FileWriter writer = new FileWriter(catalogFile);

Marshaller marshal = new Marshaller(writer);
marshal.setEncoding("euc-kr");
marshal.marshal(catalog);
  • 저기서 XML의 문자 인코딩을 지정했는데, 이것은 Writer의 인코딩과 일치해야 한다. 여기서는 운영체제 문자 인코딩이 EUC-KR 이다.
  • 다음 과 같이 Marshaller의 객체를 생성하지 않고 static 메소드로 해도 된다. 하지만 이럴 경우 운영체제의 문자 인코딩이 UTF-8이 아니라면 문자 인코딩 문제가 발생할 수 있다. 이 경우에 Writer의 인코딩을 UTF-8로 맞춰야 한다.

    Marshaller.marshal(catalog, writer);
  • 반응형
    출처: http://kr.blog.yahoo.com/kwon37xi/folder/3381246.html


    • JAXP는 새로운 기능을 제공하는 것이 아니라 기존의 SAX, DOM 파서들을 래핑해서 벤더 중립적으로 SAX와 DOM 기능을 사용할 수 있게 해준다.
    • JAXP는 XML 분석 기능을 제공하지 않는다. 즉, SAX, DOM 혹은 그 이외의 XML 파싱 API 없이 JAXP만 가지고는 XML을 분석할 수 없다.
    • SAX, DOM 그리고 JDOM은 XML을 분석하는데 사용된다. 반면 JAXP는 이러한 API와 분석된 문서의 결과를 얻는 방법을 제공한다. JAXP 자체는 문서를 분석하는 새로운 방법을 제공하는 것은 아니다.
    • 결론 : JAXP는 새로운 작업을 수행하기 위한 API가 아니라 기존에 존재하는 API를 추상화시켜 특정 벤더에 종속적인 코드를 전혀 쓰지않고 하나의 단일된 형태로 사용할 수 있게 만든 중간계층이다.

    JAXP 1.0 with SAX

    • SAX 1.0만 지원한다.
    • SAX 처리 파서와 함께 JAXP를 사용하려면 org.xml.sax.HandlerBase 클래스를 확장하고 애플리케이션에서 처리하려는 콜백들을 구현하면 된다. HandlerBase는 SAX 2.0의 DefaultHandler와 같은 역할을 한다.
    • JAXP는 자바 시스템 Property를 통해서 벤더 클래스의 파서를 지정할 수 있다.

    SAX 사용순서

    • SAXParserFactory 클래스의 객체를 생성한다.
    • SAXParserFactory는 SAX 파서의 인스턴스를 생성하고, 파서의 옵션을 설정하는 역할을 한다.
    • SAXParserFactory에서 설정한 옵션들은 그것을 통해 얻은 모든 파서의 인스턴스에 적용된다.
      • SAXParserFactory.setNamespaceAware(boolean) : 네임스페이스 인식 여부
      • SAXParserFactory.setValidating(boolean) : 유효성 검사 여부
    • 일단 SAXParserFactory를 설정하고 나면, SAXParserFactory.newSAXParser() 메소드를 사용하여 파서에 해당하는 SAXParser 클래스(JAXP에 포함된 클래스임)의 인스턴스를 구할 수 있다.
    • SAXParser.parse()로 XML 파싱을 수행한다.
      // JAXP import
      import javax.xml.parsers.*;
      
      // SAX import
      import org.xml.sax.*;
      
      // SAXParserFactory를 얻는다.
      SAXParserFactory factory = SAXParserFactory.newInstance();
      
      // 유효성 검사를 수행하고, 네임스페이스를 인식하지 않도록 설정
      factory.setValidating(true);
      factory.setNamespaceAware(false);
      
      // SAXParser를 얻어 파싱을 한다.
      SAXParser parser = factory.newSAXParser();
      parser.parse(new File(xmlFileName), new MyHandlerBase());
      // MyHandlerBase는 org.xml.sax.HandlerBase 를 상속한 클래스이다.
      

    발생 가능한 예외

    • FactoryConfigurationError : 일반적으로 파서가 사용하는 JAXP 구현 클래스나 시스템 Property를 불러올 수 없을 경우에 발생한다.
    • ParserConfigurationException : 파서에서 사용할 수 없는 특징을 설정할 때 발생한다.

    SAXParser 클래스

    • SAXParser.isValidating() : 유효성 검사 수행 여부
    • SAXParser.isNamespaceAware() : 네임스페이스 인식 여부
    • SAXParser 클래스는 위 두 특징을 변경할 수 있는 메소드는 제공하지 않는다. SAXParserFactory에서 변경해야 한다.
    • SAXParser.getParser() : 내부적으로 실제 사용하는 파서의 객체(org.xml.sax.Parser의 인스턴스)

    JAXP 1.0 with DOM

    • SAX와 거의 동일하다.
    • 파싱 후 Document 객체를 리턴한다.

    DOM 사용 순서

    • DocumentBuilderFactory 클래스의 인스턴스를 얻는다.
    • factory 객체에서 설정할 사항들을 설정하고,
    • DocumentBuilder를 DocumentBuilderFactory로 부터 얻는다.
    • DocumentBuilder로 파싱을 수행해서 Document 객체를 얻는다.
      // DocumentBuilderFactory를 얻는다.
      DocumentBuilderFactory factory =
        DocumentBuilderFactory.newInstance();
      
      // 여러가지 설정...
      
      // DocumentBuilder 얻기
      DocumentBuilder builder = factory.newDocumentBuilder();
      
      // XML 파싱 수행
      Document doc = builder.parse(new File(xmlFileName));
      

    발생 가능한 예외

    SAX와 동일하다.

    DocumentBuilder 클래스

    • SAX 이벤트를 처리하지 않으므로 HandlerBase 인스턴스가 필요없다.
    • DocumentBuilder.parse()는 곧바로 Document 객체를 리턴한다.
    • SAX의 ErrorHandler를 위한 DocumentBuilder.setErrorHandler()
    • SAX의 EntityResolver를 위한 DocumentBuilder.setEntityResolver()

    네임스페이스?

    JAXP 1.0은 네임스페이스를 처리하지 않는다. "지원"만 할 뿐이다.

    JAXP 1.1은 네임스페이스를 처리할 수 있다.

    파서의 변경

    • JAXP가 사용하는 파서를 변경한다는 것은 실제로 파서를 생성하는 Factory를 변경한다는 의미이다.
    • SAXParserFacotry 변경 : javax.xml.parsers.SAXParserFactory 시스템 프라퍼티로 설정
    • DocumentBuilderFactory 변경 : javax.xml.parsers.DocumentBuilderFactory 시스템 프라퍼티로 설정

    JAXP 1.1

    • XSLT 프로세서는 javax.xml.transform.TransformerFactory 시스템 프라퍼티로 설정할 수 있다.

    1.1에서 바뀐점

    • SAX 2.0과 DOM Level 2를 지원한다.
    • 네임스페이스를 처리한다.
    • SAX 2.0으로 넘어가면서 Parser 인터페이스는 디프리케이티드 되었다. 대신 org.xml.sax.XMLReader를 사용한다.
    • SAXParser.getXMLReader()가 추가되었다.
    • SAXParser에 SAX 2의 DefaultHandler를 인자로 받는 parse() 메소드를 추가했다.
    • SAXParserFactory.setFeature(), SAXParserFactory.getFeature()가 추가되었다.
    • SAXParser.setProperty(), SAXParser.getProperty()가 추가되었다.

    TrAX API : XSL을 위한 API

    • XML 문서 변환을 벤더에 중립적으로 처리할 수 있다.
    • 다음과 같은 순서로 XSL 변환을 처리한다.
      1. TransformerFactory를 얻는다.
      2. Transformer를 얻는다.
      3. 변환을 수행한다.

    Factory

    • javax.xml.transform.TransformerFactory 팩토리 객체를 생성한다.
    • 팩토리 객체에 다양한 옵션을 설정한다. 이 옵션들은 이 팩토리에서 생성되는 모든 Tansformer 인스턴스에 영향을 주게 된다.
      • 속성 설정(각 XSL 프로세서에 종속적임). TransformerFactory.setAttribute(), TransformerFactory.getAttribute()
      • ErrorListener 설정 : 분석도중에 발생하는 문제를 프로그램에서 처리시킨다. javax.xml.transform.ErrorListener 인터페이스 구현. TransformerFactory.setErrorListener()로 설정.
      • URIResolver 설정 : xsl:import 혹은 xsl:include 등에서 가져올 XML 데이터를 Source 객체로 제공해준다. 특정 URI를 만났을 때 Transformer가 여러 곳에 있는 특정 문서를 검색할 수 있게 해준다. javax.xml.transform.URIResolver 인터페이스 구현. TransformerFactory.setURIResolver()로 설정.
    • TansformerFactory.newTransformer()는 변환에 사용되는 스타일시트를 입력으로 받아들인다.

      // TransformerFactory를 얻는다.
      TransformerFactory factory = TransformerFactory.newInstance();
      
      // TransformerFactory를 구성한다.
      factory.setErrorResolver(myErrorResolver);
      factory.setURIResolver(myURIResolver);
      
      // 명시된 옵션들을 가지는 작업에 사용할 Transformer를 얻는다.
      Transformer transformer =
         factory.newTransformer(new StreamSource("foundation.xsl"));
      

    XML 변환

    • 스타일시트의 위치는 반드시 그것의 위치를 나타내는 javax.xml.transform.Source의 인스턴스를 사용해 명시한다.
    • Source 인터페이스 : 스타이시트, XML 혹은 다른 정보들의 집할일 수 있는 입력의 위치
      • StreamSource : InputStream, Reader, 시스템 아이디로 입력 받음
      • DOMSource : DOM 트리에서 데이터 읽기. org.w3c.dom.Node를 인자로 받음. 이미 DOM파싱이 된 문서를 사용할 때는 DOMSource를 써야 성능이 더 좋다.
      • SAXSource : SAX 생성기로 부터 데이타 읽기. InputSource혹은 XMLReader를 입력으로 받는다. SAX 컨텐트 핸들러가 이미 사용중이고, 콜백이 설정되고 변환에 앞서 특정 작업을 처리해야 할 경우라면 SAXSource를 사용하는 것이 좋다.
    • 변환 결과는 javax.xml.transform.Result의 인스턴스로 받는다.
    • Result 인터페이스 : 변환된 문서를 출력할 목표 지정
      • StreamResult
      • DOMResult
      • SAXResult : SAX의 ContentHandler를 인스턴스로 넘겨 받는다.
        // 명시된 옵션들을 가지는 작업에 사용할 Transformer를 얻는다.
        Transformer transformer =
            factory.newTransformer(new StreamSource("foundation.xsl"));
        
        // 변환을 수행하고 결과 출력
        transformer.transform(new StreamSource("asimov.xml"),
                              new StreamResult("results.xml"));
        

    SourceLocator

    • SourceLocator 인터페이스는 동작이 발생한 위치에 대한 정보를 제공한다.
    • DOMLocator 인터페이스는 처리중인 DOM 노드를 반환하는 getOriginatingNode()라는 메소드가 추가되어 있다.

    OutputKeys

    • javax.xml.transform.OutputKeys 클래스는 TrAX의 변환을 위한 출력 Property를 위해 몇몇 상수를 정의하고 있다.

    Templates

    • 여러번 재활용되고 다중 쓰레드에서 사용할 Transformer를 생성한다.
    • Templates 인터페이스는 출력 Property의 집합을 여러 개의 변환작업에 똑같이 적용하고 싶거나, 변환 지시어들의 집합을 연속적으로 사용하고 싶을 때 사용한다.
      TransformerFactory factory = TransformerFactory.newInstance();
      
      // Templates 객체를 얻는다.
      Template template =
          factory.newTemplates(new StreamSource("html.xsl"));
      
      // Transformer의 인스턴스를 얻는다.
      Transformer transformer = template.newTransformer();
      
      // 변환
      transformer.transform(new DOMSource(orderForm), new StreamResult(res.getOutputStream()));
      
    • 하나의 스타일시트를 두 번이상 사용하면 Templates 객체를 사용하는 것이 좋다.
    • XSL 스타일시트를 자바 객체로 변환하는 과정을 반복하지 않으므로 더 성능이 좋다.
    • 다중 쓰레드 환경에서는 Templates 꼭 사용해야 한다.

    JAXP 설정

    $JRE_HOME/lib/ext 디렉토리에 jaxp.properties 파일을 만들고 원하는 팩토리를 설정해 둘 수 있다.
    반응형
    출처: http://kr.blog.yahoo.com/kwon37xi/folder/3381246.html


    TEXT 클래스

    • org.jdom.Text
    • Element 클래스는 getText() 메소드로 텍스트를 얻을 수 있지만, 내부적으로는 Text 클래스의 인스턴스를 만들어서 요소의 텍스트를 저장한다.
    • 이렇게 한 이유는 트리모델에서 탐색을 용이하게 하기 위해서이다.

    EntityRef 클래스

    • org.jdom.EntityRef
    • XML 엔티티 참조를 나타낸다.
    • 만약 엔티티가 XML DTD나 스키마를 참조한다면, 이 클래스로 이름, 공개ID, 시스템ID를 설정하거나 반환할 수 있다.
    • JDOM 컨텐트 트리의 어디에나 위치할 수 있다.
    • 거의 사용되지 않는다.
    • EntityRef를 사용하기 위해서는 엔티티 확장을 하지 않게 해야한다.

      SAXBuilder builder = new SAXBuilder();
      
      // 엔티티 참조를 확장하지 않는다.(기본값은 true)
      builder.setExpandEntities(false);
      
      // EntityRef 객체를 포함하는 트리 생성
      Document doc = builder.build(inputStream);
      
    • 엔티티 확장을 true로 하면 엔티티를 만날 때는 실제 엔티티의 값으로 바뀐 것을 읽게 된다.
    • 엔티티 참조 생성

      EntityRef ref = new EntityRef("TrueNorthGuitarsTagline");
      ref.setSystemID("tngTagline.xml");
      
      // 트리에 넣는다.
      tagLineElement.addContent(ref);
      

    Namespace 클래스

    • org.jdom.Namespace
    • 요소를 생성하거나 요소를 검색하는데 새로운 네임스페이스가 필요하다면, Namespace 클래스의 정적 메소드인 getNamespace()를 사용해야 한다.

      // 접두어가 있는 네임스페이스를 생성한다.
      Namespace schemaNamespace =
          Namespace.getNamespace("xsd", "http://www.w3.org/XMLSchema/2001");
      
      // 접두어가 없는 네임스페이스를 생성한다.
      Namespace javaxml2Namespace =
          Namespace.getNamespace("http://www.oreilly.com/javaxml2");
      
    • 네임스페이스 적용

      // 네임스페이스가 있는 요소 생성
      Element schema = new Element("schema", schemaNamespace);
      
      // 특정한 네임스페이스에 속한 자식 요소들을 찾는다.
      List chapterElements = contentElement.getChildren("chapter", javaxml2Namespace);
      
      // 요소에 새로운 네임스페이스를 선언한다.
      catalogElement.addNamespaceDeclaration(
          Namespace.getNamespace("tng", "http://www.truenorthguitars.com");
      
    • 접두어와 상관없이 Namespace의 URI가 동일하면 Namespace객체는 동일하다. - 이것은 표준 규약을 따르는 것이다.

    JDOM Factory

    • org.jdom.JDOMFactory 인터페이스는 JDOM에 있는 모든 타입의 객체를 생성하기 위한 여러 메소드를 정의하고 있다.
    • 보통 JDOM은 org.jdom.DefaultJDOMFactory 클래스를 사용해서 JDOM 트리를 구성한다. DefaultJDOMFactory 클래스를 상속하여 자신만의 팩토리 클래스를 작성할 수 있다.

      class CustomJDOMFactory extends org.jdom.DeafultJDOMFactory {
          ....
      }
      
    • 사용자 정의 Factory 사용해서 JDOM 트리 구성하기 : setFactory(factory)

      SAXBuilder builder = new SAXBuilder();
      
      JDOMFactory factory = new CustomJDOMFactory();
      
      // 사용자 정의 팩토리를 사용하도록 설정
      builder.setFactory(factory);
      
    • JDOMFactory를 사용할 때는 필요한 메소드가 정확히 구현되었는지 확실히 확인해야 한다.
    반응형
    출처: http://kr.blog.yahoo.com/kwon37xi/folder/3381246.html

    JDOM은 XML 문서를 트리 구조로 구성한다는 점에서 DOM과 유사하다. 그러나 JDOM은 오직 Java만 지원한다.
    JDOM은 DOM이 아니며 내부적으로 DOM을 확장하지도 않았다.

    기본적으로 알아야 할 것

    JDOM에는 DOM의 Node와 같은 트리 구조를 위한 상위 인터페이스가 존재하지 않는다. 요소(Element)와 속성(Attribute) 등 모든 것이 콘크리트 클래스(concrete class; 일반적인 인터페이스와 abstract 클래스를 제외한 클래스를 뜻한다. 또한 직접적으로 객체를 생성할 수 있는 클래스를 콘크리트 클래스라고 한다)로 이루어져 있다.

    • Element 클래스에 getText()가 있어 요소의 컨텐트를 구할 수 있다.
    • NodeListNamedNodeMap 같은 리스트 클래스가 없이 Java 컬렉션 API(java.util.List 등)을 사용한다.
    • Element.getAttributes() 로 속성의 List를 얻을 수 있다.

    JDOM Document 생성하기

    XML 원시 데이타가 없는 상태에서 JDOM Document 객체를 생성하려면 우선 JDOM의 Element 클래스를 사용해 XML 문서의 루트 요소를 생성하고, Element 클래스를 Document 클래스 생성자에 인자로 전달하여 Document 인스턴스를 생성하면 된다.
    Element rootElement = new Element("root"); // "root"는 Root 요소
    Document document = new Document(rootElement); // 새로운 Document 생성
    

    입력과 출력

    JDOM은 파서가 아니다. JDOM은 XML 원본을 읽기 위해 다른 파서에 의존한다. 또한 JDOM은 SAX 이벤트, DOM 트리, JDBC의 ResultSet 등을 입력 받는다.
    • 입력 스트림, 파일, 디스크상의 문서를 사용하거나 또는 기존의 XML을 DOM 트리로 생성할 필요가 없는 경우에는 SAXBuilder를 사용하는 것이 좋다.

      SAXBuilder builder = new SAXBuilder();
      Document doc = builder.build(new FileInputStream("contents.xml"));
      
    • DOM 빌더는 이미 DOM 트리 구조로 되어 있는 것을 JDOM 으로 바꿀 때만 사용한다. 성능이 SAXBuilder에 비해 떨어지므로 DOM 트리가 아닌 스트림에서 XML 데이터를 읽어 파싱할 때는 SAXBuilder를 사용한다.

      DOMBuilder builder = new DOMBuilder();
      
      // myDomDocumentObject는 DOM의 Document 객체이다.
      Document doc = builder.build(myDomDocumentObject);
      
      위는 org.w3c.dom.Documentorg.jdom.Document로 전환한다.
    • JDOM의 구조를 DOM 트리로 바꾸려면 DOMOutputter 클래스를 사용한다.

      DOMOutputter outputter = new DOMOutputter();
      org.w3c.dom.Document domDoc = outputter.output(myJDOMDocumentObject);
      
    • JDOM의 구조를 이용해 SAX 이벤트를 처리하려면

      SAXOutputter outputter = new SAXOutputter();
      outputter.setContentHandler(myContentHandler);
      outputter.setErrorHandler(myErrorHandler);
      outputter.output(myJDOMDocumentObject);
      
      SAXOutputter는 XML 문서가 아닌 JDOM Document를 분석하여 SAX 이벤트를 발생시키는 SAXReader라고 생각하면 된다.
    • XMLOutputter는 XML 문서를 Stream이나 Writer, 파일 또는 변환하려는 다른 구조 등으로 출력한다.

      XMLOutputter outputter = new XMLOutputter(org.jdom.output.Format.getPrettyFormat());
      outputter.output(jdomDocumentObject, new FileOutputStream("result.xml"));
      
      org.jdom.output.Format 객체를 이용해 출력 형식을 결성할 수 있으며 Format.getPrettyFormat()은 잘 정렬된 기본적인 XML 출력 형식을 지정한다.
    • XMLOutputter는 책에서 설명한 JDOM 버전과 현재 1.0 버전의 사용법이 다르다. 여기서 설명한 것은 1.0 기준이다.

    요소, 속성 등을 추가하기

    • Element의 내용은 Element.setText(String)으로 추가한다.

      // <ClassName>org.jdom.Element</ClassName>
      Element element = new Element("ClassName");
      element.setText("org.jdom.Element");
      
    • Element나 그 외의 JDOM에 적합한 모든 구성 요소는 요소의 addContent() 메소드에 의해 추가될 수 있다. 추가 될 수 있는 타입으로는 Element, Attribute, Entity, Comment, ProcessingInstruction 등이 있다.

    자식 노드 얻기

    • Element.getChild("요소이름")로 요소에서 "요소이름"의 자식 요소 첫번째를 얻을 수 있다. 자식 요소가 없으면 null을 리턴한다.
    • Element.getChildren()은 현재 요소의 자식 요소 List를 리턴한다.
    • Element.getChildren("요소이름")은 현재 요소의 "요소이름"이라는 자식 요소 List를 리턴한다.
    • Element.getTextTrim()은 요소의 텍스트에서 앞뒤 공백을 제거하고 리턴한다.
    • Element.getTextNormalize()은 요소의 텍스트에서 앞뒤 공백을 제거하고 중간에 나온 공백은 공백이 여러개라도 한개로 만들어 리턴한다.

    속성

    • 속성 값 설정 첫번째 방식

      Attribute attribute =
        new Attribute("value", propertyValue); // 속성이름 value, 속성값 propertyValue
      element.setAttribute(attribute);
      
    • 속성 값 설정 두번째 방식

      element.setAttribute("value", propertyValue);
      
    • 속성 값 가져오기

      String text = element.getAttribut    eVal     ue("value"); // 속성 value의 값 가져오기
      
    • 속성 리스트 가져오기

      List attrs = element.getAttributes(); // 요소에 속한 속성(Attribute 객체)의 List
      

    getContent()

    Document나 Element 클래스에서 getContent()를 사용하면 컨텐트의 타입(요소, 처리지시어, 주석, 엔티티, 텍스트 등)과 상관없이 해당하는 모든 컨텐트를 리턴한다.
    • 주석을 XML문서의 맨 앞에 추가하려면 다음과 같이 해야한다. 그냥 doc.addContent(comment)를 하면 XML 문서의 맨 마지막에 주석이 추가되어 버린다.

      // doc 은 JDOM의 Document 객체이다.
      Comment comment = new Comment("이러쿵 저러쿵..");
      doc.getContent().add(0, comment);
      

    XPath

    XPath xpath = XPath.newInstance("/collection/dvd"); // XPath 문자열
    List list = xpath.selectNodes(doc); // Document 객체
    

    얻어진 list의 각 요소들을 Element, Attribute, String 등으로 캐스팅하여 사용하면 된다.

    Element e = (Element)xpath.selectSingleNode(doc); 이처럼 XPath.selectSingleNode()를 사용하면 XPath결과 중에서 한 개의 값만을 가져올 수 있다.

    XSLT

    • JDOM의 XSLTranformer는 파라미터를 받지 않는 문제가 있다. 이때 JAXP를 사용해야 한다.
    • 트랜스폼 결과는 Document로 리턴된다.

      StringWriter writer = new StringWriter();
      
      XSLTransformer transformer = new XSLTransformer("list.xsl");
      Document resultDoc= transformer.transform(doc); // Document 객체
      
      XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
      out.output(resultDoc, stringWriter); // 문자열 Writer에 결과를 저장.
      
      out.println(stringWriter.toString()); // 문자열로 출력
      

    반응형
    출처: http://kr.blog.yahoo.com/kwon37xi/folder/3381246.html

    • DOM은 XML을 생성하고 변경할 수 있다.

    XML DOM 트리의 생성과 변경

    • 새로운 XML을 생성하기 위해서는 org.w3c.dom.DOMImplementation을 구현한 클래스를 사용해야한다.
    • Xerces의 DOMImplementation구현 : org.apache.xerces.dom.DOMImplementationImpl
    • 생성 예

      DOMImplementation domImpl = new DOMImplementationImpl();
      Document doc = domImpl.createDocument(null, "rootElement", null);
      
    • Document 객체 생성시 파서의 Document 구현 클래스를 사용하면 DocType 이 생성되지 않는다. DOMImplementation 을 사용해서 새로운 XML DOM 트리를 생성해야 한다.
    • DOMImplementation.createDocument(1,2,3);
      • 첫번째 인자 : 문서의 루트 요소를 위한 네임스페이스
      • 두번째 인자 : 루토 요소
      • 세번째 인자 : DocType 클래스의 인스턴스.
    • DocType이 필요할 경우 DOMImplementation.createDocType() 사용.
    • 변경 예

      Element root = doc.getDocumentEelment();
      root.setAttribute("id", id); // id 속성의 추가
      
      Element nameElement = doc.createElement("name");
      Text nameText = doc.createTextNode("내용");
      nameElement.appendChild(nameText); //name 요소에 텍스트 값 추가
      root.appendChild(nameElement); // rootElement 요소에 name 요소 추가
      
    • 모든 노드의 생성은 Document 객체의 create* 메소드를 통해서 이뤄진다.
    • "appendChild()"는 자식 노드를 추가한다.

    네임스페이스

    • DOM Level 2는 네임스페이스를 지원한다.
    • 네임스페이스를 위해 Node 인터페이스는 "getPrefix()"와 "getNamespaceURI()" 메소드를 제공한다.
    • Document.createElementNS() 네임스페이스를 지원하는 요소 추가.
    • 네임스페이스를 인식하는 각 메소드의 첫번째 인자는 "네임스페이스 URI"이고, 두번째 인자는 요소와 속성등의 QName이다. QName은 "ora:copyright" 와 같은 형태를 띈다.
    • "ora:copyright" 요소에서 getPrefix() : "ora" 리턴
    • 네임스페이스에 속하지 않는 요소에서 getPrefix() : null 리턴
    • 네임스페이스를 지정했을 때는 루트 요소에 xmlns 속성을 지정해야 한다.

    DOM Level 2 - 순회(Traverse)

    • DOM 트리를 순회하는 기능을 제공한다.
    • "org.w3c.dom.traversal.DocumentTraversal" 인터페이스를 이용한다.
    • 일반적인 파서의 Document 구현 클래스는 DocumentTraversal 도 함께 구현한다.
    • NodeIterator

      NodeList descriptionElements =
      	root.getElementsByTagNameNS(docNS, "description");
      Element description = (Element)descriptionElements.item(0);
      
      // NodeIterator를 구한다.
      NodeIterator i = ((DocumentTraversal)doc)
      	.createNodeIterator(description, NodeFilter.SHOW_ALL,
      	new FormattingNodeFilter(), true);
      
      Node n;
      
      while ((n = i.nextNode()) != null) {
      	System.out.println("Search phrase found: '" + n.getNod eVal  ue() + "'");
      }
      
    • createNodeIterator(1, 2, 3, 4)
      • 첫번째 인자 : 순회할 노드 요소
      • 두번째 인자 : 상수 필터
        1. NodeFilter.SHOW_ALL : 모든 노드를 포함하여 순회
        2. NodeFilter.SHOW_ELEMENT : 요소만 순회
        3. NodeFilter.SHOW_TEXT : 텍스트 노드만 순회
      • 세번째 인자 : NodeFilter 구현 객체
      • 네번째 인자 : 엔티티 참조의 실제값을 분석할 것인가?
      • 두번째와 세번째 인자가 함께 나올 경우 두번째 인자 필터를 우선적용하고 그 결과를 다시 세번째 인자로 필터링한다.
    • NodeFilter
      • public short acceptNode(Node n); 을 이용해서 순회할 노드인지 여부를 결정한다.
        • 리턴값 NodeFilter.FILTER_SKIP : 필터로 들어온 노드는 건너 뛰고 그 자식노드를 계속 탐색
        • 리턴값 NodeFilter.FILTER_REJECT : 필터로 들어온 노드와 그 자식 모두 건너 뜀
        • 리턴값 NodeFilter.FILTER_ACCEPT : 필터로 들어온 노드 사용
      • 노드 필터 예

        class FormattingNodeFilter implements NodeFilter {
        	public short acceptNode(Node n) {
        		if (n.getNodeType() == Node.TEXT_NODE) {
        			Node parent = n.getParentNode();
        
        			if ((parent.getNodeName().equalsIgnoreCase("b")) ||
        				(parent.getNodeName().equalsIgnoreCase("i"))) {
        				return FILTER_ACCEPT;
        			}
        		}
        
        		return FILTER_SKIP;
        	}
        }
        
    • TreeWalker
      트리 뷰를 얻는다. 필터를 이용해 특정한 요소 등만 가진 트리를 생성해낸다.

    범위(Range)

    알 수 없는 DOM 구조에 새로운 컨텐트를 추가하거나 또는 컨텐트를 삭제, 복사, 추출해야 할 경우에 범위 모듈을 사용한다.

    Wrong document Exception

    잘못된 문서 예외(Wrong document Exception)은 서로 다른 문서의 노드들을 함께 사용하려 할 때 발생한다.

    다른 문서의 노드를 현재 문서에 append하려면 importNode를 사용한다.
    Element otherDocElement = otherDoc.getDocumentElement();
    Element thisDocElement = thisDoc.getDocumentElement();
    
    // 대상 문서에 노드 임포트
    Element readyToUseElement =
        (Element)thisDoc.importNode(otherDocElement);
    
    // 아무문제없이 노드 추가
    thisDocElement.appendChild(readyToUseElement);
    



    반응형
    출처: http://kr.blog.yahoo.com/kwon37xi/folder/3381246.html
    DOM(Document Object Model)은 모든 프로그래밍 언어와 개발 도구에서 사용하는 문서의 컨텐트 모델을 표현하기 위해 설계되었다. 각 언어별로 바인딩이 존재한다.
    이 점은 장점이 될 수도 있지만, JAVA 고유의 편리한 기능을 사용할 수 없어, 단점으로 작용하기도 한다. JAVA 고유의 기능을 사용한 JDOM이 DOM보다 훨씬 편리하다.
    • DOM은 모든 면에서 트리 모델이다.
    • DOM은 XML문서 전체를 메모리에 저장하여 표현한다.
    • 각 트리는 org.w3c.dom.Node 인턴페이스를 기반으로 한다. 요소, 속성, 텍스트, PI, 주석 등 모든 것이 Node로 표현된다.
    • 요소의 텍스트도 하나의 트리로 간주된다. 그러므로 Element 노드의 텍스트를 구할 때 "getText()"와 같은 방식으로 구할 수 없고, 요소의 Text 자식 노드들을 구한뒤, 거기서 값을 가져와야한다.

    SAX의 장/단점

    • SAX는 순차적이라 XML문서의 요소를 무작위로 접근할 수 없다.
    • 형제 요소를 처리하기 어렵다.
    • 메모리를 훨씬 적게 사용한다.

    XML 파싱 : Xerces 기준

    • DOM에서는 문서를 완전히 분석하여 트리 구조가 생성되어야 XML 문서의 데이터를 사용할 수 있다.
    • DOM에서 문서를 분석한 결과는 org.dom.w3c.dom.Document 객체로 표현된다.
    • 다음과 같이 XML 문서를 파싱한다.

      import org.apache.xerces.parsers.DOMParser; // 파서 import
      import org.w3c.dom.*; // DOM 인터페에스 import
      ...
      
      DOMParser parser = new DOMParser();
      
      // Document 객체인 DOM 트리 구성
      parser.parse("document.xml");
      Document doc = parser.getDocument(); // DOM Document 객체 얻기
      

    • import org.apache.xerces.parsers.DOMParser
      • void parse(org.xml.sax.InputSource inputSource)
      • void parse(java.lang.String systemId)

    Node

    • DOM의 장점중의 하나는 XML을 표현하는(Document 객체를 포함한) 모든 DOM 객체가 DOM의 Node인터페이스를 상속한다는 점이다.
    • Node.getNodeType() : 현재 노드의 타입(요소, 속성, PI 등등..)을 가리킨다.
    • Document.getDocumentElement() : 최상위 요소(Root Element) 노드
    • Node.getNodeName() : 노드의 이름. Text 노드(요소의 값)의 경우 이 노드 이름은 의미가 없다.
    • Node.getNodeValue() : 노드의 값. Element 노드의 경우 이 값은 의미가 없으며 자식 노드를 구해 그 중 Text노드의 값을 가져와야만 한다.
    • Node.getChildNodes() : NodeList 인스턴스 반환. 자식 노드 목록.
    • NamedNodeMap Node.getAttributes() : Element 노드의 경우에만 유효. 속성 목록을 반환한다.
    • NodeList.item(int) : 자식 Node들을 순서대로 반환받는다.

    DOCTYPE, PI 등의 처리

    최상위 엘리먼트보다 상위에 오는 DOCTYPE과 PI(처리 지시어; Processing Instruction)등을 처리하려면 Document 노드 단에서 자식 노드들을 얻어야만 한다.

    NodeList 사용시 주의점!

    이것은 Java와 XML 책에는 없는 내용이다. 내 경험상의 주의점이다.
    

    다음과 같은 XML이 있을 때
    <root>
      <child1>hello</child1>
      <child2>hi~</chil2>
    </root>
    
    위 XML을 파싱하여 "root" 엘리먼트 Node 객체에서 getChildNodes()를 했을 경우에 주의할 점이 있다.
    이 상황에서 "child1" 노드 객체를 가져올 때
    DOMParser parser = new DOMParser();
    
    parser.parse("test.xml");
    
    Document doc = parser.getDocument();
    
    Element root = doc.getDocumentElement();
    
    NodeList children = root.getChildNodes(); // root 의 자식 노드 얻기 -- !! 요주의 부분!!
    
    Node child1Node = children.item(0); // child1 요소 얻기 
    
    Node textNode = child1Node.getChildNodes().item(0); // child1의 텍스트 얻기
    
    System.out.println("child1 : " + textNode.getNodeValue());
    
    위와 같이 하면 제대로 값을 가져올 수 있을까?

    답은 "가져올 수도 있고 못 가져올 수도 있으나, 십중팔구는 NullPointerException이 발생한다는 것이다."
    NullPointerException이 발생한다면 그것은 textNode가 null이기 때문이다.
    위와 같이 NodeList.item(int) 메소드를 사용할 경우에 root 요소와 child1 요소 사이의 공백이 Text 노드로서 읽힐 수도 있다. 이 경우 NodeList.item(0)가 리턴하는 노드는 child1 요소가 아니라 root요소의 Text 노드가 되는 것이다.
    만약 root 요소와 child1요소 사이에 아무런 공백도 없거나 DTD 등으로 공백을 무시하도록 했다면 안 그럴 수도 있다.

    그러므로 child1 요소를 명백하게 가져오려고 할 경우에는 root.getChildNodes()를 사용해서는 안된다. root 노드를 Element 객체로 캐스팅하고 Element.getElementsByTagName(String)으로 명백하게 가져와야 한다.
    Element root = doc.getDocumentElement();
    
    // 이 부분이 바뀌었다!!
    NodeList children = root.getElementsByTagName("child1"); // root 의 자식 노드 얻기
    
    Node child1Node = children.item(0); // child1 요소 얻기
    
    Node textNode = child1Node.getChildNodes().item(0); // child1의 텍스트 얻기
    
    System.out.println("child1 : " + textNode.getNodeValue());
    

    위와 같이 하면 children 객체에는 요소 이름이 "child1"인 요소만 남게 된다.

    반응형
    출처: http://kr.blog.yahoo.com/kwon37xi/folder/3381246.html

    Property

    파서에 추가되는 인터페이스로서 파서에 특정 인터페이스를 추가하여 분석 기능을 추가한다(수행 동작이 인터페이스를 구현한 객체에 구현되어 있다). Property는 Feature와 마찬가지로 URI를 사용하여 구별하는데, http://xml.org/sax/properites/를 접두어로 가지며 lexical-hander 같은 구분자가 뒤에 따라온다.

    • XMLReader.setProperty(String propertyID, Object value)
    • XMLReader.setFeature(String featureID, boolean value)
    • Object XMLReader.getProperty(String propertyID)
    • boolean XMLReader.getFeature(String featureID)

    Feature

    파서가 수행해야 하는 동작을 나타내기 위한 플래그로서 파서가 수행 가능한 동작의 실행 여부를 표시한다(수행하는 동작은 이미 파서에 구현되어 있다). Feature는 URI를 사용하여 구분하는데 http://xml.org/sax/features/를 접두어로 가지며 뒤에 validation과 같은 구분자가 따른다. 즉, 유효성 검사와 관련된 Feature는 http://xml.org/sax/features/validation이라는 URI로 표시된다.

    EntityResolver

    • org.xml.sax.EntityResolver
    • 엔티티를 분석하는 이벤트 핸들러

    public InputSource resolveEntity(String publicID, String systemID)

    • XMLReader가 엔티티 참조를 만날 때마다 그 엔티티에 해당하는 공개ID와 시스템ID를 resolveEntity메소드에 넘겨준다.
    • resolveEntity() 메소드에 어떤 코드를 추가하더라도, 항상 기본적으로는 null 을 반환하도록 해야 한다.

    DTDHandler

    • org.xml.sax.DTDHandler
    • DTDHandler 인터페이스는 XMLReader가 분석하지 못한 엔티티나 표기(Notation) 선언을 만나게 되면 이를 알려준다. 물론 이 두 가지 이벤트는 XML문서가 아니라 DTD에서 발생한다.
    • 유효성 검사를 하면서 동시에 이 핸들러를 사용하는 것은 피하는 것이 좋다.
    • DTDHandler를 등록했다고 해도 유효성 검사 Feature(http://xml.org/sax/features/validation)를 선언하지 않으면 유효성 검사를 하지 않는다.

    public void notationDecl(String name, String publicID, String systemID)

    표기 선언(Notation)을 만나면 호출된다.

    public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName)

    분석되지 않은 엔티티 선언을 만나면 호출된다.

    org.xml.sax.helpers.DefaultHandler 클래스

    • 여러 핸들러(ContentHandler, ErrorHandler, EntityResolver, DTDHandler)를 모두 구현했다. 구현한 메소드는 아무런 작동도 하지 않는다.
    • 이것을 상속하여 클래스를 작성하면 불필요한 메소드를 뺀 핸들러 클래스를 만들 수 있다.
    • EntityResolver는 다른 핸들러 클래스와 별도로 분리하는 것이 좋다.

    XMLFilter

    • 하나의 SAX Reader가 모든 것을 처리하도록 하는 대신 Reader가 특정 처리를 하고 다른 Reader에게 넘겨주는 작업을 반복적으로 수행하는 파이프라인.
    • org.xml.sax.helpers.XMLFilterImpl클래스를 상속하여 구현하고, 자기 부모로 XMLReader를 지정하면 된다.
    • 핸들러는 최종 필터에 등록해야 한다.
    • XMLFilterImpl 클래스는 기본적으로 5개의 인터페이스에 정의된 모든 메소드는 관련된 이벤트를 처리하지 않고 단순히 넘어가도록 구현돼 있다. XMLFilterImpl 클래스를 상속한 클래스는 필터가 처리하는 메소드만 오버라이딩하여 구현하면 된다.

    XMLWriter

    org.xml.sax.ext.LexicalHandler

    • 주석, 엔티티선언, DTD 선언 그리고 CDATA 영역과 같은 구문과 관련된 이벤트를 처리하는 메소드를 제공한다. ContentHandler는 이 구문 관련 이벤트를 기본적으로 무시한다.
    • 이것을 사용하기 위해서는 Property에 이 핸들러를 구현한 객체를 등록해야만 한다.

      reader.setProperty("http://xml.org/sax/properties/lexical-handler", lexicalHandler);
      

    public void startDTD(String name, String publicID, String systemID)

    DTD 참조 또는 선언의 시작

    public void endDTD()

    DTD 참조 또는 선언의 끝

    public void startEntity(String name)

    엔티티 참조 시작

    public void endEntity(String name)

    엔티티 참조 끝

    public void startCDATA()

    CDATA 영역 시작

    public void endCDATA()

    CDATA 영역 끝

    public void comment(char[] ch, int start, int length)

    • 주석
    • <!-- 와 --> 주석 구분자를 제외한 텍스트만을 받는다.

    org.xml.sax.ext.DeclHandler

    • DeclHandler 핸들러는 요소 선언이나 속성 선언과 같은 DTD에서 발생하는 특정 이벤트를 처리하는 메소드를 정의 하며 아주 특별한 경우에만 사용된다.
    • 이것을 사용하기 위해서는 Property로 이 핸들러를 구현한 객체를 등록해야 한다.

      reader.setProperty("http://xml.org/sax/properties/declaration-handler", declHandler);
      

    public void attributeDecl(java.lang.String eName, java.lang.String aName, java.lang.String type, java.lang.String mode, java.lang.String value)

    속성의 선언을 처리한다. <!ATTLIST>

    public void elementDecl(java.lang.String name, java.lang.String model)

    요소의 선언을 처리한다. <!ELEMENT>

    public void externalEntityDecl(java.lang.String name, java.lang.String publicId, java.lang.String systemId)

    외부 자원을 참조하는 엔티티 선언을 처리한다. <!ENTITY>

    public void internalEntityDecl(java.lang.String name, java.lang.String value)

    내부에서 선언된 엔티티 선언을 처리한다.

    반응형
    출처: http://kr.blog.yahoo.com/kwon37xi/folder/3381246.html
    Java와 XML 2판의 내용정리이다.
    책을 보지 않으면 이 내용을 이해할 수 없을 수 있다.

    SAX 파서는 XML 문서를 순차적으로 분서하는데 문서를 분석하는 동안 시작 태그나 속성, 종료 태그, 텍스트 데이터 등을 만나면 각 구성 요소를 처리하는 메소드를 호출한다.
    이때 메소드를 호출하는 구성요소를 만나는 것이 이벤트가 된다. 즉, SAX 파서가 시작태그를 만나는 것이 하나의 이벤트이고 속성을 만나는 것이 또 다른 이벤트가 된다. 그리고 각 구성요소를 처리하는 메소드를 호출하는 것은 이벤트를 처리한다라고 표현하며, 호출되는 메소드를 콜백(callback) 메소드라고 부른다.

    SAX Parser

    http://xml.apache.org 에서 Xerces 파서를 구할 수 있다.

    SAX 클래스는 org.xml.sax 구조로 패키징되어 있다. 최소한 org.xml.sax.XMLReader 클래스가 있어야 한다.

    SAX 공식 홈 : http://wwww.saxproject.org

    SAXReader

    SAX 사용의 시작은 org.xml.sax.XMLReader 의 객체를 얻는 것이다.
    // 파서 클래스 지정. 여기서는 아파치 Xerces
    private String parserClass="org.apache.xerces.parsers.SAXParser";
    
    // 파싱에 사용할 XMLReader 객체 생성
    XMLReader reader = XMLReaderFactory.createXMLReader(parserClass);
    

    • XMLReader 의 객체는 재사용이 가능하지만 한 번에 한개의 XML 파일만을 파싱해야한다.

    XML 문서 파싱

    XMLReader 객체의 parse(InputSource) 혹은 parse(String URI)로 파싱한다. InputSource 사용권장.

    InputSource is = new InputSource(new FileInputStream(new File(xmlURI)));
    
    // 필수적으로 SystemID를 설정해야 한다.
    // SystemID는 XML 문서의 URI이다.(파일의 경우 파일의 경로)
    is.setSystemId(xmlURI);
    
    // 파싱
    reader.parse(inputSource);
    
    • 항상 시스템 ID를 설정해야만 한다!!
    • SystemID는 XML문서의 URI이다. 파일의 경우는 파일의 경로를 의미한다.

    Handler 등록

    핸들러는 SAX 파서가 문서를 순차적으로 분석하는 동안 발생한 이벤트에 대해 호출할 메소드를을 가진 클래스 객체이다.

    • XMLReader.setContentHandler()
    • XMLReader.setErrorHandler()
    • XMLReader.setDTDHandler()
    • XMLReader.setEntityHandler()


    • 모든 핸들러는 throws SAXException 을 해야 한다.

    Content Handler

    • 요소 등 XML의 내용을 만났을때 호출되는 콜백 메소드를 가지는 클래스.
    • ContentHandler 인터페이스 구현

    public void setDocumentLocator(Locator locator)

    • 분석중인 문서의 위치 정보를 가진 Locator의 객체 생성. Locator 객체의 getLineNumber(), getColumnNumber() 메소드들로 이벤트가 발생한 위치를 알아낼 수 있다.
    • 이벤트의 위치는 실제 처리중인 분석과정에만 유효. Locator는 ContentHandler를 구현한 클래스 범위 내에서만 사용되어야 한다! Locator를 ContentHandler 의 인스턴스 멤버로 등록한다.

    public void startDocument() throws SAXException

    • 문서 시작시 호출되는 콜백 메소드.
    • 모든 핸들러를 포함하여 가장 처음에 호출.(setDocumentLocator() 제외)

    public void endDocument() throws SAXException

    • 문서 분석이 끝날 때 호출되는 콜백 메소드
    • 모든 핸들러를 포함하여 가장 나중에 호출.

    public void processingInstruction(String target, String data)

    • 처리지시어(<? --- ?>)를 처리한다.
    • XML 데이터를 사용하는 실제 애플리케이션은 이 메소드로 처리 지시어를 받아 변수 값을 설정하거나 특정한 처리 과정을 수행하는 메소드를 실행한다.
    • <?xml version="1.0"?> 이 부분은 전달되지 않는다.

    네임스페이스 매핑

    • 네임스페이스를 선언하는 xmlns 를 만나면 발생
    • public void startPrefixMapping(String prefix, String uri)
    • public void endPrefixMapping(String prefix)
    • 프로그래밍 패턴

      private Map namespaceMappings = new HashMap();
      
      public void startPrefixMapping(String prefix, String uri) {
      	// 시각적인 이벤트는 발생하지 않는다.
      	namespaceMappings.put(uri, prefix);
      }
      
      public void endPrefixMapping(String prefix) {
      	// 시각적인 이벤트는 발생하지 않는다.
      	for (Iterator i = namespaceMappings.keySet().iterator(); i.hasNext(); ) {
      		String uri = (String)i.next();
      		String thisPrefix = (String)namespaceMappings.get(uri);
      		if (prefix.equals(thisPrefix)) {
      			namespaceMappings.remove(uri);
      			break;
      		}
      	}
      }
      

    public void startElement(String namespaceURI, String localName, String qName, Attributes atts)

    • 요소가 시작될 때 호출
    • qName 은 네임스페이스 접두어가 있다면 그것을 이름에 포함한다.
    • atts 는 요소의 속성들을 배열로 가지고 있다.

    public void endElement(String namespaceURI, String localName, String qName, Attributes atts)

    • 요소가 닫힐 때 호출

    public void characters(char[] ch, int start, int length)

    • 요소의 텍스트 데이터
    • ch 배열의 start 인덱스부터 length 길이 만큼 만이 데이터이다!!

    public void ignorableWhitespace(char[] ch, int start, int length)

    • 무시 가능한 공백문자가 올 경우 호출
    • DTD나 스키마가 없으면 호출되지 않는다. DTD나 스키마에서 무시가능한 공백문자를 지정하기 때문이다.

    public void skippedEntity(String name)

    • 파서가 엔티티를 처리하지 않을 때 호출
    • 실제 이 메소드가 호출되는 경우는 거의 없다.(Xerces는 절대 호출하지 않는다.)
    • 이 콜백을 수행하면 엔티티 참조의 앞의 앰퍼샌드와 뒤의 세미콜론을 포함하지 않는 엔티티 참조를 매개변수로 전달한다.

    ErrorHandler

    • 파싱중 오류가 발생하면 호출되는 핸들러
    • ErrorHandler 인터페이스 구현

    public void warning(SAXParseException ex)

    • 경고

    public void error(SAXParseException ex)

    • 치명적이지 않은 오류

    public void fatalError(SAXParseException ex)

    • 치명적 오류
    • 파싱을 중지하는게 낫다.

    + Recent posts