将 XML 元素反序列化为 Java 映射
Deserialize XML Elements to Java Map
我正在尝试使用简单XML 将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>
对应的JavaClass是这样的:
@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));
}
}
最后层 Class:
public class Layer {
@Attribute
private String id;
@Attribute
private String name;
@Attribute
private String description;
@Attribute
private String color;
}
加载 XML 文件后,地图包含两个键,但它们都指向 null
而不是实际的图层对象。
我不是 SimpleFrawmerow 用户,所以我不保证它会起作用,但您可能应该指定 ElementMap 映射的更多属性:
@ElementMap(key = "id", attribute = true, keyType=String.class
,valueType=Layer.class)
如果没有帮助,您必须自己处理列表到地图的转换。问题是您的 xml 实际上包含 Layer 元素列表而不是地图(没有成对的键/值元素)。
您可以添加到您的 Piece class 额外字段来存储该列表并使用它构建地图字段:
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) 对图层列表使用getters和setters,方法内部根据需要构建列表地图内容:
@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 注解)。在序列化之前调用的一种方法中,您使用地图创建列表内容,而在另一种方法中,您使用列表值填充地图。我个人更喜欢它而不是 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 来完全控制这个过程了,但我相信上面的方法更简单也更简洁。
我正在尝试使用简单XML 将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>
对应的JavaClass是这样的:
@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));
}
}
最后层 Class:
public class Layer {
@Attribute
private String id;
@Attribute
private String name;
@Attribute
private String description;
@Attribute
private String color;
}
加载 XML 文件后,地图包含两个键,但它们都指向 null
而不是实际的图层对象。
我不是 SimpleFrawmerow 用户,所以我不保证它会起作用,但您可能应该指定 ElementMap 映射的更多属性:
@ElementMap(key = "id", attribute = true, keyType=String.class
,valueType=Layer.class)
如果没有帮助,您必须自己处理列表到地图的转换。问题是您的 xml 实际上包含 Layer 元素列表而不是地图(没有成对的键/值元素)。
您可以添加到您的 Piece class 额外字段来存储该列表并使用它构建地图字段:
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) 对图层列表使用getters和setters,方法内部根据需要构建列表地图内容:
@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 注解)。在序列化之前调用的一种方法中,您使用地图创建列表内容,而在另一种方法中,您使用列表值填充地图。我个人更喜欢它而不是 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 来完全控制这个过程了,但我相信上面的方法更简单也更简洁。