2012-08-14 48 views
3

映射我有這樣如何解組展開收藏與JAXB

<info> 
    <item key=1>value1</item> 
    <item key=2>value2</item> 
</info> 

一個XML文件,我想獲得一個綁定的類像這樣

class Info { 
    @XmlJavaTypeAdapter(MapAdapter.class) 
    private Map<Integer,Item> map; 

    public setMap... 
    public getMap... 
} 

class Item{ 
    @XmlAttribute 
    private Integer key; 

    @XmlValue 
    private String value; 

    //get,set method... 
} 

它的工作原理樂趣包裹場

<info> 
    <map> 
    <item key=1>value1</item> 
    <item key=2>value2</item> 
    </map> 
</info> 

當我擺脫<map>,它失敗,沒有錯誤。 MapAdapter沒有工作。

public Map<Integer, Item> unmarshal(MapType myMapType) throws Exception { 
    HashMap<Integer, Item> hashMap = new HashMap<Integer, Item>(); 
    for (Item myEntryType : myMapType.getEntry()) { 
     hashMap.put(myEntryType.getKey(), myEntryType); 
    } 
    return hashMap; 
} 

myMapType始終爲空。

我該如何處理這個XML?

回答

1

我的解決辦法是,

  1. 離開地圖作爲@XmlTransient
  2. 創建另一個屬性

完全Maven化項目是在這裏http://code.google.com/p/jinahya/source/browse/trunk/com.googlecode.jinahya/stackoverflow

@XmlRootElement 
@XmlAccessorType(XmlAccessType.NONE) 
public class Info { 

    @XmlElement(name = "item") 
    private List<Item> getItems() { 
     return new ArrayList<Item>(getMap().values()); 
    } 

    private void setItems(final List<Item> items) { 
     getMap().clear(); 
     for (Item item : items) { 
      getMap().put(item.getKey(), item); 
     } 
    } 

    public Map<Integer, Item> getMap() { 
     if (map == null) { 
      map = new HashMap<Integer, Item>(); 
     } 
     return map; 
    } 

    private Map<Integer, Item> map; 
} 

測試

@Test 
public void testXml() throws JAXBException { 

    final JAXBContext context = JAXBContext.newInstance(Info.class); 

    final Info marshall = new Info(); 
    marshall.getMap().put(1, Item.newInstance(1, "value1")); 
    marshall.getMap().put(2, Item.newInstance(2, "value2")); 

    final Marshaller marshaller = context.createMarshaller(); 
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); 

    final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 

    marshaller.marshal(marshall, baos); 
    System.out.println(new String(baos.toByteArray())); 

    final Unmarshaller unmarshaller = context.createUnmarshaller(); 

    final Info unmarshal = (Info) unmarshaller.unmarshal(
     new ByteArrayInputStream(baos.toByteArray())); 

    for (Item item : unmarshal.getMap().values()) { 
     System.out.println(item); 
    } 
} 

打印

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<info> 
    <item key="1">value1</item> 
    <item key="2">value2</item> 
</info> 

key=1&value=value1 
key=2&value=value2 
+0

好的解決方案,即使不需要XmlJavaTypeAdapter和其他任何依賴關係 – Foxswily 2012-08-16 02:03:49

+0

setItems永遠不會被調用,它使用getItems然後嘗試將元素添加到給定列表。 – 2017-06-13 12:40:15

1

您的InfoMap的裝修工。在你的例子中,它沒有提供超過地圖的價值。我看到兩個選擇:

  1. 刪除Info,移動你的map高達取代info用途。

  2. Info寫下您的@XmlJavaTypeAdapter而不是地圖。 有沒有編組/內部編組map - 你現在正在做什麼,只是把它提升一個層次。

+0

信息有一些更多元素/屬性在它 <信息ID = 「一些」 VER = 「1.0」?> VALUE1 VALUE2 Foxswily 2012-08-15 01:43:42

0

標識地圖成員。地圖成員上的@XmlValue註解可能有效。

+0

謝謝,但它不起作用。 @ XmlAttribute/@ XmlValue需要引用映射到XML中的文本的Java類型 – Foxswily 2012-08-15 01:42:16

0

備註:我是EclipseLink JAXB (MOXy)的領導者和JAXB (JSR-222)專家組的成員。

您可以利用MOXy的@XmlPath擴展來支持您的用例。

信息

package forum11956071; 

import java.util.Map; 
import javax.xml.bind.annotation.*; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 
import org.eclipse.persistence.oxm.annotations.XmlPath; 

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
class Info { 
    @XmlJavaTypeAdapter(MapAdapter.class) 
    @XmlPath(".") 
    private Map<Integer,String> map; 

} 

MapAdapter

package forum11956071; 

import java.util.*; 
import java.util.Map.Entry; 

import javax.xml.bind.annotation.*; 
import javax.xml.bind.annotation.adapters.XmlAdapter; 

public class MapAdapter extends XmlAdapter<MapAdapter.AdaptedMap, Map<Integer, String>>{ 

    public static class AdaptedMap { 
     public List<Item> item = new ArrayList<Item>(); 
    } 

    public static class Item { 
     @XmlAttribute Integer key; 
     @XmlValue String value; 
    } 
    @Override 
    public AdaptedMap marshal(Map<Integer, String> map) throws Exception { 
     AdaptedMap adaptedMap = new AdaptedMap(); 
     for(Entry<Integer, String> entry : map.entrySet()) { 
      Item item = new Item(); 
      item.key = entry.getKey(); 
      item.value = entry.getValue(); 
      adaptedMap.item.add(item); 
     } 
     return adaptedMap; 
    } 

    @Override 
    public Map<Integer, String> unmarshal(AdaptedMap adaptedMap) throws Exception { 
     Map<Integer, String> map = new HashMap<Integer, String>(); 
     for(Item item : adaptedMap.item) { 
      map.put(item.key, item.value); 
     } 
     return map; 
    } 

} 

jaxb.properties

要指定莫西爲您的JAXB提供者,你需要有一個名爲jaxb.properties文件日Ë同一個封裝領域模型中的以下項(請參見:http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory 

演示

package forum11956071; 

import java.io.File; 
import javax.xml.bind.*; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     JAXBContext jc = JAXBContext.newInstance(Info.class); 

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     File xml = new File("src/forum11956071/input.xml"); 
     Info info = (Info) unmarshaller.unmarshal(xml); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(info, System.out); 
    } 

} 

輸入。XML /輸出

<?xml version="1.0" encoding="UTF-8"?> 
<info> 
    <item key="1">value1</item> 
    <item key="2">value2</item> 
</info> 
+0

這真的很有用! THKS。但它需要一些新的依賴關係(特別是org.eclipse.persistence.core over 4M =。=「)。 – Foxswily 2012-08-16 01:53:02