JWorld@TW the best professional Java site in Taiwan
      註冊 | 登入 | 全文檢索 | 排行榜  

» JWorld@TW » Java & XML、Web Service  

按列印兼容模式列印這個話題 列印話題    把這個話題寄給朋友 寄給朋友    訂閱主題
reply to topicthreaded modego to previous topicgo to next topic
己加入精華區
by koji at 2011-02-22 14:15
本主題所含的標籤
作者 JAXB 新手學習筆記 [精華]
benbai123





發文: 25
積分: 0
於 2011-02-22 13:11 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
各位先進好, 小弟最近剛學 JAXB, 整理了一些內容,
希望能藉此減低往後入門者的痛感,
新手拙文, 請多指教,

總共會有八篇

初探 JAXB -- 生成物件及將物件轉 xml
由 XML 字串生成物件 -- 如字面所述
用 NamespacePrefixMapper 修正 prefix -- 增加生出來的 xml 的可讀性
JAXB xsd 中使用其它文件的內容 -- import / include / namespace
使用 Name space 解決名稱衝突 -- 撞名問題
為同名型態生成不同 class - Customizing JAXB Bindings -- 處理完撞名繼續看它
分門別類 - customize package bindings -- 管理 package
以 Ant 使用 JAXB xjc -- 用 Ant 做 xjc 動作

會陸續整理上來

立即開始第一篇 -- 初探 JAXB

1. 撰寫 XML Schema 的 xsd 檔


首先要準備一份 xsd 檔, 以便利用它來生成物件,

並使用 JAXB 的 API 進行物件與 xml 之間的轉換,

例如以下的 schema 代表一家製糖公司生產的 白糖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<!-- xmlns:xsd="http://www.w3.org/2001/XMLSchema" ::
   http://www.w3.org/2001/XMLSchema 
     可以想成使用到的其它份文件的 namespace
     xsd 則是要關聯到該文件中的 type 時用作前綴的短名稱
 
  targetNamespace="http://www.WhiteSugerCompany.com/ws" ::
    表示這一份文件的 namespace 為 http://www.WhiteSugerCompany.com/ws
    想像有多家製糖公司各自都有一個 suger 的 type,
    namespace 可以用來區分它們
   -->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:ws="http://www.WhiteSugerCompany.com/ws"
  targetNamespace="http://www.WhiteSugerCompany.com/ws">
 
  <!-- 一個 suger 的 type, 包含了 顏色, 甜度 -->
  <xsd:complexType name="suger">
    <xsd:sequence>
      <xsd:element name="color" type="xsd:string"/>
      <xsd:element name="sweetness" type="xsd:byte"/>
    </xsd:sequence>
  </xsd:complexType>
 
  <!-- 一個 type 為 suger 的 element -->
  <xsd:element name="Sugers" type="ws:suger"/>
</xsd:schema>



2. 使用 xjc 由 xsd 檔生成物件


接下來將 xsd 檔複製到 jdk\bin 資料夾中 執行以下命令

1
C:\Program Files\Java\jdk1.6.0_21\bin>xjc -p org.iii.test.jaxb.whitesuger xmlSchema\WhiteSuger\WhiteSuger.xsd


就可以利用 jdk 所附的 xjc 程式, 由我們寫的 xsd 檔生成對應物件,

其中 \-p 是用來指定物件的 package,

xmlSchema\WhiteSuger\WhiteSuger.xsd 則是我們 xsd 檔的相對路徑,

這時可看到像以下的畫面及檔案






3. 利用 JAXB 由物件生成 XML


現在有了 xsd 檔及生出的物件, 接下來便可以使用 JAXB 提供的 API,

由物件直接生成 xml

首先將剛生成的 package 放到 src 中如下 (請先忽略紅框之外的部份)



然後要下載 JAXB RI 及將 lib 加入專案, 如下

下載 JAXB RI

下載頁

http://jaxb.java.net/2.2.3/

點 Download the binary, 副檔名要改 .jar

安裝

在下載後的 jar 檔點兩下, 第一頁版權宣告頁拉到最下方,

點 Accept, 會生出一個資料夾, 將它搬到適當地方即可,

然後將該資料夾下 lib 內的 jar 檔加入專案內

下載並加入 jar 後

接下來撰寫如下程式, 生成物件, 設置適當的值並生成 xml

這裡要注意的是, StringWriter 會以附加的方式持續加入內容,

因此在加入新內容前要清空它的 buffer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package org.iii.test.jaxb;
 
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import org.iii.test.jaxb.whitesuger.Suger;
import org.iii.test.jaxb.whitesuger.ObjectFactory;
 
public class Test {
 
