2015-04-08 17 views
0

我正嘗試使用simpleXML將XML文件反序列化爲Java對象。一切工作正常,直到我不得不使用ElementMap。 這是我的XML文件的一部分:將XML元素反序列化爲Java地圖

<piece composer="Me" date="Yesterday" title="Important work"> 
    <editions> 
     <edition name="My Name" date="2015" description="A single page"> 
      <pages> 
       <page fileName="page01.jpg" /> 
      </pages> 
     </edition> 
     <edition name="My Name again" date="2015" description="Another single page"> 
      <pages> 
       <page fileName="page01.jpg" /> 
      </pages> 
     </edition> 
    </editions> 
    <layers> 
     <layer name="Annotations" color="#FF0000" description="Empty" id="anno" /> 
     <layer name="Information" color="#00FF00" description="Empty" id="info" /> 
    </layers> 
</piece> 

相應的Java類看起來是這樣的:

@Root 
public class Piece { 
    @Attribute 
    private String composer; 
    @Attribute 
    private String title; 
    @Attribute 
    private String date; 

    @ElementList 
    private List<Edition> editions; 

    @ElementMap(key = "id", attribute = true) // Relevant 
    private Map<String, Layer> layers;  // Lines 

    public static Piece loadFromAsset(Context context, String fileName) throws Exception { 
     Serializer serial = new Persister(); 
     return serial.read(Piece.class, context.getResources().getAssets().open(fileName)); 
    } 
} 

最後層類:

public class Layer { 
    @Attribute 
    private String id; 
    @Attribute 
    private String name; 
    @Attribute 
    private String description; 
    @Attribute 
    private String color; 
} 

加載XML文件後地圖包含兩個鍵,但它們都指向null而不是實際的層對象。

回答

0

我不SimpleFrawmerow用戶,所以我不能保證它會工作,但你或許應該指定ElementMap映射的更多attirbutes:

@ElementMap(key = "id", attribute = true, keyType=String.class 
      ,valueType=Layer.class) 

如果它不能幫助你必須處理列表給自己映射轉換。問題是你的xml實際上包含了一個Layer元素而不是map的列表(沒有鍵/值元素對)。

您可以添加到你的作品類字段來存儲列表並在地圖領域構建的使用它:

class Piece { 
    ... 
    @ElementList //only for solution B, for a do not use this annotation 
    List<Layer> layers; 

    @Transient //importatnt as it does not go into xml directly 
    private Map<String, Layer> layersMap;   
} 

現在有兩種做法:

A)使用getter和setter層列表,並且這些方法內構建體所需的列表地圖內容:

@ElementList 
    public void setLayers(Collection<Layer> layers) { 
     layersMap = new HashMap<>(); 
     for (Layer l : layers) layersMap.put(l.getId(),l); 
    }   

    @ElementList 
    public Collection<Layer> getLayers() { 
     return layersMap.values(); 
    } 

B)使用串行化的生命週期的機制(堅持和提交註釋)。在序列化之前調用的一種方法中,您使用另一箇中的地圖創建列表內容,然後使用列表值填充地圖。我個人比較喜歡getters/setters,因爲你可以隱藏'layers'元素。

class Piece { 
.... 
@Commit 
public void prepareMap() { 
    layersMap = new HashMap<>(); 
    for (Layer l : layers) layersMap.put(l.getId(),l); 
} 

@Persist 
public void prepareList() { 
    layers = new ArrayList<>(); 
    layers.addAll(layersMap.values()); 
} 
} 

最後,您可以使用Converter來完全控制過程,但我相信上面的內容更容易,更簡潔。

+0

非常感謝!我用一種幾乎完全相同的語法結束了使用方法A的過程。 其他解決方案並不少,但簡單美觀。 ;-) – sonovice