java JAXB 将 XML 的元素解组为 Map

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27182975/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 11:21:25  来源:igfitidea点击:

JAXB unmarshal elements of XML to Map

javaxmljaxb

提问by khateeb

I have an XML file. In this file, some of the elements are have attributes that change. I want to put those attributes into a Map. How do I do this?

我有一个 XML 文件。在此文件中,某些元素的属性会发生变化。我想将这些属性放入地图中。我该怎么做呢?

My XML is:

我的 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>

In this, the VARSelement can have attributes which changes and I do not know beforehand what these elements will be.

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

I have created a class for this purpose:

为此,我创建了一个类:

@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;
    }
}

I want to map the VARSelement to a Map. I want the tags such as CAUSE, LOTto be keys and their values to be the values in the map. I have written an XmlAdapaterfor this purpose:

我想将VARS元素映射到Map. 我希望诸如CAUSE,之类的标签LOT是键,它们的值是地图中的值。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;
    }
}

This adapter is giving me nullfor the variableMapvariable. How should the Adapter be modified for this?

该适配器是给我nullvariableMap变量。为此应如何修改 Adapter?

回答by bdoughan

You could do the following:

您可以执行以下操作:

XmlAdapter (MapAdapter)

XmlAdapter ( MapAdapter)

You could do the following for your XmlAdapterwhere you convert an instance of Mapto an object that has a Listof DOM Element. You will construct the instances of Elementso that the name is they key from the map entry, and the text content is the value.

您可以XmlAdapter在将 的实例转换为Map具有ListDOM的对象的位置执行以下操作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;
    }


}

Optimizing the Use of MapAdapter

优化使用 MapAdapter

To improve performance we want to minimize the number of times the DocumentBuiderFactoryand DocumentBuilderis instantiated. We can do this by creating an instance of the MapAdapterfor JAXB to use and set it on the Marshallerand Unmarshaller. This way JAXB will use that instance instead of creating a new one each time the adapter is required.

为了提高性能,我们希望最小化DocumentBuiderFactoryDocumentBuilder的实例化次数。我们可以通过创建一个MapAdapter供 JAXB 使用的的实例并将其设置在Marshaller和上来做到这一点Unmarshaller。这样 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);
    }

}


If You are Using MOXy as your JAXB (JSR-222) Provider

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

If you are using MOXy as your JAXB provider then you can leverage the @XmlVariableNodeextension to make the mapping of this use case easier:

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