  public static void main(String args[]){
 
    try{
      //-- get context instance
      JAXBContext ctx = JAXBContext.newInstance("org.iii.test.jaxb.whitesuger");
      ObjectFactory of = new ObjectFactory();
 
      //-- create Suger object
      Suger ws = of.createSuger();
 
      //-- set values
      ws.setColor("Cream color");
      ws.setSweetness((byte)20);
 
      //-- convert ws to JAXBElement
      JAXBElement<Suger> je = of.createSugers(ws);
      //-- get Marshaller
      Marshaller m = ctx.createMarshaller();
 
      //-- marshal JAXBElement into StringWriter
      StringWriter xml = new StringWriter();
      m.marshal(je, xml);
      System.err.println(xml.toString());
 
      //-- separator
      System.err.println("\n********\n********\n");
 
      //-- clear old content in StringWriter
      StringBuffer sb = xml.getBuffer();
      sb.setLength(0);
 
      //-- marshal JAXBElement into StringWriter with format
      m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
      m.marshal(je, xml);
      System.err.println(xml.toString());
    }
    catch (Exception e){
      e.printStackTrace();
    }
  }
}
 


輸出結果如下圖



其中兩行星號上方的是 未格式化 的輸出結果,

下方的則是經過格式化的輸出結果


4. References


W3C 文件

http://www.w3.org/TR/xmlschema-0/#DefnDeclars

史蒂芬 很詳盡的教學

http://home.so-net.net.tw/idealist/WebService/JAXB.html


benbai123 edited on 2011-04-17 12:05
reply to postreply to post
作者 Re:JAXB 新手學習筆記 [Re:benbai123]
benbai123





發文: 25
積分: 0
於 2011-02-22 13:26 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
第二篇 -- 由 XML 字串生成物件


1. 使用 Unmarshaller


在 第一篇 之中, 我們將物件利用 JAXB 的 API 轉成 XML 字串,

通常之後我們會將轉出的字串傳到其它地方, 而其它地方收到後,

便要由 XML 字串 轉回相對應的物件,

假設已經知道所要轉成的物件類型, 則轉換的程式如下

1
2
3
4
5
6
7
8
9
10
//-- get context instance
JAXBContext context = JAXBContext.newInstance(Suger.class);
//-- get unmarshaller
Unmarshaller um = context.createUnmarshaller();
//-- unmarshal xml string to JAXB element
JAXBElement<Suger> root = um.unmarshal(new StreamSource(new StringReader(
  xmlString)), Suger.class);
 
//-- get object from JAXB element
Suger ws2 = root.getValue();


這裡要注意的是, xmlString 要是未經 format 過的,


2. 完整程式及執行結果


以下為完整的程式及執行結果截圖, 其中包含 第一篇 的部份

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package org.iii.test.jaxb.test;
 
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
 
import org.iii.test.jaxb.whitesuger.Suger;
import org.iii.test.jaxb.whitesuger.ObjectFactory;
 
public class Test {
 
  public static void main(String args[]){
 
    try{
      //-- get context instance
      JAXBContext ctx = JAXBContext.newInstance("org.iii.test.jaxb.whitesuger");
      ObjectFactory of = new ObjectFactory();
 
      //-- create Suger object
      Suger ws = of.createSuger();
 
      //-- set values
      ws.setColor("Cream color");
      ws.setSweetness((byte)20);
 
      //-- convert ws to JAXBElement
      JAXBElement<Suger> je = of.createSugers(ws);
      //-- get Marshaller
      Marshaller m = ctx.createMarshaller();
 
      //-- marshal JAXBElement into StringWriter
      StringWriter xml = new StringWriter();
      m.marshal(je, xml);
 
      //-- get xml string
      String xmlString = xml.toString();
      System.err.println(xmlString);
 
      //-- separator
      System.err.println("\n********\n********\n");
 
      //-- clear old content in StringWriter
      StringBuffer sb = xml.getBuffer();
      sb.setLength(0);
 
      //-- marshal JAXBElement into StringWriter with format
      m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
      m.marshal(je, xml);
      System.err.println(xml.toString());
 
      //-- get context instance
      JAXBContext context = JAXBContext.newInstance(Suger.class);
      //-- get unmarshaller
      Unmarshaller um = context.createUnmarshaller();
      //-- unmarshal xml string to JAXB element
      JAXBElement<Suger> root = um.unmarshal(new StreamSource(new StringReader(
          xmlString)), Suger.class);
 
      //-- get object from JAXB element
      Suger ws2 = root.getValue();
 
      //-- separator
      System.err.println("\n********\n********\n");
 
      //-- output object value
      System.err.println(" ws2 color = " + ws2.getColor());
      System.err.println(" ws2 sweetness = " + ws2.getSweetness());
    }
    catch (Exception e){
      e.printStackTrace();
    }
  }
}





3. References


實用教學

http://jaxb.java.net/guide/_XmlRootElement_and_unmarshalling.html


reply to postreply to post
作者 Re:JAXB 新手學習筆記 [Re:benbai123]
benbai123





發文: 25
積分: 0
於 2011-02-22 13:38 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
第三篇 -- 用 NamespacePrefixMapper 修正 prefix



1. 前言



在 第一篇 之中, 格式化的輸出如下

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:Sugers xmlns:ns2="http://www.WhiteSugerCompany.com/ws">
    <color>Cream color</color>
    <sweetness>20</sweetness>
</ns2:Sugers>
 


我們可以發現, [http://www.WhiteSugerCompany.com/ws] 在這裡的 prefix,

變成了 ns2, 而不是 xsd 中的 ws,

我們可以實作 com.sun.xml.bind.marshaller.NamespacePrefixMapper,

來進行 Namespace 與 Prefix 之間對應的處理,



2. 實作並使用 NamespacePrefixMapper



實作 NamespacePrefixMapper

首先我們要實作 NamespacePrefixMapper, 實作程式如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package org.iii.test.jaxb.test;
 
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
 
public class NamespacePrefixMapperImpl extends NamespacePrefixMapper {
 
  public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
    //-- if namespace is "http://www.WhiteSugerCompany.com/ws"
    //-- map it to "ws"
    if( "http://www.WhiteSugerCompany.com/ws".equals(namespaceUri) )
      return "ws";
 
    // otherwise just use the default suggestion.
    return suggestion;
  }
}
 


使用 NamespacePrefixMapper

接下來是在 Marshaller 中 設定要使用的 NamespacePrefixMapperImpl 如下

1
m.setProperty("com.sun.xml.bind.namespacePrefixMapper",new NamespacePrefixMapperImpl());


只要加了這一行, 並且有實作 NamespacePrefixMapper,

便可得到如下圖的輸出, 可以看到原本的 ns2 都變成 ws 了,



完整程式如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package org.iii.test.jaxb.test;
 
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
 
import org.iii.test.jaxb.whitesuger.Suger;
import org.iii.test.jaxb.whitesuger.ObjectFactory;
 
public class Test {
 
  public static void main(String args[]){
 
    try{
      //-- get context instance
      JAXBContext ctx = JAXBContext.newInstance("org.iii.test.jaxb.whitesuger");
      ObjectFactory of = new ObjectFactory();
 
      //-- create Suger object
      Suger ws = of.createSuger();
 
      //-- set values
      ws.setColor("Cream color");
      ws.setSweetness((byte)20);
 
      //-- convert ws to JAXBElement
      JAXBElement<Suger> je = of.createSugers(ws);
      //-- get Marshaller
      Marshaller m = ctx.createMarshaller();
 
      StringWriter xml = new StringWriter();
      //-- marshal JAXBElement into StringWriter with format and mapped prefix
      m.setProperty("com.sun.xml.bind.namespacePrefixMapper",new NamespacePrefixMapperImpl());
      m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
      m.marshal(je, xml);
      System.err.println(xml.toString());
 
    }
    catch (Exception e){
      e.printStackTrace();
    }
  }
}




3. References



官方文件

http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/2.0/jaxb/vendorProperties.html


reply to postreply to post
作者 Re:JAXB 新手學習筆記 [Re:benbai123]
benbai123





發文: 25
積分: 0
於 2011-02-22 13:52 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
第四篇 -- JAXB xsd 中使用其它文件的內容



1. 前言



我們可以在一份 schema 中, 使用在其它份 schema 中定義好的部份,

大致可分為三種情形, 分別為 都沒有 name space,

有相同的 name space, 及在不同的 name space,

以下說明



2. 都沒有 name space



假設有三份 schema 分別為 白糖 ( WhiteSuger ) , 飲料基底 ( DrinkBase ),

及 白糖水 ( WhiteSugerWater ) 如下圖,



其中 白糖 的 schema 如下,

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 
  <xsd:complexType name="suger">
    <xsd:sequence>
      <xsd:element name="color" type="xsd:string"/>
      <xsd:element name="sweetness" type="xsd:byte"/>
    </xsd:sequence>
  </xsd:complexType>
 
</xsd:schema>


飲料基底 的 schema 如下

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 
  <xsd:complexType name="water">
    <xsd:sequence>
      <xsd:element name="hardness" type="xsd:byte"/>
      <xsd:element name="ph" type="xsd:byte"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>
 


則在 白糖水 中, 可如下使用以上兩個 schema

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 
  <xsd:include schemaLocation="../WhiteSuger/WhiteSuger.xsd"/>
  <xsd:include schemaLocation="DrinkBase.xsd"/>
 
  <!-- drink type -->
  <xsd:complexType name="whiteSugerWaterType">
    <xsd:sequence>
      <xsd:element name="sugerInDrink" type="suger"/>
      <xsd:element name="waterInDrink" type="water"/>
      <xsd:element name="sugerGram" type="xsd:int"/>
      <xsd:element name="waterMl" type="xsd:int"/>
    </xsd:sequence>
  </xsd:complexType>
 
  <!-- drink element -->
  <xsd:element name="whiteSugerWater" type="whiteSugerWaterType"/>
 
</xsd:schema>


說明

可以看出在 白糖 及 飲料基底 之中都沒有宣告 targetNamespace,

