Taslak Çalışmalarım

English (Ä°ngilizce)

Sunday, August 14, 2005

JibX ile XML-Java Mapping

JibX ile XML-Java nesneleri arasında mapping yapılmasına yönelik bazı temel komutları, referans dokümanı şeklinde hazırladım. Zaman içinde yeni eklemeler yapacağım:

mapping

Bir java nesnesinin eşleştirme tanımlamasını başlatır:

<mapping name="customer" class="com.yunus.xml.jibx_1.Customer">

 

direction

Eğer nesne-XML bağlama işini tek yönlü yapacaksan, bunu belirterek, bazı tanımlamalardan tasarruf edebilirsin.

direction="input" veya direction="output"

 

structure

Structure, bir java nesnesine eşleştirilir.

<binding>

<mapping name="customer" class="com.yunus.xml.jibx_1.Customer">

<structure name="person" field="person">

<value name="cust-num" field="customerNumber" />

<value name="first-name" field="firstName" />

<value name="last-name" field="lastName" />

</structure>

<value name="street" field="street" />

structure ve mapping birbirine benzer. İkisi de bir nesnenin nasıl XML´e eşleştirildiğini tanımlar. Ancak structure, bir java nesnesinin içindeki bir nesneyi tanımlar. Ayrıca structure genel kural koymaz. Yani aynı sınıfın nesneleri bir yerde bir şekilde eşleştirilip, diğer yerde farklı eşleştirilebilir.

XML structure

XML içindeki structure´lar Javadaki kompoze edilen bir nesneye karşılık gelmek zorunluluğu yok. Bunun için field kısmı boş tutulur. Yani field belirtilmez.

<mapping name="customer" class="example6.Customer">

<structure name="person">

<value name="cust-num" field="customerNumber"/>

<value name="first-name" field="firstName"/>

<value name="last-name" field="lastName"/>

</structure>

<customer>

<person>

<cust-num>123456789</cust-num>

<first-name>John</first-name>

<last-name>Smith</last-name>

</person>

public class Customer {

public int customerNumber;

public String firstName;

public String lastName;

 

Java structure

Javadaki bir nesneye karşılık XMLde herhangi bir structure bulunması zorunlu değil. Bunun için structure elementi, name atributu belirtilmeden tanımlanır:

<structure field="address">

<value name="street" field="street"/>

<value name="city" field="city"/>

public class Customer {

public Address address;

<customer>

<street>12345 Happy Lane</street>

<city>Plunk</city>

<state>WA</state>

 

--- Opsiyonel alanlar ---

Bir Java nesnesini herhangi bir XML alanına bağlamazsan, bunu XML dosyasında üretmez. Tersine, bir XML elementini bir structure ile tanımlar, ancak herhangi bir fielda bağlamazsan, bu veriyi Java nesnesine taşımaz.

<mapping name="customer" class="example8.Customer">

<value name="street" field="street"/>

<value name="city" field="city"/>

<value name="state" field="state"/>

<value name="zip" field="zip"/>

<structure name="instructions"/>

<customer>

<street>12345 Happy Lane</street>

<city>Plunk</city>

<state>WA</state>

<zip>98059</zip>

<instructions>

<!-- content skipped when unmarshalled -->

<p>Leave package behind bushes to <b>left</b>

of door</p>

<!-- always marshalled as empty -->

</instructions>

<phone>888.555.1234</phone>

</customer>

public class Customer {

public Person person;

public String street;

public String city;

public String state;

public Integer zip;

public String phone;

}

Person nesnesi, herhangi bir XML elemanına bağlanmamış. instructions elemanıysa, herhangi bir nesne alanına bağlanmamış.

--- name ---

name atributu, XML taginin ismini belirtir.

Eğer name belirtilmezse, bir üst elementin belirttiği şartlar geçerli olur:

<structure name="person" field="person"

value-style="attribute">

<value name="cust-num" get-method="getNumber"

set-method="setNumber"/>

<value name="first-name" field="firstName" />

<value field="lastName" style="text"/>

</structure>

<person cust-num="2993" first-name="Ahmet">Özgül</person>     

 

--- field ---

field atributu java nesnesinin member değişkenidir.

--- style ---

style ile XML içeriğinin text olarak mı, atribut olarak mı yazılacağı belirtilir.

<value field="lastName" style="text"/>

 

--- value ---

Primitif java verileri, value ile XML elemanlarına bağlanır.

<value field="lastName" style="text"/>

 

--- value-style ---

value´lar, XML elemanlarına (atribute veya element) karşılık gelir. value-style, XML elemanlarının tipini (atribute mu, element mi) olduğunu belirtir:

<structure name="person" field="person"

value-style="attribute">

<value name="cust-num" get-method="getNumber"

set-method="setNumber"/>

<value name="first-name" field="firstName" />

<value field="lastName" style="text"/>

</structure>

<person cust-num="2993" first-name="Ahmet">Özgül</person>

 

--- usage ---

Java nesnesinden XML´e dönüştürme sırasında herhangi bir elemanın zorunlu mu, opsiyonel mi olduğunu belirtir.

<value name="zip" field="zip" usage="optional" />

Java -> XML

<customer>

<person cust-num="2993" first-name="Ahmet">Özgül</person>

<street>Mertebe</street>

<city>Emek</city>

<state>Ankara</state>

<phone>+90(535)7120767</phone>

</customer>

XML -> Java dönüşümünde, eğer zip yoksa, zip değişkenine null atanacaktır.

--- get-method set-method ---

Bir XML elemanına karşılık gelen nesne içeriğinin getter ve setterını belirtir:

<value name="cust-num" get-method="getNumber"

set-method="setNumber"/>

 

--- collection ---

Bir java nesnesindeki collection nesnesini eşleştirir:

<mapping name="timetable" class="com.yunus.xml.jibx_4.TimeTable">

<collection field="carriers" item-type="com.yunus.xml.jibx_4.Carrier"/>

public class TimeTable {

private ArrayList carriers;

Collection içeriği de özel nesnelerse, bunların eşleştirmesinin de tanımlanması gerekir:

<mapping name="carrier" class="com.yunus.xml.jibx_4.Carrier">

item-type zorunlu değil. Ancak item-type belirtilmezse, collection içinde her türlü nesne bulunabilir. Bu durumda XML->Java dönüşümü istenildiği gibi olmaz.

--- wrapper ---

Collection içindeki nesnelerin, bir wrapper içinde gösterilmesi için:

<timetable>

<carriers>

<carrier code="NL" rating="4">

Her bir collection tanımına, bir name belirtmelisin:

<collection name="carriers" field="carriers"/>

 

--- ordered ---

XML dokümanının binding.xml dosyasında belirtilen sırada olması varsayımını kaldırır. Ancak bu xml-java dönüştürme işini yavaşlatır.

<mapping name="customer" class="example3.Customer" ordered="false">

 

--- ident referans ---

Java nesneleri arasındaki referansları XML´de de koruyabilmek için, XML´in ID ve IDREF özellikleri kullanılır.

<mapping name="airport" class="example5.Airport">

<value style="attribute" name="code" field="code" ident="def"/>

<mapping name="route" value-style="attribute" class="example5.Route">

<value name="from" field="from" ident="ref"/>

<value name="to" field="to" ident="ref"/>

XML:

<route from="BOS" to="SEA">

 

--- namespace ---

namespace hangi element ve atributlara uygulanacağı, default atributuyla belirtilir:

<mapping name="customer" class="example9.Customer">

<namespace uri="http://www.sosnoski.com/ns1";

default="elements"/>

<customer phone="888.555.1234"

xmlns="http://www.sosnoski.com/ns1">;

Eğer default="all" belirtilirse, bütün alt element ve atributlarda namespace uygulanır:

<mapping name="person" class="example9.Person">

<namespace prefix="ns2"

uri="http://www.sosnoski.com/ns2"; default="all"/>

<ns2:person ns2:cust-num="123456789"

xmlns:ns2="http://www.sosnoski.com/ns2">;

<ns2:first-name>John</ns2:first-name>

<ns2:last-name>Smith</ns2:last-name>

</ns2:person>

Eğer üst bir elemanda belirtilmiş namespace´i iptal etmek istiyorsan, ns atributunu kullanmalısın.

--- abstract ve extends ---

abstract olarak belirttiğin sınıfları extend eden sınıfları belirtebilirsin. Böylece, soyut sınıfa ait xml verisi, her iki extend eden sınıfta da kullanılabilir:

<binding>

<mapping name="customer" class="example10.Customer">

<structure field="identity"/>

</mapping>

<mapping class="example10.Identity" abstract="true">

<value name="cust-num" field="customerNumber"/>

</mapping>

<mapping name="person" class="example10.Person" extends="example10.Identity">

<structure map-as="example10.Identity"/>

<value name="first-name" field="firstName"/>

</mapping>

<mapping name="company" class="example10.Company" extends="example10.Identity">

<value name="tax-id" field="taxId"/>

<structure map-as="example10.Identity"/>

</mapping>

</binding>

<customer>

<person>

<cust-num>123456789</cust-num>

<first-name>John</first-name>

</person>

</customer>

<customer>

<company>

<tax-id>91-234851</tax-id>

<cust-num>311233459</cust-num>

</company>

</customer>

 

--- using ve label ---

Bir structure, mapping veya collection ile tanımlanmış eşleştirmeyi tekrar tekrar farklı yerlerde kullanabilirsin.

<structure name="ship-address" field="shipAddress" label="base-address">

<value name="street" field="street"/>

<value name="city" field="city"/>

<value name="state" field="state"/>

<value name="zip" field="zip"/>

</structure>

<structure name="bill-address" field="billAddress" using="base-address"

usage="optional"/>

<ship-address>

<street>12345 Happy Lane</street>

<city>Plunk</city>

<state>WA</state>

<zip>98059</zip>

</ship-address>

<bill-address>

<street>54321 Happy Lane</street>

<city>Plunk</city>

<state>WA</state>

<zip>98059</zip>

</bill-address>

Ancak bu kullanım şekli 2. versiyonda değiştirilecek. abstract yaklaşımını şimdi daha ziyade kullanmakta fayda var.

--- pre-get pre-set post-set factory ---

factory metodu bir nesne serisizleştirilmeden (unmarshall) önce çağrılır. pre-get metodu, nesne serileştirmeden önce çağrılır.

<mapping name="order" class="example12.Order"

factory="example12.Order.orderFactory" pre-get="preget">

public static Order orderFactory() {

System.out.println("Order.orderFactory called");

return new Order();

}

public void preget() {

System.out.println("Order.preget called");

total = items.size() * 1.5;

}

pre-set metodu nesne serileştirilmeden önce çağrılır.

post-set metodu nesne serileştirilmenin ardında çağrılır. Burada nesneler arasında referanslar kurmak uygun olur.

<mapping name="customer" class="example12.Customer">

<structure name="person" field="person" pre-set="preset">

<mapping name="item" class="example12.Item" post-set="postset">

public void postset(IUnmarshallingContext ctx) {

order = (Order)ctx.getStackObject(1);

System.out.println("Item.postset called");

}

public void preset(Object obj) {

customer = (Customer)obj;

System.out.println("Person.preset called");

}

Object tipinden parametre alan pre-set metotları, XML dosyasındaki kapsayan nesnenin referansını parametre olarak gönderir.

post-set metotları, Context nesnesini parametre olarak alır. Bununla tüm binding bünyesindeki nesnelere erişmek mümkündür.

--- serializers ---

İki tip özel serializer belirtmek mümkün. 1. format elementiyle, belirli tipteki tüm değerler için özel serializer yazılabilir. 2. belirli bir alan ve eleman için özel olarak serializer belirtilebilir:

<binding>

<format type="int[]" serializer="example13.Conversion.serializeIntArray"

deserializer="example13.Conversion.deserializeIntArray"/>

...

<value name="total" field="total"

serializer="example13.Conversion.serializeDollarsCents"

deserializer="example13.Conversion.deserializeDollarsCents"/>

<value name="orders" field="orders"/>

public class Conversion

{

private Conversion () {}



public static String serializeDollarsCents(int cents) {

serializerlar, statik metotlar olmak durumundadır.


--- marshaller ---

Özel marshallerlar yazmak da mümkün. Bunlar belirli bir sınıfı nasıl serileştireceklerini bilir:

<mapping class="java.util.HashMap" name="map"

marshaller="example14.HashMapper" unmarshaller="example14.HashMapper"/>

public class HashMapper implements IMarshaller, IUnmarshaller, IAliasable

<map size="4">

<entry key="38193">

<customer state="WA" zip="98059">

<name first-name="John" last-name="Smith"/>

<street>12345 Happy Lane</street>

<city>Plunk</city>

</customer>

</entry>

<entry key="39122">

0 Comments:

Post a Comment

<< Home