java - JDOM

Development/Java 2012. 10. 2. 11:39


JDOM으로 XML 프로그래밍 단순화 하기 (한글)


요약:  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으로서 언제나 사용할 수 있다. List Iterator 같은 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);

Element addContent 메소드가 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 엘리먼트에 대한 레퍼런스를 획득하려면, Element getChild 메소드를 사용한다.


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는 포맷팅 옵션을 갖고 있다. 여기에서, 우리는 부모 엘리먼트에서 두 스페이스를 들여쓰기 한 자식 엘리먼트를 원한다고 지정했고, 엘리먼트들 사이에 새로운 라인을 원한다는 것을 지정했다. XMLOutputter Writer 또는 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 세계에 적용될 수 있다.


참고자료

필자소개

Wes Biggs는 Los Angeles Times, USWeb, Elite Information Systems 등 여러 기업들에서 인터넷 애플리케이션을 개발했다. 오픈 소스 자바 프로젝트의 기여자이며, Free Software Foundation의 gnu.regexp 정규식 패키지를 관리하고 있다. (wes@tralfamadore.com)

Harry Evans는 소프트웨어 디자인과 애플리케이션 엔지니어링 분야에서 경력을 쌓았다. 여러 웹 기반 및 인터넷 인식 제품들의 디자인 분야에서 일했다. Rapid Application Development부터 레거시 제품 통합까지 경력을 쌓았다. (harry@tralfamadore.com)


출처 - http://www.ibm.com/developerworks/kr/library/j-jdom/


===================================================================================


Java와 XML 7장 JDOM

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

