我有一个XML文件,如下所示:
<root>
<item>
<id>my id</id>
<type>my type</id>
<key1>value1</key1>
<key2>value1</key2>
<key3>value1</key3>
</item>
<item>
<id>my id</id>
<type>my type</type>
<other-key1>value1</other-key1>
<other-key2>value1</other-key2>
</item>
(...)
</root>
我想在这样的类上解析 XML:
public class Item {
private String id;
private String type;
private Map<String, String> values;
}
其中,id 节点和类型节点映射到具有相同名称的属性,并且项目内的所有其他节点都添加到映射中。
我尝试编写一个带有注释XmlJavaTypeAdapter和XmlAnyElement的类,但这并没有按照我预期的方式工作:
(...)
public class Item {
@XmlElement
private String id;
@XmlElement
private String type;
@XmlAnyElement
@XmlJavaTypeAdapter(MapAdapter.class)
private Map<String, String> values;
}
public class MapAdapter extends XmlAdapter<Object, Map<String, String>> {
@Override
public Object marshal(Map<String, String> v) throws Exception {
}
@Override
public Map<String, String> unmarshal(Object v) throws Exception {
// v is a node instead an array of nodes.
// I want to get an array of nodes to convert them to a map.
//
// eg:
//
// key1 -> value1
// key2 -> value2
// key3 -> value3
//
}
知道我怎么能得到这个吗?
更新
澄清我的问题:
我的问题是我想在地图中解封的元素不在包装器中,而是与同一级别的其他元素混合。
我尝试使用 XmlAnyElement 和 XmlJavaTypeAdapter 来获取所有剩余元素的映射。但是,这些注释有一个隐式顺序,我得到的是使用适配器解析的元素集合:
XmlAnyElement 查找每个剩余的元素,使用适配器对其进行分析并将结果添加到集合中。
有什么办法可以扭转这种情况吗?
我想获取所有剩余元素的集合,然后使用 XmlAdapter 解析该集合以获取映射。
像你一样,我没有成功写出XmlAdapter
. 但还有另一种可能的方法:
在你的Item
类中声明一个用@XmlAnyElement
注释的List<Element>
, 以便 JAXB 将其用于编组/解组。
但是你想要一个Map<String, String>
.因此,您也声明, 但用@XmlTransient
注释,以便JAXB不会将其用于编组/解组。
最后实现一个私有方法afterUnmarshal(Unmarshaller unmarshaller, Object parent)
您将内容从List<Element>
铲到Map<String, String>
的地方. 如中所述 取消封送事件回调 JAXB 将在适当的时候调用此方法。
如果需要编写 XML 文件 您可能还需要私有方法beforeMmarshal(Marshaller marshaller)
您将内容物从Map<String, String>
铲回List<Element>
. 如中所述 封送事件回调 JAXB 将在适当的时候调用此方法。
public class Item {
@XmlElement
private String id;
@XmlElement
private String type;
@XmlAnyElement
private List<Element> otherElements;
@XmlTransient // don't participate in JAXB marshalling/unmarshalling
private Map<String, String> values;
@SuppressWarnings("unused") // called only by JAXB
private void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
values = new HashMap<>();
if (otherElements != null) {
for (Element element : otherElements) {
String key = element.getNodeName();
String value = element.getFirstChild().getNodeValue();
values.put(key, value);
}
}
}
}