要映射的 JAXB 节点



我有一个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);
}
}
}
}

最新更新