본문 바로가기

Dev.../웹서비스

[펌] XMLBeans 소개(1)

XMLBeans 소개 (1)
 
 
XMLBeans 는 2003년 9월 BEA 에서 Apache Project 에 제출한 기술이다.
BEA 의 개발환경 즉 Weblogic Workshop 을 기반으로 한 SOA 기반의 개발환경은 매우 매력적이였지만 플랫폼 독립적인 제품을 만드는 필자의 입장에서 채택을 꺼려한 이유에는 벤더의존적이였다는 것이였다.  이러한 한계를 인식한 BEA 에서 서서히 그들의 기술을 Open 하기 시작하여 표준화하려는 노력들을 시작하였다.  XMLBeans 도 그러한 움직임에서 Apache에 공개된 기술이며, Beehive 의 구성 요소 중 하나이다. Beehive 에 대한 자세한 설명은 다음 기회로 미루기로한다.

필자도 XML 문서를 다루기 위하여 DOM 과 같은 XML Parser 를 이용하여 코드내부에
XML 의 문서양을 고려한 로직을 넣어 프로그래밍 하곤 하였다.
이러할 경우 특정 양식의 XML 문서를 다루는 코드는 XML의 양식에 따라 그 복잡성이 매우 증가하며, 문서의 양식에 동적으로 반응하는것은 사실상 불가하다.
또한 시스템 내부적으로는 Java객체를 타시스템과의 인터페이스를 위하여서는 표준 XML 문서를 변환하는 식의 개발이 이루어진것이 사실이다.

XMLBeans 는 한마디로 말하면 이러한 문제를 XML Schema 를 이용하여 일반적인 방식으로 풀어낸
XML-Java Binding tool 정도가 되지않나 생각한다.
즉 XML 문서의 양식을 Schema로 정의하고 이를 이용하여 Java 객체를 생성하여 XML Instance를
파싱하고 생성하고 변경 하는 것이다.
이를 도식화 해보면 다음과 같다.
 




 
 
예를들어 PO 문서를 다루는 프로그래밍을 해야하는 개발자는 PO문서를 위하여 XML 문서를 직접 파싱하거나 할 필요없이 PO 에 해당하는 Java Object 를 이용하여 다른 객체들과 마찬가지로 다룰 수 있게 된다.  이러한 방법을 통하여 XML이 가지는 장점과 Java 객체가 가지는 장점을 동시에 수용할 수 있다고 생각한다.

그러면 실제 간단한 예제를 통하여 XMLBeans 를 사용하는 예를 살펴보기로 한다.
먼저 이를 테스트 해보려면 다음의 준비가 필요하다.
- JDK 1.4 for version 1 XMLBeans releases.
- An XMLBeans version 1 installation. (Apache Site 에서 다운받을 수 있다.)
먼저 다음과 같은 간단한 PO 문서를 정의한 XML Schema 가 있다고 가정하자.
(XML Schema 에 대한 설명은 여기서 하지 않기로 한다.)
<xs:schema
    xmlns:xs="
http://www.w3.org/2001/XMLSchema"
    xmlns:po="
http://openuri.org/easypo"
    targetNamespace="
http://openuri.org/easypo"
    elementFormDefault="qualified">
    <xs:element name="purchase-order">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="customer" type="po:customer"/>
                <xs:element name="date" type="xs:dateTime"/>
                <xs:element name="line-item" type="po:line-item" minOccurs="0" maxOccurs="unbounded"/>
                <xs:element name="shipper" type="po:shipper" minOccurs="0" maxOccurs="1"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="customer">
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="address" type="xs:string"/>
        </xs:sequence>
        <xs:attribute name="age" type="xs:int"/>
        <xs:attribute name="moo" type="xs:int" default="100"/>
        <xs:attribute name="poo" type="xs:int" fixed="200"/>
    </xs:complexType>
    <xs:complexType name="line-item">
        <xs:sequence>
            <xs:element name="description" type="xs:string"/>
            <xs:element name="per-unit-ounces" type="xs:decimal"/>
            <xs:element name="price" type="xs:decimal"/>
            <xs:element name="quantity" type="xs:integer"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="shipper">
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="per-ounce-rate" type="xs:decimal"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>
 
위의 Schema 를 가지는 문서의 예이다.
 
<purchase-order xmlns="http://openuri.org/easypo">
    <customer>
        <name>Gladys Kravitz</name>
        <address>Anytown, PA</address>
    </customer>
    <date>2003-01-07T14:16:00-05:00</date>
    <line-item>
        <description>Burnham's Celestial Handbook, Vol 1</description>
        <per-unit-ounces>5</per-unit-ounces>
        <price>21.79</price>
        <quantity>2</quantity>
    </line-item>
    <line-item>
        <description>Burnham's Celestial Handbook, Vol 2</description>
        <per-unit-ounces>5</per-unit-ounces>
        <price>19.89</price>
        <quantity>2</quantity>
    </line-item>
    <shipper>
        <name>ZipShip</name>
        <per-ounce-rate>0.74</per-ounce-rate>
    </shipper>