기본적으로 알아야 할 것

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

 

  • Element 클래스에 getText()가 있어 요소의 컨텐트를 구할 수 있다.
  • NodeList나 NamedNodeMap 같은 리스트 클래스가 없이 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.Document를 org.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.getAttributeValue("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://kwon37xi.springnote.com/pages/1231824.xhtml


===================================================================================


JDOM 이라는 API 를 통해 간단히 XML 을 만들 수 있다.


아래 코드를 보면 바로 이해가 될 것으로 보인다.


(String 으로 출력 하는 방식과  file  로 만드는 방식을 모두 정리 하였다.)


import java.io.FileOutputStream;

import java.io.IOException;

import org.jdom.Document;

import org.jdom.Element;

import org.jdom.output.Format;

import org.jdom.output.XMLOutputter;


public class XmlGene {

 /**

  * @param args

  */

 public static void main(String[] args) {

  // TODO Auto-generated method stub

  Document doc = new Document();  

  

  Element root = new Element("generator");

  

  Element pack = new Element("package");

  

  Element pack_name = new Element("package-name");

  

  root.addContent(pack);//root element 의 하위 element 를 만들기

  pack.addContent(pack_name); //package element 의 하위로 package-name 만들기

  

  pack_name.setText("com.ysci.theme.aaa");

  //package-name element 에 value 값을 text 로 넣어 주기

  

  doc.setRootElement(root);

  

  try {                                                             

      FileOutputStream out = new FileOutputStream("d:\\test.xml"); 

      //xml 파일을 떨구기 위한 경로와 파일 이름 지정해 주기

      XMLOutputter serializer = new XMLOutputter();                 

                                                                    

      Format f = serializer.getFormat();                            

      f.setEncoding("UTF-8");

      //encoding 타입을 UTF-8 로 설정

      f.setIndent(" ");                                             

      f.setLineSeparator("\r\n");                                   

      f.setTextMode(Format.TextMode.TRIM);                          

      serializer.setFormat(f);                                      

                                                                    

      serializer.output(doc, out);  // 파일 출력

      // serializer.output(doc, System.out)  // 화면 출력                                 

      out.flush();                                                  

      out.close();    

      

      //String 으로 xml 출력

     // XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat().setEncoding("UTF-8")) ;

     // System.out.println(outputter.outputString(doc));

  } catch (IOException e) {                                         

      System.err.println(e);                                        

  }                                                                 

 }

}


===============================================================================

결과는 


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

<generator>

  <package>

    <package-name>com.ysci.theme.aaa</package-name>

  </package>

</generator>


와 같이 나온다.


출처 - http://shonm.tistory.com/entry/JAVA-XML-%EB%A7%8C%EB%93%A4%EA%B8%B0


===================================================================================


JDOM 을 이용하여 XML 문서를 출력해 보자.

* Xml.java

/**
 * @class Xml
 * @brief Xml Classes
 *
 * registered date 20100105
 * programmed by Seok Kyun. Choi. 최석균
 * http://syaku.tistory.com
 */

package org.syaku.util;

import java.util.*;

import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;


public class Xml {

  // 해쉬맵을 이용하여 문서 생성
  public Document make(HashMap hm) throws Exception {
    
    Element data = new Element("data");

    Element element = new Element("item");
    Set set = hm.keySet();
    Object []items = set.toArray();
    for(int i = 0; i < items.length; i++) {
      String name = (String) items[i]; 
      String value = (String) hm.get(name);

      addElement(element,name,value);
    }

    data.addContent(element);

    Document document = new Document(data);

    return document;
  }

  // 엘리먼트 생성
  public Element addElement(Element parent, String name, String value) {
    Element element = new Element(name);
    element.setText(value);
    parent.addContent(element);
    return parent;
  }

  // 애트리뷰트 생성
  public void addAttribute(Element element, String name, String value){
    Attribute attribute = new Attribute(name,value);
    element.setAttribute(attribute);
  }


}

* Xml 출력

<%@ page contentType="text/html; charset=euc-kr"%>
<%@ page import="java.util.*" %>
<%@ page import="org.syaku.util.*" %>
<%@ page import="org.jdom.*" %>
<%@ page import="org.jdom.output.*" %>

<%
HashMap hm = new HashMap();
hm.put("샤쿠","Syaku");
hm.put("Site","syaku.tistory.com");
hm.put("블로그","Blog");

Xml xml = new Xml();
Document document = (Document) xml.make(hm);

XMLOutputter outputter = new XMLOutputter();
Format format = Format.getPrettyFormat();
format.setEncoding("EUC-KR");
outputter.setFormat(format);

response.setContentType("application/xml");
outputter.output(document, response.getWriter());
// 시스템출력
// outputter.output(document, System.out);
%>

* 결과


출처 - http://syaku.tistory.com/147


===================================================================================


xml 문서가 있을때 불러오기

 

package ex1;

import org.jdom.Document;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

 

public class JDOMEx2 {
    public static void main(String[] args) throws Exception{
       
        //이미 존재하는 XML문서를 메모리상에 올리려면...
        SAXBuilder sb = new SAXBuilder();
       
        Document doc = sb.build("c:/Java_Study/0509/web/ex1/fax.xml");
       
        //메모리상에 있는 Document 객체를 화면에 또는 파일에 출력하려면
        //우선 org.jdom.output.XMLOutputter객체가 필요하다.
       
        XMLOutputter xo = new XMLOutputter();
       
        //XMLOutputter 라는 것은 XML형식으로 출력을 할 수 있도록 정의된
        //클래스이다. 화면에 출력을 하거나 파일에 출력을 하고자 할때 유익하다.
        //XMOutputter 객체에는 일반적으로 [출력형식]을 가지고 있다.
        //우린 그것을 org.jdom.output.Format 객체라고 한다.

       
        Format format = xo.getFormat();
        format.setEncoding("euc-kr"); //인코딩 지정
        format.setLineSeparator("\r\n"); //줄바꿈
        format.setIndent("   "); //들여쓰기
        format.setTextMode(Format.TextMode.TRIM); //Enter값 무시...
       
        xo.setFormat(format); //포멧설정
        xo.output(doc, System.out); //화면출력     
    }
}

 

 

 

 

존재하지 않는 xml문서를 생성

 

package ex1;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

 

public class JDOMEx3 {
    public static void main(String[] args) {
        //존재하지 않는 xml문서를 생성하는 예제!
        Element root = new Element("Total");
        Element computer = new Element("Computer");
        Element cpu = new Element("CPU");
        Element ram = new Element("RAM");
        Element hdd = new Element("HDD"); 
       
        //문자열
        cpu.setText("Core2 2G");
        ram.setText("2G");
        hdd.setText("300G");
       
        //배치작업
        computer.addContent(cpu);
        computer.addContent(ram);
        computer.addContent(hdd);
        computer.setAttribute("model","CT-7000");
       
        root.addContent(computer);
       
        Document doc = new Document(root); //문서 객체 생성
       
        //XMLOutputter를 통하여 화면에 출력!
        XMLOutputter xo = new XMLOutputter();
        try {
            Format fo = xo.getFormat(); //출력형식 얻기
            fo.setEncoding("euc-kr");
            fo.setLineSeparator("\r\n"); //줄바꿈
            fo.setIndent("   "); //들여쓰기
            fo.setTextMode(Format.TextMode.TRIM); //Enter값 무시...
            xo.setFormat(fo); //출력형식 재 설정
           
            //xo.output(doc, System.out); //화면에 출력
            xo.output(doc, new FileOutputStream("C:/text.xml")); //파일에 출력
        } catch (IOException ex) {
            ex.printStackTrace();
        }               
    }
}

 

 

 

생성된 파일의 root 엘리먼트에 Computer라는 엘리먼트 하나더 추가하는 예제.

 

 

 

package ex1;

import java.io.FileOutputStream;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

 

public class JDOMEx4 {
    public static void main(String[] args) throws Exception{
        //앞서 수행한 예제에 test.xml이라는 파일이 생성되었다.
        //생성된 파일의 root 엘리먼트에 Computer라는 엘리먼트 하나더 추가하는 예제.
        SAXBuilder sb = new SAXBuilder();
        Document doc = sb.build("C:/text.xml");
        Element root = doc.getRootElement();
       
        //추가하고자 하는  엘리먼트 작업
        Element com = new Element("Computer");
        com.setAttribute("model","T-1000");
        //com 엘리먼트의 하위 엘리먼트들 생성
        Element cpu = new Element("CPU");
        Element ram = new Element("RAM");
        Element hdd = new Element("HDD");
       
        //하위 엘리먼트들의 Text값 설정
        cpu.setText("Quad 2G");
        ram.setText("4G");
        hdd.setText("360GB");
       
        //배치작업
        com.addContent(cpu);
        com.addContent(ram);
        com.addContent(hdd);
       
        root.addContent(com);

        //root.addContent(2,com); 2번째 요소로 com 추가
        
        //파일에 저장 작업
        XMLOutputter xo = new XMLOutputter();
        Format fo = xo.getFormat();
        fo.setEncoding("euc-kr");
        fo.setIndent("   ");
        fo.setLineSeparator("\r\n");
        //Enter키의 Text값인(\r\n)에 의해 자동 줄 바꿈을 해제
        fo.setTextMode(Format.TextMode.TRIM);
        xo.setFormat(fo); //출력형식 재설정!!
       
        //메모리상에만 존재하고 있는 Document객체의 내용을
        //XML형식으로 파일에 저장한다.
        xo.output(doc, new FileOutputStream("C:/text.xml"));
    }
}

 

 

XML문서에 XSL문서를 겸한 변환을 하는 예제

 

 

package ex2;

import java.io.FileOutputStream;
import org.jdom.Document;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.transform.XSLTransformer;

 

public class JDOM_Trans {
    public static void main(String[] args) throws Exception{
        //XML문서에 XSL문서를 겸한 변환을 하는 예제
       
        //우선 변환을 위해 필요한 XSL문서를 가지고
        //변환 객체인 XSLTransformer를 생성한다.
       
        XSLTransformer xslt = new XSLTransformer("C:/Java_Study/0509/web/ex2/handphone.xsl");
       
        //변환하고자 하는 XML문서의 Document객체가 필요하다.
        SAXBuilder sb = new SAXBuilder();
        Document doc = sb.build("C:/Java_Study/0509/web/ex2/handphone.xml");
       
        //위에서 받은 doc를 xslt가 알고 있는 xsl문서와 함께 새로운 Document를 생성.-"변환작업"
        Document htmldoc = xslt.transform(doc);
       
        //위의 작업까지는 변환 작업이 완료된 경우다.

           즉 htmldoc가 xsl형식에 맞게 생성된 html문서 객체이다.
        //이것은 물리적으로 존재하는 것이 아니라 그저 메모리상에만 존재하는 형태이다.
        //그럼 실제 물리적으로 파일이 생성되려면 XMLOutputter객체가 필요하다.
        XMLOutputter xo = new XMLOutputter();
        Format fo = xo.getFormat();
        fo.setEncoding("euc-kr");
        fo.setIndent("   ");
        fo.setLineSeparator("\r\n");
        fo.setTextMode(Format.TextMode.TRIM);
        xo.setFormat(fo);
       
        xo.output(htmldoc, new FileOutputStream ("C:/Java_Study/0509/web/ex2/handphone.html"));
    }
}


출처 - http://blog.naver.com/PostView.nhn?blogId=freederic84&logNo=20064661734&redirect=Dlog&widgetTypeCall=true


===================================================================================


xml 파일 읽기


import java.util.List;                              // List형태로 값을 담을 때 사용

import org.jdom.Document;                    // XML 내용을 담기 위해 사용
import org.jdom.Element;                       // 하나의 태그 항목을 담을 때 사용
import org.jdom.input.SAXBuilder;          // XML 을 불러낼때 사용

 

    File file = new File(읽어드릴 xml 파일 주소);
   
    FileInputStream input = new FileInputStream(file); 
   
    SAXBuilder builder = new SAXBuilder();
   
    Document doc = builder.build(input);   // xml파일을 부른다.


    Element xmlRoot = doc.getRootElement();   // xml파일의 첫번째 태그를 부른다.

 

    List list1 = xmlRoot.getChildren();     // 첫번째 list1을 List 형태로 불러온다.

 

    Element element0 = (Element) list1.get(0);    // list1의 첫번째 태그인 element0을 불러온다.

 

    element0.getName();  // element0의 이름인 element0을 리턴한다.(String)

    element0.getText();    // element0의 값인 aaa를 리턴한다.(String)

 

 

<test>

    <list1>

        <element0>aaa</element0>

        <element1>bbb</element1>

    <list1>

    <list2>

        <element0>aaa</element0>

        <element1>bbb</element1>

    <list2>

</test>


출처 - http://blog.naver.com/PostView.nhn?blogId=darkelfand&logNo=90045930894


===================================================================================


케리스 소스를 포팅하여 인자원에서 프로젝트를 하고 있습니다.

xml 파일을 파싱하는 부분에서 xml파일 이름이 ex)피타 고라스의 정리.xml이라고 하면

