用于映射

时间:2017-08-09 10:56:47

标签: java xml 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解析集合以获取地图。

1 个答案:

答案 0 :(得分:1)

和你一样,我没有成功写出XmlAdapter。 但还有另一种可能的方法:

Item班级中,声明List<Element>注明了@XmlAnyElement, 以便JAXB将其用于编组/解组。

但你想要一个Map<String, String>。因此你也宣布了, 但注释为@XmlTransient,以便JAXB不会将其用于编组/解组。

最后实现私有方法afterUnmarshal(Unmarshaller unmarshaller, Object parent) 您将内容从List<Element>铲到Map<String, String>。 如中所述 docs JAXB将在适当的时候调用此方法。

如果您需要编写XML文件 您可能还需要私有方法beforeMmarshal(Marshaller marshaller) 将内容从Map<String, String>铲回List<Element>。 如中所述 Unmarshal Event Callbacks 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);
            }
        }
    }

}