</purchase-order>
 
그럼 XML Schema 를 이용하여 Java 객체를 생성해본다.
 
 scomp -out tutorialsgettingstartedlibeasypo.jar schemaseasypoeasypo.xsd
 
* XMLBeans 를 Install 한 디렉토리가 xmlbeans-1.0.3 이라면 bin 에 가면 scomp 라는 cmd 혹은 sh 를 사용할 수 있다.
  이때 주의할 점은 반드시 Java Runtime Version 이 1.4 이상이어야 한다는 점이다.
 
이렇게 하면 tutorialsgettingstartedlibeasypo.jar 를 얻을 수 있다.  이를 classpath 에 넣기만하면 purchase-order 객체를 사용할 수 있는것이다.
 
[생성된 객체]
1. Schema 에 정의된 Element 에 상응하는 Java 객체와 Method 생성된다.
  예) Customer Element
 
 // Customer 객체를 얻는다.
 public abstract org.openuri.easypo.Customer getCustomer()
 // Customer 객체를 Set한다.
 public abstract void setCustomer( org.openuri.easypo.Customer )
 // 새로운 Customer 객체를 추가한다.
 public abstract org.openuri.easypo.Customer addNewCustomer()
 
2. Schema 에 Optional 로 정의된 Element 의 경우 다음과 같은 Method 추가 생성된다.
 
 // Shipper Element 가 있으면 true
 public boolean isSetShipper ( )
 // Shipper Element 삭제
 public abstract void unsetShipper ( )
 
    * Optional 로 정의되었다 함은 minOccurs="0" 이렇게 정의함을 의미한다.
   
3. Schema 에 maxOccurs 가 “unbounded” 로 설정된 Element의 경우 Array 형태로 다둘 수 있으며  다음과 같은 Method가 생성된다.
 // 전제 Array 를 set 하거나 get
 public abstract org.openuri.easypo.LineItem[] getLineItemArray ( )
 public abstract void setLineItemArray ( org.openuri.easypo.LineItem[] )
 
 // 하나의 Array 를 set 하거나 get
 public abstract org.openuri.easypo.LineItem getLineItemArray ( int )
 public abstract void setLineItemArray( int, org.openuri.easypo.LineItem )
 
 // Add or remove an item. public abstract org.openuri.easypo.LineItem insertNewLineItem( int )
 public abstract void removeLineItem( int )
 
 // 전체 Array Size 를 가지고 온다.
 public abstract int sizeOfLineItemArray()
    
 
그러면 이렇게 생성된 객체를 이용하여 실제 사용하는 예제를 살펴보자.
PO 문서에 Line Item을 하나 추가하는 Method를 만든다고 가정하면 ..
PO XML 파일과 LineItem 정보를 입력하여 PO 문서에 Line Item 이 추가되는 예제이다.
 
public class POUpdater
{
    public static void main(String[] args)
    {
        File poXmlFile = new File(args[0]);
        String updatedPoXml = addLineItem(poXmlFile, args[1], args[2],
            args[3], args[4]);
        System.out.println(updatedPoXml);
    }
 
    private static String addLineItem(File purchaseOrder, String itemDescription,
                                      String perUnitOuncesString,
                                      String itemPriceString, String itemQuantityString)
    {
        PurchaseOrderDocument poDoc = null;
        try
        {
            // PO 문서를 파싱하여 PurchaseOrderDocument 라는 XMLBeans 를 생성한다.
           poDoc = PurchaseOrderDocument.Factory.parse(purchaseOrder);
        } catch (XmlException e)
        {
            e.printStackTrace();
        } catch (IOException e)
        {
            e.printStackTrace();
        }
 
        // Convert incoming data to types that can be used in accessors.
        BigDecimal perUnitOunces = new BigDecimal(perUnitOuncesString);
        BigDecimal itemPrice = new BigDecimal(itemPriceString);
        BigInteger itemQuantity = new BigInteger(itemQuantityString);
 
        // 새로운 <line-item> element 를 추가한다.
        LineItem newItem = poDoc.getPurchaseOrder().addNewLineItem();
        newItem.setDescription(itemDescription);
        newItem.setPerUnitOunces(perUnitOunces);
        newItem.setPrice(itemPrice);
        newItem.setQuantity(itemQuantity);
        return poDoc.toString();
    }
}