将XML元素反序列化为Java Map

时间:2015-04-08 09:01:41

标签: java android xml xml-deserialization simple-framework

我正在尝试使用simpleXML将XML文件反序列化为Java对象。一切都很好,直到我不得不使用ElementMap。 这是我的XML文件的一部分:

<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));
    }
}

最后是Layer Class:

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

加载XML文件后,Map包含两个键,但它们都指向null而不是实际的图层对象。

1 个答案:

答案 0 :(得分:0)

我不是SimpleFrawmerow用户,所以我不保证它会起作用,但你应该指定更多的ElementMap映射的地址:

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

如果没有帮助,您必须自己处理列表以进行地图转换。问题是你的xml实际上是一个Layer元素列表而不是map(没有键/值元素对)。

您可以添加Piece类额外字段来存储该列表,并使用它构建地图字段:

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)使用序列化生命周期机制(Persist和Commit annotations)。在序列化之前调用的一个方法中,使用另一个中的映射创建列表内容,使用列表值填充映射。我个人更喜欢它,因为你可以隐藏'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());
} 
} 

最后,您可以使用转换器完全控制该过程,但我相信上述内容更容易,更简洁。