jom으로 build하기 전까지 파일 이름이 피타 고라스의 정리.xml로 잘 넘어가는데

jom에서 build하면서 피타%20고라스의%20정리.xml로 읽어와서 파일을 찾을 수 없었습니다.

그래서 파일 이름 대신 파일 인풋 스트림 자체를 넣었습니다.

 

예전 거

 SAXBuilder builder = new SAXBuilder();
 Document doc = builder.build(new File(filename));


바꾼 거

 FileInputStream fis = new FileInputStream(xml_file);
 doc = new SAXBuilder().build(fis);
 root = doc.getRootElement();

 

잘 됩니다.


출처 - http://blog.naver.com/PostView.nhn?blogId=wga2&logNo=30873212&redirect=Dlog&widgetTypeCall=true


===================================================================================


xml 형식

<?xml version="1.0" encoding="UTF-8" ?>
<category>
  <idx id="1">
   <title>
     보증수리 기간은 언제를 기준으로 하나요?
   </title>
   <contents>
     그런거 안해
   </contents>
  </idx>
  <idx id="2">
   <title>
     이벤트 당첨 확인은 어디에서 하나요?
   </title>
   <contents>
     떨어진거라 생각해
   </contents>
  </idx>
  <idx id="3">
   <title>
     주행중 시동이 꺼져요
   </title>
   <contents>
     차 버려~
   </contents>
  </idx>


