JAXB解组XML到Map的元素

时间:2014-11-28 06:18:41

标签: java xml jaxb

我有一个XML文件。在此文件中,某些元素具有更改的属性。我想将这些属性放入Map中。我该怎么做?

我的XML是:

<ROW id='1'>
    <MOBILE>9831138683</MOBILE>
    <VARS>
        <CAUSE>Delayed payment</CAUSE>
        <DO>100.56</DO>
        <LOT>1</LOT>
    </VARS>
</ROW>
<ROW id='2'>
    <MOBILE>9831138684</MOBILE>
    <VARS>
        <NAME>hi</NAME>
        <ADDRESS>Here</ADDRESS>
        <LOT>2</LOT>
    </VARS>
</ROW>

在此,VARS元素可以具有更改的属性,我事先不知道这些元素将是什么。

我为此创建了一个类:

@XmlRootElement(name = "ROW")
@XmlAccessorType(XmlAccessType.FIELD)
public class SMSDetail {
    @XmlAttribute
    private int id;
    @XmlElement(name = "MOBILE")
    private int mobileNo;
    @XmlElement(name = "VARS")
    @XmlJavaTypeAdapter(MapAdapter.class)
    private HashMap<String, String> variableMap;

    public int getId() {
        return id;
    }

    public int getMobileNo() {
        return mobileNo;
    }

    public HashMap<String, String> getVariableMap() {
        return variableMap;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setMobileNo(int mobileNo) {
        this.mobileNo = mobileNo;
    }

    public void setVariableMap(HashMap<String, String> variableMap) {
        this.variableMap = variableMap;
    }
}

我想将VARS元素映射到Map。我希望CAUSELOT等标记为关键字,其值为地图中的值。我为此目的写了XmlAdapater

public class MapAdapter extends XmlAdapter<MapElements[], Map<String, String>> {
    public MapAdapter() {
    }

    @Override
    public MapElements[] marshal(Map<String, String> arg0) throws Exception {
        MapElements[] mapElements = new MapElements[arg0.size()];
        int i = 0;
        for (Map.Entry<String, String> entry : arg0.entrySet())
            mapElements[i++] = new MapElements(entry.getKey(), entry.getValue());

        return mapElements;
    }

    @Override
    public Map<String, String> unmarshal(MapElements[] arg0) throws Exception {
        Map<String, String> r = new TreeMap<String, String>();
        for (MapElements mapelement : arg0)
            r.put(mapelement.key, mapelement.value);
        return r;
    }
}

class MapElements {
    @XmlAttribute
    public String key;
    @XmlAttribute
    public String value;

    private MapElements() {
    } //Required by JAXB

    public MapElements(String key, String value) {
        this.key = key;
        this.value = value;
    }
}

此适配器为null变量提供了variableMap。应如何修改适配器?

1 个答案:

答案 0 :(得分:11)

您可以执行以下操作:

XmlAdapter(MapAdapter

您可以对XmlAdapter执行以下操作,将Map的实例转换为具有List DOM Element的对象。您将构造Element的实例,以便名称是映射条目中的键,文本内容是值。

import java.util.*;
import java.util.Map.Entry;

import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.*;

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

    private DocumentBuilder documentBuilder;

    public MapAdapter() throws Exception {
        documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    }

    public static class AdaptedMap {        
        @XmlAnyElement
        public List<Element> elements = new ArrayList<Element>();
    }

    @Override
    public AdaptedMap marshal(Map<String, String> map) throws Exception {
        Document document = documentBuilder.newDocument();
        AdaptedMap adaptedMap = new AdaptedMap();
        for(Entry<String, String> entry : map.entrySet()) {
            Element element = document.createElement(entry.getKey());
            element.setTextContent(entry.getValue());
            adaptedMap.elements.add(element);
        }
        return adaptedMap;
    }

    @Override
    public Map<String, String> unmarshal(AdaptedMap adaptedMap) throws Exception {
        HashMap<String, String> map = new HashMap<String, String>();
        for(Element element : adaptedMap.elements) {
            map.put(element.getLocalName(), element.getTextContent());
        }
        return map;
    }


}

优化MapAdapter

的使用

为了提高性能,我们希望尽量减少DocumentBuiderFactoryDocumentBuilder实例化的次数。我们可以通过为JAXB创建MapAdapter的实例来实现此目的,并在MarshallerUnmarshaller上进行设置。这样,JAXB将使用该实例,而不是每次需要适配器时都创建一个新实例。

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(SMSDetail.class);

        MapAdapter mapAdapter = new MapAdapter();

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setAdapter(mapAdapter);
        File xml = new File("src/forum27182975/input.xml");
        SMSDetail smsDetail = (SMSDetail) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setAdapter(mapAdapter);
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(smsDetail, System.out);
    }

}

如果您使用MOXy作为JAXB(JSR-222)提供程序

如果您使用MOXy作为JAXB提供程序,那么您可以利用@XmlVariableNode扩展名来简化此用例的映射: