반응형
출처: 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()); // 문자열로 출력
    

+ Recent posts