則此時在 白糖水 中也不能宣告 targetNamespace,

只要以 xsd:include 指定要使用的 schema 位置即可使用其它 schema 中的項目,



3. 有相同或不同的 name space



假設 白糖 的 schema 開頭宣告改為如下

1
2
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://www.WhiteSuger.com/ws">


而 飲料基底 的 schema 開頭宣告改為如下

1
2
3
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://www.Drink.com/dr">
 


則在白糖水中, 便要改用以下的方式使用其它兩份 schema

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:ws="http://www.WhiteSuger.com/ws"
  xmlns:dr="http://www.Drink.com/dr"
  targetNamespace="http://www.Drink.com/dr">
 
  <xsd:import namespace="http://www.WhiteSuger.com/ws" schemaLocation="../WhiteSuger/WhiteSuger.xsd"/>
  <xsd:include schemaLocation="DrinkBase.xsd"/>
 
  <!-- drink type -->
  <xsd:complexType name="whiteSugerWaterType">
    <xsd:sequence>
      <xsd:element name="sugerInDrink" type="ws:suger"/>
      <xsd:element name="waterInDrink" type="dr:water"/>
      <xsd:element name="sugerGram" type="xsd:int"/>
      <xsd:element name="waterMl" type="xsd:int"/>
    </xsd:sequence>
  </xsd:complexType>
 
  <!-- drink element -->
  <xsd:element name="whiteSugerWater" type="dr:whiteSugerWaterType"/>
 
</xsd:schema>


說明

可以看到 白糖 宣告了

1
targetNamespace="http://www.WhiteSuger.com/ws"


而飲料基底 宣告了

1
targetNamespace="http://www.Drink.com/dr">


則此時 白糖水 就一定要宣告一個 name space, 可以與前面兩者相同,

也可以另外宣告一個新的,

在這裡我們宣告為和 飲料基底 相同的 name space,

而在 白糖水 的 schema 中, 開頭宣告的部份便得增加宣告

1
xmlns:xxx="ooo",


定義這一份 schema 中使用到的其它 schema 的 name space 及對應的 prefix,

而若 白糖水 本身有獨立的一個 name space, 自己有定義 type 並有 element 參照的話,

也需要宣告自己的那一份,

而在下面引入的話份, 可以看到因為 白糖水 及 飲料基底 有相同的 name space,

便同樣用
1
xsd:includ
的方式, 而 白糖水 和 白糖 的 namespace 不同,

則得改用
1
xsd:import
, 並定義 namespace 與 schema 的對應,

而在下方使用的部份, 則需加上在開頭宣告時的 prefix:

( 其實也可將
1
xmlns:dr="http://www.Drink.com/dr"


改為

1
xmlns="http://www.Drink.com/dr"
, 使用時去掉
1
dr:
的部份,

但定義較不明確, 不建議 )

測試程式及執行結果分別如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package org.iii.test.jaxb.test;
 
import java.io.StringReader;
import java.io.StringWriter;
 
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
 
import org.iii.test.jaxb.drink.ObjectFactory;
import org.iii.test.jaxb.drink.Suger;
import org.iii.test.jaxb.drink.Water;
import org.iii.test.jaxb.drink.WhiteSugerWaterType;
 
public class Test {
 
  public static void main(String args[]){
 
    try{
      //-- get context instance
      JAXBContext ctx = JAXBContext.newInstance("org.iii.test.jaxb.drink");
      ObjectFactory of = new ObjectFactory();
 
      //-- create WhiteSugerWater
      WhiteSugerWaterType wswt = of.createWhiteSugerWaterType();
      //-- create suger for WhiteSugerWater
      Suger sg = of.createSuger();
      //-- create water for WhiteSugerWater
      Water wt = of.createWater();
 
      //-- set suger property
      sg.setColor("Creem color");
      sg.setSweetness((byte)20);
 
      //-- set water property
      wt.setHardness((byte)15);
      wt.setPh((byte)7);
 
      //-- set WhiteSugerWater property
      wswt.setSugerInDrink(sg);
      wswt.setWaterInDrink(wt);
      wswt.setSugerGram(60);
      wswt.setWaterMl(700);
 
      //-- convert wswt to JAXBElement
      JAXBElement<WhiteSugerWaterType> je = of.createWhiteSugerWater(wswt);
      //-- get Marshaller
      Marshaller m = ctx.createMarshaller();
 
      StringWriter xml = new StringWriter();
      String xmlString = "";
      //-- marshal JAXBElement into StringWriter with mapped prefix
      m.setProperty("com.sun.xml.bind.namespacePrefixMapper",new NamespacePrefixMapperImpl());
      m.marshal(je, xml);
      xmlString = xml.toString();
 
      //-- clear StringWriter
      xml.getBuffer().setLength(0);
      //-- marshal JAXBElement into StringWriter with format and mapped prefix
      m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
      m.marshal(je, xml);
      System.err.println(xml.toString());
 
      //-- get unmarshaller
      Unmarshaller um = ctx.createUnmarshaller();
      //-- unmarshal xml string to JAXB element
      JAXBElement<WhiteSugerWaterType> root = (JAXBElement)um.unmarshal(new StreamSource(new StringReader(
        xmlString)));
 
      WhiteSugerWaterType wswt2 = root.getValue();
 
      System.err.println(" suger in drink : " + wswt2.getSugerGram() + " g");
      System.err.println(" water in drink : " + wswt2.getWaterMl() + " ml");
    }
    catch (Exception e){
      e.printStackTrace();
    }
  }
}






4. References



很詳盡的資料

http://www.datypic.com/books/defxmlschema/chapter04.html


reply to postreply to post
作者 Re:JAXB 新手學習筆記 [Re:benbai123]
benbai123





發文: 25
積分: 0
於 2011-02-22 14:02 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
第五篇 -- 使用 Name space 解決名稱衝突



1. 關於名稱衝突



假設我們想要以 白糖, 黑糖 來製作 混合糖水,

因此 白糖公司 與 黑糖公司 都提供了一份自己的 schema,

都沒有 namespace, 而且都有個型態叫 suger,

則我們在使用 xjc 時就會看到如下圖的錯誤



而假若他們都有提供自己的 namespace, 我們便可以 namespace 加以區分,

則能得到如下的結果



oops~ 仍然有錯誤, 然而注意看可看出錯誤訊息為 suger 這個 class 已經有人用,

這表示 xjc 已經能分辨 WhiteSuger 及 BlackSuger 兩份 schema 裡的 suger,

但是在為 suger 生成 class 時, 無法在同一個地方生出兩份叫 suger 的 class,

錯誤訊息裡也很親切的說明要使用 class customization 來解決,

這將會在 第六篇 為同名型態生成不同 class -- Customizing JAXB Bindings 說明



2. References



提到衝突問題的討論

http://xsd.stylusstudio.com/2002Jun/post02016.htm


reply to postreply to post
作者 Re:JAXB 新手學習筆記 [Re:benbai123]
benbai123





發文: 25
積分: 0
於 2011-02-22 14:16 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
第六篇 -- 為同名型態生成不同 class - Customizing JAXB Bindings



1. 撰寫並使用 binding customization file



在 第五篇 -- 使用 Name space 解決名稱衝突 之中解決了名稱衝突的問題後,

但仍然有物件的衝突要處理, 處理物件的衝突,

就要使用 customization JAXB bindings,

以下用外部檔案方式為例,

binding 檔案內容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<jaxb:bindings version="2.0"
  xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
 
  <!-- class WhiteSuger for "suger" in WhiteSuger.xsd -->
  <jaxb:bindings schemaLocation="WhiteSuger/WhiteSuger.xsd"
    node="//xs:complexType[@name='suger']">
    <jaxb:class name="WhiteSuger"/>
  </jaxb:bindings>
 
  <!-- class BlackSuger for "suger" in BlackSuger.xsd -->
  <jaxb:bindings schemaLocation="BlackSuger/BlackSuger.xsd"
    node="//xs:complexType[@name='suger']">
    <jaxb:class name="BlackSuger"/>
  </jaxb:bindings>
 
</jaxb:bindings>


檔案位置如下圖



則進行 xjc 時以 -b 指定 binding 檔案, 指令如下

1
C:\Program Files\Java\jdk1.6.0_21\bin>xjc -b xmlSchema\customBinding.xml -p org.iii.test.jaxb.drink xmlSchema\Drink\MixedSugerWater.xsd


即可生成物件, 將之放入專案中如下



其中各 xsd 檔內容如下

WhiteSuger.xsd

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://www.WhiteSuger.com/ws">
 
  <xsd:complexType name="suger">
    <xsd:sequence>
      <xsd:element name="color" type="xsd:string"/>
      <xsd:element name="sweetness" type="xsd:byte"/>
    </xsd:sequence>
  </xsd:complexType>
 
</xsd:schema>


BlackSuger.xsd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://www.BlackSuger.com/bs">
 
  <xsd:complexType name="suger">
    <xsd:sequence>
      <xsd:element name="color" type="xsd:string"/>
      <xsd:element name="aroma" type="xsd:string"/>
      <xsd:element name="sweetness" type="xsd:byte"/>
    </xsd:sequence>
  </xsd:complexType>
 
</xsd:schema>
 