FaqModel.java
public class FaqModel {

	String idx = "";
	
	String title = "";
	
	String contents = "";

	public String getIdx() {
		return idx;
	}

	public void setIdx(String idx) {
		this.idx = idx;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getContents() {
		return contents;
	}

	public void setContents(String contents) {
		this.contents = contents;
	}
	
	
}



FaqModel.java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

public class FaqDao {

	private String XML_FILE_DIR = "http://url";

	SAXBuilder builder;  // Parser 객체 생성
	Document doc;        // XML문서 전체 나타냄  
	Element root;        // 하나의 태그를 나타냄

	/**
	 * 기본 생성자, Parser를 생성하여 XML문서를 메모리에 읽어 들인다. 
	 */
	public FaqDao(String XML_FILE_NAME) throws Exception {
		try {
			builder = new SAXBuilder();
//			doc = builder.build(new File(XML_FILE_DIR, XML_FILE_NAME));  //디렉토리로 파일을 가져올 경우
			doc = builder.build(XML_FILE_DIR+XML_FILE_NAME);  //url로 파일을 가져올 경우
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 *  XML문서의 내용을 읽어 객체화 합니다.
	 * @return
	 */
	public ArrayList getData() throws Exception{
		
		ArrayList obj = new ArrayList();
		FaqModel model = null;
		
		root = doc.getRootElement(); // root component  태그를 산출함
		
		List list = root.getChildren();
		
		Iterator it = list.iterator();
		
		while(it.hasNext()){
			Element el = (Element)it.next();

			model = new FaqModel();
			model.setIdx(el.getAttributeValue("id"));
			model.setTitle(el.getChild("title").getText());
			model.setContents(el.getChild("contents").getText());
			
			obj.add(model);
		}

		return obj;
		
	}
}


list로 가져가는것이  뷰단에서 컨트롤 하기가 쉬워서 닭질스럽게 담았다....ㅋㅋㅋ


출처 - http://kimddochi.tistory.com/entry/java-jdom%EC%9C%BC%EB%A1%9C-xml-%ED%8C%8C%EC%8B%B1%ED%95%98%EA%B8%B0


===================================================================================


. XML File

XML file as following

<?xml version="1.0"?>
<company>
	<staff>
		<firstname>yong</firstname>
		<lastname>mook kim</lastname>
		<nickname>mkyong</nickname>
		<salary>100000</salary>
	</staff>
	<staff>
		<firstname>low</firstname>
		<lastname>yin fong</lastname>
		<nickname>fong fong</nickname>
		<salary>200000</salary>
	</staff>
</company>

3. Java File

Use JDOM parser to parse above XML file.

import java.io.File;
import java.io.IOException;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
 
public class ReadXMLFile {
	public static void main(String[] args) {
 
	  SAXBuilder builder = new SAXBuilder();
	  File xmlFile = new File("c:\\file.xml");
 
	  try {
 
		Document document = (Document) builder.build(xmlFile);
		Element rootNode = document.getRootElement();
		List list = rootNode.getChildren("staff");
 
		for (int i = 0; i < list.size(); i++) {
 
		   Element node = (Element) list.get(i);
 
		   System.out.println("First Name : " + node.getChildText("firstname"));
		   System.out.println("Last Name : " + node.getChildText("lastname"));
		   System.out.println("Nick Name : " + node.getChildText("nickname"));
		   System.out.println("Salary : " + node.getChildText("salary"));
 
		}
 
	  } catch (IOException io) {
		System.out.println(io.getMessage());
	  } catch (JDOMException jdomex) {
		System.out.println(jdomex.getMessage());
	  }
	}
}

Output

First Name : yong
Last Name : mook kim
Nick Name : mkyong
Salary : 100000
First Name : low
Last Name : yin fong
Nick Name : fong fong
Salary : 200000


출처 - http://www.mkyong.com/java/how-to-read-xml-file-in-java-jdom-example/


===================================================================================


JDOM(Java Document Object Model)은 이름에서 알 수 있듯이 Java에 최적화된 XML 데이터를 다루기 위한 오픈소스 라이브러리로 SAX(Simple API for XML), 문서 객체 모델(DOM)과 상호 연동되며 SAX와 DOM의 장점만을 골라 만든 클래스와 인터페이스를 제공합니다. 


(SAX는 이벤트기반의 Document 파싱과 처리를 할 수 있는 빠르고 강력한 기능을 제공하는 API인반면, DOM은 매우 유연한 구조를 가지고 있지만 늦은 처리시간과 Document 처리절차가 복잡하다는 난점을 가지고 있는데, JDOM은 이러한 SAX의 빠른 수행속도와 DOM의 높은 유연성 등의 장점을 적절히 혼합해 놓은 형태를 보여줍니다.) 

JDOM은 W3C DOM과 유사하지만 DOM을 기반으로 설계되거나 DOM을 모델로 하지 않는 대안적인 문서 객체 모델로, 차이점은 DOM은 언어 중립적으로 설계되었고, 초기에 HTML 페이지의 자바 스크립트 가공에 주로 이용되었던 반면, JDOM은 Java 전용으로 설계되어 메소르 오버로딩, 컬렉션, 리플렉션 등 Java 프로그래머에게 친숙한 환경을 제공합니다.


위의 사이트에서 JDOM을 다운받아 프로젝트에 jdom.jar파일을 추가하면 됩니다.

1. JDOM을 이용한 간단한 XML 읽기 예제
public static void main(String[] args) {
		try {
			File xmlFile = new File("init.xml");
			FileInputStream in = new FileInputStream(xmlFile);
			SAXBuilder builder = new SAXBuilder();
			Document doc = builder.build(in);
			Element root =  doc.getRootElement();
			
			List<element> elements = root.getChildren();
			for(Element element : elements) {
				if( element.getName().equals("Id") )
					System.out.println(element.getText());
				else if( element.getName().equals("File") ) {
					List<ltelement> items = element.getChildren();
					for(Element item : items)
						System.out.println(item.getText());
				}
			}
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
XML소스는 아래와 같습니다.

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

<session>

<id>1</id>

<file>

<item>a.txt</item>

<item>b.txt</item>

<item>c.txt</item>

</file>
</session>

출처 - http://lyb1495.tistory.com/30

===================================================================================


namespace가 설정 되어 있을 경우 getChild() 메소드 호출시 인자로 namespace 값을 전달해 준다.


XML 예제 파일

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

<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1/gpx.xsd" version="1.1">

    <trk>

        <trkseg>

            <trkpt lat="0.0" lon="0.0">

                <time>2012-10-04T18:43:07</time>

            </trkpt>

        </trkseg>

        <trkseg>

            <trkpt lat="37.51129108015448" lon="127.04661022871733">

                <time>2012-10-04T18:43:10</time>

            </trkpt>

        </trkseg>

        <trkseg>

            <trkpt lat="37.51132058445364" lon="127.04664031974971">

                <time>2012-10-04T18:43:13</time>

            </trkpt>

        </trkseg>

    </trk>

</gpx>



예제 코드

public class JdomXmlRead {

    public static void main(String [] args) {

    File xmlFile = new File("예제.xml");

    try(FileInputStream fis = new FileInputStream(xmlFile)) {

    Document doc = new SAXBuilder().build(fis);

    Namespace ns =   Namespace.getNamespace("http://www.topografix.com/GPX/1/1");

    Element root = doc.getRootElement();

    Element trk = root.getChild("trk", ns);

   

    List<Element> trksegList = trk.getChildren("trkseg", ns);

   

    for(Element trkseg : trksegList) {

    Element trkpt = trkseg.getChild("trkpt", ns);

   

    String lat = trkpt.getAttributeValue("lat");

    String lon = trkpt.getAttributeValue("lon");

   

    Element time = trkpt.getChild("time", ns);

    String timeStr = time.getText();

   

    System.out.println(lat + ", " + lon + ", " + timeStr);

    }

    } catch(Exception e) {

    e.printStackTrace();

    }

    }

}
























Posted by linuxism
,


Service API changes starting with Android 2.0

원문 : http://android-developers.blogspot.com/2010/02/service-api-changes-starting-with.html


원래 하나의 포스트로 끝마치려고 했지만... 글이 조금 길어지는 경향이 있어서 두 개로 나누어 포스트 합니다. 첫번째 글에서 바로 뒤이어 Service 의 라이프 사이클 변화에 관한 내용을 번역합니다.

Service lifecycle changes

 Service 들이 필요하지 않은 경우에도 불구하고, 자신을 포그라운드 프로세스로 설정하는 문제를 제외하고도,  백그라운드에서 너무 많은 수의 Service 들이 돌아감에 따라, 각각의 Service 들이 한정된 메모리 자원을 차지하게 위해 서로 경쟁하게 되면 또 다른 문제가 발생할 수 있다. 안드로이드 플랫폼과 Service 간의 상호 작용 과정에서, 특정 어플리케이션이 코드상으로는 별다른 문제 없이 작성된 경우에도, Service 가 정상 종료되지 않고 백그라운드에 남아있을 수 있다. 예를 들어 다음과 같은 상황이다.
  1. Application 이 StartService 를 호출 한다.

  2. Service 의 onCreate, onStart() 함수가 호출 되고, 특정한 작업을 수행하기 위해 백그라운드 스레드가 생성된다.

  3. 시스템이 메모리 부족으로 인해 현재 작동중인 서비스를 강제로 종료 한다.

  4. 잠시 후에, 메모리 상황이 호전되어 Service 가 재시작한다. 이 때, Service 의 onCreate 함수는 호출 되지만, onStart 는 호출 되지 않는다. (startService 는 호출 되지 않았음으로..)

 
 결국, Service 는 생성된 채로 남아있게 된다. Service 는 어떠한 일을 수행 하지도 않으며 (무슨 일을 수행해야할 지 알 수 없음으로...), 어떤 시점에 종료되어야 하는지도 알 수 없다.

 이러한 문제를 해결하기 위해 안드로이드 2.0 에서 Service 의 onStart() 는 더이상 사용되지 않는다. (이전 버전과의 호환성 문제때문에 작동 자체는 하지만...) 대신 Service.onStartCommand() 콜백이 사용된다. 이 콜백 함수는 시스템이 Service 를 좀 더 잘 관리 할 수 있도록 해주는데, 기존 API 와는 달리  onStartCommand() 는 결과값을 반환한다. 안드로이드 플랫폼은 이 결과값을 기반으로 만일 작동중인 서비스가 강제로 종료될 경우, 어떠한 일을 수행해야 하는지 판단한다.
  • START_STICKY  는 기본적으로 이전과 동일하게 작동한다. 이전과의 차이점은 다음과 같다.  기존에 프로세스가 강제 종료된 후 Service 가 재 시작 될 때, onStart() 콜백이 호출 되지 않았지만, START_STICKY 형태로 호출된 Service 는 null Intent 가 담긴 onStartCommand() 콜백 함수가 호출된다. 이 모드를 사용하는 Service 는 null Intent 로 onStartCommand() 콜백 함수가 호출되는 경우를 주의깊게 처리해야 한다. 
  • START_NOT_STICKY 모드로 시작된 Service는  안드로이드 플랫폼에 의해 프로세스가 강제로 종료되는 경우, 다시 시작되지 않고 종료된 상태로 남게된다. 이러한 방식은 특정 Intent 로 주어진 명령을 수행하는 동안에만 Service 가 실행되면 되는 경우에 적당하다 예를 들어, 매15분마다 네트워크 상태를 체크하기 위해 실행되는 Service 를 생각해 보면, 만일 이 Service 가 작업도중 강제로 종료될 경우, 이 Service 는 재시작하기 보다는 정지된 상태로 남겨두고, 15분 후에 새롭게 시작되도록 하는 것이 최선이다. 
  • START_REDELIVER_INTENT  는 START_NOT_STICKY 와 유사하다. 단, 프로세스가 강제로 종료되는 경우 (stopSelf() 가 호출 되기 전에 종료되는 경우), Intent 가 다시 전달 되어 Service 가 재시작 한다.  (단, 여러차례 시도한 후에도, 작업이 종료되지 않으면, Service 는 재시작되지 않는다.) 이 모드는 전달받은 명령을 반드시 수행해야 하는 Service 에 유용하다. 
 기존에 존재하는 어플리케이션과의 호환성을 위해서, 이전 버전을 기준으로 제작된 어플리케이션은  START_STICKY_COMPATIBILITY 모드로 작동한다.  (null intent 를 보내지 않고 기존과 동일하게 작동). 단 API 버전 5  이상을 기준으로 작성된 어플리케이션들은 기본적으로 START_STICKY 모드로 작동 하며, 개발자는 반드시 onStart() 나 onStartCommand() 가 null intent 를 가지고 호출되는 경우를 염두해 두어야 한다. 

 개발자들은 아래에 제시된 코드를 활용하여, 손쉽게 이전 버전과 새로운 버전 양쪽 모두에서 작동하는 Service 를 구현할 수 있다. 

    // This is the old onStart method that will be called on the pre-2.0
    // platform.  On 2.0 or later we override onStartCommand() so this
    // method will not be called.
    @Override
    public void onStart(Intent intent, int startId) {
        handleStart(intent, startId);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        handleStart(intent, startId);
        return START_NOT_STICKY;
    }

    void handleStart(Intent intent, int startId) {
        // do work


New "running services" user interface

 * 이 후 이어지는 내용은 새롭게 추가된 Running Service 를 확인 할 수 있는 UI 어플리케이션에 관한 내용이라 대충 대충 건너 띄도록 하겠습니다.

 안드로이드 2.0 부터는 새롭게 "Running Services" Activity 가 어플리케이션 세팅에 추가 되었다. 사용자는 목록에 표시된 Service 를 터치해서 종료할 수 있다.

 화면 하단부에는 현재 시스템의 메모리 상황에 대한 정보가 표시된다. 

  • Avail: 38MB+114MB in 25 은 현재 38MB 의 공간이 바로 사용가능하며, 114MB 의 메모리 공간은 언제든지 종료시킬 수 있는 25개의 백그라운드 프로세스에 의해 점유되고 있음을 알려준다. 
  • Other: 32MB in 3 은 현재 3개의 임의로 종료되서는 않되는 포그라운드 프로세스에 의해 32MB 의 공간이 사용되고 있음을 알려준다. 
 대부분의 사용자들에게 이 새로운 UI 는 기존의 Task Killer 어플리케이션에 비해 사용하기 편리하며, 강제로 Service 를 종료시키는 것이 아니기 때문에 문제를 일으킬 소지가 훨씬 적다. 

 개발자들에게는 자신이 작성한 어플리케이션이 잘 작동하는지 (특히 Service 관리라는 측면에서) 확인 할 수 있게 해주는 유용한 툴이 될 수있다. 또한 어플리케이션이 구동한 Service 가 사용자에 의해 어느시점에서든지 종료 할 수 있다는 점을 염두해 두어야 한다. 안드로이드의 Service 는 매우 강력한 도구이지만, 어플리케이션 개발자들이 전체 폰의 성능에 큰 악영향을 끼칠 수 있는 문제를 가장 많이 일으키는 도구이기도 한다. 




'Android > Common' 카테고리의 다른 글

android - WebView 사용 하기  (1) 2012.11.03
android - app 버전 관리  (0) 2012.10.07
android - SharedPreferences  (0) 2012.09.24
android - 이클립스 환경 설정  (0) 2012.09.21
android - 하이브리드 앱(웹)  (1) 2012.09.19
Posted by linuxism
,


모든 안드로이드 폰이 다 똑같은지는 모르겠습니다. (아마 대부분 같지 않을까 싶습니다.)
일단, 제가 개발용으로 사용하고 있는 갤럭시S2 기준으로 !!

개발을 하다보면 테스트를 하면서 핸드폰이 죽거나 할 때 왜 죽었는지 알고 싶을 때가 있습니다.
보통은 PC에 USB를 꽂은 상태로 이클립스(eclpise)에서 테스트를 하기 때문에 
실시간으로 로그 체크가 가능하지만, 만약 USB를 꽂지 않은 상태에서 폰이 죽었다면...?


다른 디바이스들도 그런지는 모르겠지만 삼성폰들은 내부적으로 어플이 비정상 종료될때 로그 파일을 남깁니다.
그 위치는 /data/log 폴더입니다.


그럼 지금부터 해당 파일을 가져오는 방법을 알아보겠습니다. 
커맨드 창을 열고..

C:\>adb shell
cd data/log

라고 입력한다음 'ls' 명령어를 이용해서 파일 리스트를 보면
대략 다음과 같은 파일 리스트가 나올겁니다.
(만약 data 폴더까지만 가서 ls 라고 명령을 내리면 아무 것도 보이지 않을 것입니다.
data 폴더 아래에 있는 폴더 및 파일들은 죄다 권한 문제로 숨겨져 있거든요.)



$ cd data/log

cd data/log

$ ls

ls

off.p

recovery_log.txt

recovery_kernel_log.txt

rtc.log

dumpstate_app_error.txt.gz

dumpstate_app_anr.txt.gz

dumpState_waitforcond.log

dumpstate_app_native.txt.gz

Imagestring.txt

RR_NPON.p

이 중 에러 로그 파일은 dumpstate_app_error.txt.gz 이며, gz로 압축되어 있습니다. 
(윈도우에서 압축풀어보면 그 안에 txt 파일이 들어 있습니다.)


일단 파일 시스템 구조는 이렇고, 윈도우 커맨드 상에서 간단히 로그 파일을 다운 받기 위해서는 다음과 같이 하면 됩니다.

C:\>adb pull data/log/dumpstate_app_error.txt.gz

이렇게 하면 현재 폴더에 해당 파일을 다운 받습니다.


윈도우에서 압축 풀어서 보면 로그 파일들을 살펴볼 수 있습니다
출처 - http://snowbora.com/452




'Android > adb' 카테고리의 다른 글

android /etc/hosts file modify  (0) 2013.01.24
Posted by linuxism
,