首页 > 解决方案 > JAXB 将未定义的元素解组为 Map?

问题描述

我有一个要解组的 XML :

<?xml version="1.0" encoding="UTF-8"?>
<ROW id='1'>
   <MOBILE>9831138683</MOBILE>
   <A>1</A>
   <B>2</B>
</ROW>

我想将它映射到一个

import java.util.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ROW {

    @XmlPath(".")
    @XmlJavaTypeAdapter(MapAdapter.class)
    private Map<String, Integer> map = new HashMap<String, Integer>();

    @XmlAttribute
    private int id;
    @XmlElement(name = "MOBILE")
    private int mobileNo;

}

为此,我尝试了它使用的bdoughan博客@XmlVariableNode("key")

地图适配器:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.bind.annotation.adapters.XmlAdapter;

import org.eclipse.persistence.oxm.annotations.XmlVariableNode;

public class MapAdapter extends XmlAdapter<MapAdapter.AdaptedMap, Map<String, String>> {

    public static class AdaptedMap {

        @XmlVariableNode("key")
        List<AdaptedEntry> entries = new ArrayList<AdaptedEntry>();

    }

    public static class AdaptedEntry {

        @XmlTransient
        public String key;

        @XmlValue
        public String value;

    }

    @Override
    public AdaptedMap marshal(Map<String, String> map) throws Exception {
        AdaptedMap adaptedMap = new AdaptedMap();
        for(Entry<String, String> entry : map.entrySet()) {
            AdaptedEntry adaptedEntry = new AdaptedEntry();
            adaptedEntry.key = entry.getKey();
            adaptedEntry.value = entry.getValue();
            adaptedMap.entries.add(adaptedEntry);
        }
        return adaptedMap;
    }

    @Override
    public Map<String, String> unmarshal(AdaptedMap adaptedMap) throws Exception {
        List<AdaptedEntry> adaptedEntries = adaptedMap.entries;
        Map<String, String> map = new HashMap<String, String>(adaptedEntries.size());
        for(AdaptedEntry adaptedEntry : adaptedEntries) {
            map.put(adaptedEntry.key, adaptedEntry.value);
        }
        return map;
    }

}

使用这种方法,所有的键(MOBILE, id, A, B)都映射到Map. 我想解组所有已定义的属性id,MOBILE映射到它们在 POJO 中的属性,其余的都映射到Map.

如何实现?

标签: javaxmljaxbmarshallingunmarshalling

解决方案


我有一个解决方案给你,但与你上面尝试的略有不同。

让我们以根类为例:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "ROW")
public class Row {

    @XmlAttribute
    private int id;
    @XmlElement(name = "MOBILE")
    private int mobileNo;

    @XmlMixed
    @XmlAnyElement
    @XmlJavaTypeAdapter(MyMapAdapter.class)
    private Map<String, String> otherElements;
}

以及用于将 uknown 值转换为映射的适配器:

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.parsers.DocumentBuilderFactory;
import java.util.HashMap;
import java.util.Map;

public class MyMapAdapter extends XmlAdapter<Element, Map<String, String>> {

    private Map<String, String> hashMap = new HashMap<>();

    @Override
    public Element marshal(Map<String, String> map) throws Exception {
        // expensive, but keeps the example simpler
        Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();

        Element root = document.createElement("dynamic-elements");

        for(Map.Entry<String, String> entry : map.entrySet()) {
            Element element = document.createElement(entry.getKey());
            element.setTextContent(entry.getValue());
            root.appendChild(element);

        }

        return root;
    }


    @Override
    public Map<String, String> unmarshal(Element element) {
        String tagName = element.getTagName();
        String elementValue = element.getChildNodes().item(0).getNodeValue();
        hashMap.put(tagName, elementValue);

        return hashMap;
    }
}

这会将 id 和手机号码放在字段中,其余的将 uknown 放入地图中。

编组将与您显示的 xml 不完全相同。它对动态值进行了包装,如下所示:

<ROW id="1">
    <MOBILE>1241204091</MOBILE>
    <dynamic-elements>
        <A>1</A>
        <B>2</B>
    </dynamic-elements>
</ROW>

推荐阅读