MixedSugerWater.xsd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:ws="http://www.WhiteSuger.com/ws"
  xmlns:bs="http://www.BlackSuger.com/bs"
  xmlns:dr="http://www.Drink.com/dr"
  targetNamespace="http://www.Drink.com/dr">
 
  <xsd:include schemaLocation="DrinkBase.xsd"/>
  <xsd:import namespace="http://www.WhiteSuger.com/ws" schemaLocation="../WhiteSuger/WhiteSuger.xsd"/>
  <xsd:import namespace="http://www.BlackSuger.com/bs" schemaLocation="../BlackSuger/BlackSuger.xsd"/>
 
  <!-- drink type -->
  <xsd:complexType name="mixedSugerWaterType">
    <xsd:sequence>
      <xsd:element name="whiteSugerInDrink" type="ws:suger"/>
      <xsd:element name="blackSugerInDrink" type="bs:suger"/>
      <xsd:element name="waterInDrink" type="dr:water"/>
      <xsd:element name="whiteSugerGram" type="xsd:int"/>
      <xsd:element name="blackSugerGram" type="xsd:int"/>
      <xsd:element name="waterMl" type="xsd:int"/>
    </xsd:sequence>
  </xsd:complexType>
 
  <!-- drink element -->
  <xsd:element name="mixedSugerWater" type="dr:mixedSugerWaterType"/>
 
</xsd:schema>
 


以下為測試程式及結果截圖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package org.iii.test.jaxb.test;
 
import java.io.StringReader;
import java.io.StringWriter;
 
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
 
import org.iii.test.jaxb.drink.BlackSuger;
import org.iii.test.jaxb.drink.MixedSugerWaterType;
import org.iii.test.jaxb.drink.ObjectFactory;
import org.iii.test.jaxb.drink.Water;
import org.iii.test.jaxb.drink.WhiteSuger;
 
public class Test {
 
  public static void main(String args[]){
 
    try{
      //-- get context instance
      JAXBContext ctx = JAXBContext.newInstance("org.iii.test.jaxb.drink");
      ObjectFactory of = new ObjectFactory();
 
      //-- create MixedSugerWaterType
      MixedSugerWaterType mswt = of.createMixedSugerWaterType();
      //-- create whiteSuger for MixedSugerWaterType
      WhiteSuger ws = of.createWhiteSuger();
      //-- create water for MixedSugerWaterType
      Water wt = of.createWater();
      //-- create blackSuger for MixedSugerWaterType
      BlackSuger bg = of.createBlackSuger();
 
      //-- set white suger property
      ws.setColor("Creem color");
      ws.setSweetness((byte)20);
 
      //-- set water property
      wt.setHardness((byte)15);
      wt.setPh((byte)7);
 
      //-- set black suger property
      bg.setAroma("Muscat");
      bg.setColor("Dark Brown");
      bg.setSweetness((byte)20);
 
      //-- set MixedSugerWaterType property
      mswt.setWhiteSugerInDrink(ws);
      mswt.setWaterInDrink(wt);
      mswt.setBlackSugerInDrink(bg);
      mswt.setWhiteSugerGram(15);
      mswt.setBlackSugerGram(15);
      mswt.setWaterMl(700);
 
      //-- convert mswt to JAXBElement
      JAXBElement<MixedSugerWaterType> je = of.createMixedSugerWater(mswt);
      //-- get Marshaller
      Marshaller m = ctx.createMarshaller();
 
      StringWriter xml = new StringWriter();
      String xmlString = "";
      //-- marshal JAXBElement into StringWriter with mapped prefix
      m.setProperty("com.sun.xml.bind.namespacePrefixMapper",new NamespacePrefixMapperImpl());
      m.marshal(je, xml);
      xmlString = xml.toString();
 
      //-- clear StringWriter
      xml.getBuffer().setLength(0);
      //-- marshal JAXBElement into StringWriter with format and mapped prefix
      m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
      m.marshal(je, xml);
      System.err.println(xml.toString());
 
      //-- get unmarshaller
      Unmarshaller um = ctx.createUnmarshaller();
      //-- unmarshal xml string to JAXB element
      JAXBElement<MixedSugerWaterType> root = (JAXBElement)um.unmarshal(new StreamSource(new StringReader(
        xmlString)));
 
      MixedSugerWaterType wswt2 = root.getValue();
 
      System.err.println(" white suger in drink : " + wswt2.getWhiteSugerGram() + " g");
      System.err.println(" black suger in drink : " + wswt2.getBlackSugerGram() + " g");
      System.err.println(" water in drink : " + wswt2.getWaterMl() + " ml");
    }
    catch (Exception e){
      e.printStackTrace();
    }
  }
}






2. References



官網, 內容很多但有點零碎, 查東西用

http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc/JAXBUsing4.html

fusesource, 可以看到比較完整的用法

http://fusesource.com/docs/esb/4.3/cxf_jaxws/JAXWSCustomTypeMappingOverview.html


reply to postreply to post
作者 Re:JAXB 新手學習筆記 [Re:benbai123]
benbai123





發文: 25
積分: 0
於 2011-02-22 14:33 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
第七篇 -- 分門別類 - customize package bindings



1. 前言



在 第六篇 -- 為同名型態生成不同 class - Customizing JAXB Bindings 中,

我們以自訂 class 名的方式將兩個 suger 型態分別生成不同的 class,

然而所有的 class 都在 drink 之下,

有時我們可能會希望不同類型的 class 可以分別在不同的 package,

這時就要做 package 的綁定,



2. 綁定不同的 schema 到不同的 package



首先改寫 binding file 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<jaxb:bindings version="2.0"
  xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
 
  <!-- package for WhiteSuger schema and class for "suger" in WhiteSuger.xsd -->
  <jaxb:bindings schemaLocation="WhiteSuger/WhiteSuger.xsd"
    node="/xs:schema">
    <jaxb:schemaBindings>
      <jaxb:package name="org.iii.test.jaxb.suger"/>
    </jaxb:schemaBindings>
    <jaxb:bindings node="//xs:complexType[@name='suger']">
      <jaxb:class name="WhiteSuger"/>
    </jaxb:bindings>
  </jaxb:bindings>
 
  <!-- package for BlackSuger schema and class for "suger" in BlackSuger.xsd -->
  <jaxb:bindings schemaLocation="BlackSuger/BlackSuger.xsd"
    node="/xs:schema">
    <jaxb:schemaBindings>
      <jaxb:package name="org.iii.test.jaxb.suger"/>
    </jaxb:schemaBindings>
    <jaxb:bindings node="//xs:complexType[@name='suger']">
      <jaxb:class name="BlackSuger"/>
    </jaxb:bindings>
  </jaxb:bindings>
 
  <!-- package for mixed suger water schema -->
  <jaxb:bindings schemaLocation="Drink/MixedSugerWater.xsd"
    node="/xs:schema">
    <jaxb:schemaBindings>
      <jaxb:package name="org.iii.test.jaxb.drink"/>
    </jaxb:schemaBindings>
  </jaxb:bindings>
 
</jaxb:bindings>


接下來以下面的指令生成物件, 這時便不能用 -p 指定 package,

否則 binding files 裡針對 package 的設定會被忽略

1
C:\Program Files\Java\jdk1.6.0_21\bin>xjc -b xmlSchema\customBinding.xml xmlSchema\Drink\MixedSugerWater.xsd


執行結果如下圖,



將生成的檔案, 放入專案如下



測試程式也需要修改, 程式碼及執行結果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package org.iii.test.jaxb.test;
 
import java.io.StringReader;
import java.io.StringWriter;
 
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
 
import org.iii.test.jaxb.drink.MixedSugerWaterType;
import org.iii.test.jaxb.drink.ObjectFactory;
import org.iii.test.jaxb.drink.Water;
import org.iii.test.jaxb.suger.BlackSuger;
import org.iii.test.jaxb.suger.WhiteSuger;
 
public class Test {
 
  public static void main(String args[]){
 
    try{
      //-- get context instance
      JAXBContext ctx = JAXBContext.newInstance("org.iii.test.jaxb.drink");
      //-- ObjectFactory for drink
      ObjectFactory of = new ObjectFactory();
      //-- ObjectFactory for suger
      org.iii.test.jaxb.suger.ObjectFactory sof = new org.iii.test.jaxb.suger.ObjectFactory();
 
      //-- create MixedSugerWaterType
      MixedSugerWaterType mswt = of.createMixedSugerWaterType();
      //-- create whiteSuger for MixedSugerWaterType
      WhiteSuger ws = sof.createWhiteSuger();
      //-- create water for MixedSugerWaterType
      Water wt = of.createWater();
      //-- create blackSuger for MixedSugerWaterType
      BlackSuger bg = sof.createBlackSuger();
 
      //-- set white suger property
      ws.setColor("Creem color");
      ws.setSweetness((byte)20);
 
      //-- set water property
      wt.setHardness((byte)15);
      wt.setPh((byte)7);
 
      //-- set black suger property
      bg.setAroma("Muscat");
      bg.setColor("Dark Brown");
      bg.setSweetness((byte)20);
 
      //-- set MixedSugerWaterType property
      mswt.setWhiteSugerInDrink(ws);
      mswt.setWaterInDrink(wt);
      mswt.setBlackSugerInDrink(bg);
      mswt.setWhiteSugerGram(15);
      mswt.setBlackSugerGram(15);
      mswt.setWaterMl(700);
 
      //-- convert mswt to JAXBElement
      JAXBElement<MixedSugerWaterType> je = of.createMixedSugerWater(mswt);
      //-- get Marshaller
      Marshaller m = ctx.createMarshaller();
 
      StringWriter xml = new StringWriter();
      String xmlString = "";
      //-- marshal JAXBElement into StringWriter with mapped prefix
      m.setProperty("com.sun.xml.bind.namespacePrefixMapper",new NamespacePrefixMapperImpl());
      m.marshal(je, xml);
      xmlString = xml.toString();
 
      //-- clear StringWriter
      xml.getBuffer().setLength(0);
      //-- marshal JAXBElement into StringWriter with format and mapped prefix
      m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
      m.marshal(je, xml);
      System.err.println(xml.toString());
 
      //-- get unmarshaller
      Unmarshaller um = ctx.createUnmarshaller();
      //-- unmarshal xml string to JAXB element
      JAXBElement<MixedSugerWaterType> root = (JAXBElement)um.unmarshal(new StreamSource(new StringReader(
        xmlString)));
 
      MixedSugerWaterType wswt2 = root.getValue();
 
      System.err.println(" white suger in drink : " + wswt2.getWhiteSugerGram() + " g");
      System.err.println(" black suger in drink : " + wswt2.getBlackSugerGram() + " g");
      System.err.println(" water in drink : " + wswt2.getWaterMl() + " ml");
    }
    catch (Exception e){
      e.printStackTrace();
    }
  }
}






3. References



stackoverflow 上的一個範例

http://stackoverflow.com/questions/1881712/is-it-possible-to-use-jaxb-to-map-from-schema-to-a-java-util-map


reply to postreply to post
作者 Re:JAXB 新手學習筆記 [Re:benbai123]
benbai123





發文: 25
積分: 0
於 2011-02-22 14:54 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
第八篇 -- 以 Ant 使用 JAXB xjc



1. 以 Ant 轉換 schema 為 java 檔



Ant 也可以用來將 xjc 的功能自動化,

讓我們不必再重覆 搬移 schema 檔案 下指令 搬回物件檔案 這些動作,

環境說明

這裡以 第七篇 -- 分門別類 - customize package bindings 的情況為例,

我們要撰寫一個 build.xml, 準備好 xsd 檔及 binding file,

執行它後就會把 java 檔 產生出來放到正確的位置

build.xml 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="BIG5"?>
 
<project name="genXsdClasses" default="genClass" basedir=".">
  <!-- 上面一行是 project 的進入點  -->
 
  <!-- Define JAXB home, 請依個人檔案路徑修改 -->
  <property name="jaxb.home" value="C:/java/jaxb-ri-20101209" />
 
  <!-- Define class path, 同上 -->
  <path id="classpath">
    <pathelement path="src" />
    <pathelement path="classes" />
    <pathelement path="schemas" />
    <fileset dir="lib" includes="*.jar" />
    <!-- this example only need this one below, above 4 just for example -->
    <fileset dir="${jaxb.home}" includes="lib/*.jar" />
  </path>
 
  <!-- This maps XJCTask to an Ant task named xjc.
    Refer to any of the build.xml under jaxb.home/samples for detail. -->
  <taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask">
    <classpath refid="classpath" />
  </taskdef>
 
  <!-- Generate .java files by defined task xjc. -->
  <target name="genClass">
    <xjc destdir="src">
      <schema dir="xmlSchema/drink" includes="MixedSugerWater.xsd" />
      <binding dir="xmlSchema" includes="customBinding.xml" />
    </xjc>
 
  </target>
 
</project>


以下為執行前及執行後的截圖

首先是執行前 src 下的情形



執行後將 src 重新整理後的情形 以及執行的訊息



寫得更完整, 加入清除舊檔的部份

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="BIG5"?>
 
<project name="genXsdClasses" default="genClass" basedir=".">
  <!-- 上面一行是 project 的進入點  -->
 
  <!-- Define JAXB home, 請依個人檔案路徑修改 -->
  <property name="jaxb.home" value="C:/java/jaxb-ri-20101209" />
  <!-- Define source and destnation, 同上 -->
 
  <!-- Define class path -->
  <path id="classpath">
    <pathelement path="src" />
    <pathelement path="classes" />
    <pathelement path="schemas" />
    <fileset dir="lib" includes="*.jar" />
    <!-- this example only need this one below, above 4 just for example -->
    <fileset dir="${jaxb.home}" includes="lib/*.jar" />
  </path>
 
  <!-- This maps XJCTask to an Ant task named xjc.
    Refer to any of the build.xml under jaxb.home/samples for detail. -->
  <taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask">
    <classpath refid="classpath" />
  </taskdef>
 
  <!-- clear old files -->
  <target name="clean">
    <delete dir="src/org/iii/test/jaxb/drink" />
    <delete dir="src/org/iii/test/jaxb/suger" />
  </target>
 
  <!-- Generate .java files by defined task xjc. -->
  <target name="genClass" depends="clean">
    <xjc destdir="src">
      <schema dir="xmlSchema/drink" includes="MixedSugerWater.xsd" />
      <binding dir="xmlSchema" includes="customBinding.xml" />
    </xjc>
 
  </target>
 
</project>


執行結果如下





2. References



官網

http://jaxb.java.net/jaxb20-ea/docs/xjcTask.html

注意, Parameter Attributes 表格中的 target 應改為 destdir 才能動


reply to postreply to post
» JWorld@TW »  Java & XML、Web Service

reply to topicthreaded modego to previous topicgo to next topic
  已讀文章
  新的文章
  被刪除的文章
Jump to the top of page

JWorld@TW 本站商標資訊

Powered by Powerful JuteForum® Version Jute 1.5.8