Java JAXB:如何将映射编组到 <key>value</key>

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3941479/
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-08-14 07:18:26  来源:igfitidea点击:

JAXB: how to marshall map into <key>value</key>

javaxmljaxbjaxb2

提问by Timur

The question is about JAXB Map marshalling - there is plenty of examples on how to marhsall a Map into a structure like follows:

问题是关于 JAXB Map 编组 - 有很多关于如何将 Map 编组为如下结构的示例:

<map>
  <entry>
    <key> KEY </key>
    <value> VALUE </value>
  </entry>
  <entry>
    <key> KEY2 </key>
    <value> VALUE2 </value>
  </entry>
  <entry>
  ...
</map>

In fact, this is natively supported by JAXB. What I need, however, is the XML where key is the element name, and value is its content:

事实上,这是 JAXB 本身支持的。但是,我需要的是 XML,其中 key 是元素名称,value 是其内容:

<map>
  <key> VALUE </key>
  <key2> VALUE2 </key2>
 ...
</map>

I didn't succeed implementing my Map adapter the way it is recommended by JAXB developers (https://jaxb.dev.java.net/guide/Mapping_your_favorite_class.html), as I need, he - dynamic attribute name :)

我没有按照 JAXB 开发人员推荐的方式成功实现我的 Map 适配器(https://jaxb.dev.java.net/guide/Mapping_your_favorite_class.html),因为我需要,他 - 动态属性名称:)

Is there any solution for that?

有什么解决办法吗?

P.S. Currently I have to create a dedicated container class for each typical set of key-value pairs I want to marshall to XML - it works, but I have to create way too many of these helper containers.

PS 目前,我必须为我想要编组到 XML 的每个典型的键值对集创建一个专用的容器类 - 它可以工作,但我必须创建太多这些帮助容器。

采纳答案by Grégory

the code provided didn't work for me. I found another way to Map :

提供的代码对我不起作用。我找到了另一种映射方法:

MapElements :

地图元素:

package com.cellfish.mediadb.rest.lucene;

import javax.xml.bind.annotation.XmlElement;

class MapElements
{
  @XmlElement public String  key;
  @XmlElement public Integer value;

  private MapElements() {} //Required by JAXB

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

MapAdapter :

地图适配器:

import java.util.HashMap;
import java.util.Map;

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

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

        return mapElements;
    }

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

The rootElement :

根元素:

import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
public class Root {

    private Map<String, Integer> mapProperty;

    public Root() {
        mapProperty = new HashMap<String, Integer>();
    }

    @XmlJavaTypeAdapter(MapAdapter.class)
    public Map<String, Integer> getMapProperty() {
        return mapProperty;
    }

    public void setMapProperty(Map<String, Integer> map) {
        this.mapProperty = map;
    }

}

I found the code in this website : http://www.developpez.net/forums/d972324/java/general-java/xml/hashmap-jaxb/

我在这个网站上找到了代码:http: //www.developpez.net/forums/d972324/java/general-java/xml/hashmap-jaxb/

回答by bdoughan

I'm still working on a better solution but using MOXy JAXB, I've been able to handle the following XML:

我仍在研究更好的解决方案,但使用MOXy JAXB,我已经能够处理以下 XML:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <mapProperty>
      <map>
         <key>value</key>
         <key2>value2</key2>
      </map>
   </mapProperty>
</root>

You need to use an @XmlJavaTypeAdapter on your Map property:

您需要在 Map 属性上使用 @XmlJavaTypeAdapter :

import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
public class Root {

    private Map<String, String> mapProperty;

    public Root() {
        mapProperty = new HashMap<String, String>();
    }

    @XmlJavaTypeAdapter(MapAdapter.class)
    public Map<String, String> getMapProperty() {
        return mapProperty;
    }

    public void setMapProperty(Map<String, String> map) {
        this.mapProperty = map;
    }

}

The implementation of the XmlAdapter is as follows:

XmlAdapter 的实现如下:

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

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

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

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

    @Override
    public AdaptedMap marshal(Map<String, String> map) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document document = db.newDocument();
        Element rootElement = document.createElement("map");
        document.appendChild(rootElement);

        for(Entry<String,String> entry : map.entrySet()) {
            Element mapElement = document.createElement(entry.getKey());
            mapElement.setTextContent(entry.getValue());
            rootElement.appendChild(mapElement);
        }

        AdaptedMap adaptedMap = new AdaptedMap();
        adaptedMap.setValue(document);
        return adaptedMap;
    }

    @Override
    public Map<String, String> unmarshal(AdaptedMap adaptedMap) throws Exception {
        Map<String, String> map = new HashMap<String, String>();
        Element rootElement = (Element) adaptedMap.getValue();
        NodeList childNodes = rootElement.getChildNodes();
        for(int x=0,size=childNodes.getLength(); x<size; x++) {
            Node childNode = childNodes.item(x);
            if(childNode.getNodeType() == Node.ELEMENT_NODE) {
                map.put(childNode.getLocalName(), childNode.getTextContent());
            }
        }
        return map;
    }

}

The AdpatedMap class is where all the magic happens, we will use a DOM to represent the content. We will trick JAXB intro dealing with a DOM through the combination of @XmlAnyElement and a property of type Object:

AdpatedMap 类是所有魔法发生的地方,我们将使用 DOM 来表示内容。我们将通过@XmlAnyElement 和 Object 类型的属性的组合来欺骗 JAXB 处理 DOM:

import javax.xml.bind.annotation.XmlAnyElement;

public class AdaptedMap {

    private Object value;

    @XmlAnyElement
    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }

}

This solution requires the MOXy JAXB implementation. You can configure the JAXB runtime to use the MOXy implementation by adding a file named jaxb.properties in with your model classes with the following entry:

此解决方案需要 MOXy JAXB 实现。您可以将 JAXB 运行时配置为使用 MOXy 实现,方法是在模型类中添加名为 jaxb.properties 的文件,其中包含以下条目:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

The following demo code can be used to verify the code:

以下演示代码可用于验证代码:

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Root root = (Root) unmarshaller.unmarshal(new File("src/forum74/input.xml"));

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

回答by Justin Rowe

There may be a valid reason why you want to do this, but generating this kind of XML is generally best avoided. Why? Because it means that the XML elements of your map are dependent on the runtime contents of your map. And since XML is usually used as an external interface or interface layer this is not desirable. Let me explain.

这样做可能有正当的理由,但通常最好避免生成这种 XML。为什么?因为这意味着地图的 XML 元素依赖于地图的运行时内容。而且由于 XML 通常用作外部接口或接口层,因此这是不可取的。让我解释。

The Xml Schema (xsd) defines the interface contract of your XML documents. In addition to being able to generate code from the XSD, JAXB can also generate the XML schema for you from the code. This allows you to restrict the data exchanged over the interface to the pre-agreed structures defined in the XSD.

Xml Schema (xsd) 定义了 XML 文档的接口契约。除了能够从 XSD 生成代码之外,JAXB 还可以从代码中为您生成 XML 模式。这允许您将通过接口交换的数据限制为 XSD 中定义的预先商定的结构。

In the default case for a Map<String, String>, the generated XSD will restrict the map element to contain multiple entry elements each of which must contain one xs:stringkey and one xs:stringvalue. That's a pretty clear interface contract.

在 a 的默认情况下Map<String, String>,生成的 XSD 将限制 map 元素包含多个条目元素,每个元素必须包含一个xs:string键和一个xs:string值。这是一个非常明确的接口契约。

What you describe is that you want the xml map to contain elements whose name will be determined by the content of the map at runtime. Then the generated XSD can only specify that the map must contain a list of elements whose type is unknown at compile time. This is something that you should generally avoid when defining an interface contract.

您所描述的是您希望 xml 映射包含其名称将由运行时映射的内容确定的元素。那么生成的 XSD 只能指定映射必须包含一个在编译时类型未知的元素列表。这是您在定义接口契约时通常应该避免的事情。

To achieve a strict contract in this case, you should use an enumerated type as the key of the map instead of a String. E.g.

在这种情况下,要实现严格的约定,您应该使用枚举类型作为映射的键,而不是 String。例如

public enum KeyType {
 KEY, KEY2;
}

@XmlJavaTypeAdapter(MapAdapter.class)
Map<KeyType , String> mapProperty;

That way the keys which you want to become elements in XML are known at compile time so JAXB should be able to generate a schema that would restrict the elements of map to elements using one of the predefined keys KEY or KEY2.

这样,您想要成为 XML 中元素的键在编译时是已知的,因此 JAXB 应该能够生成一个模式,将映射元素限制为使用预定义键 KEY 或 KEY2 之一的元素。

On the other hand, if you wish to simplify the default generated structure

另一方面,如果您希望简化默认生成的结构

<map>
    <entry>
        <key>KEY</key>
        <value>VALUE</value>
    </entry>
    <entry>
        <key>KEY2</key>
        <value>VALUE2</value>
    </entry>
</map>

To something simpler like this

像这样更简单的东西

<map>
    <item key="KEY" value="VALUE"/>
    <item key="KEY2" value="VALUE2"/>
</map>

You can use a MapAdapter that converts the Map to an array of MapElements as follows:

您可以使用 MapAdapter 将 Map 转换为 MapElements 数组,如下所示:

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


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

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

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

回答by lunicon

I have solution without adapter. Transient map converted to xml-elements and vise versa:

我有没有适配器的解决方案。瞬态映射转换为 xml 元素,反之亦然:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "SchemaBasedProperties")
public class SchemaBasedProperties
{
  @XmlTransient
  Map<String, Map<String, String>> properties;

  @XmlAnyElement(lax = true)
  List<Object> xmlmap;

  public Map<String, Map<String, String>> getProperties()
  {
    if (properties == null)
      properties = new LinkedHashMap<String, Map<String, String>>(); // I want same order

    return properties;
  }

  boolean beforeMarshal(Marshaller m)
  {
    try
    {
      if (properties != null && !properties.isEmpty())
      {
        if (xmlmap == null)
          xmlmap = new ArrayList<Object>();
        else
          xmlmap.clear();

        javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance();
        javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder();
        org.w3c.dom.Document doc = db.newDocument();
        org.w3c.dom.Element element;

        Map<String, String> attrs;

        for (Map.Entry<String, Map<String, String>> it: properties.entrySet())
        {
          element = doc.createElement(it.getKey());
          attrs = it.getValue();

          if (attrs != null)
            for (Map.Entry<String, String> at: attrs.entrySet())
              element.setAttribute(at.getKey(), at.getValue());

          xmlmap.add(element);
        }
      }
      else
        xmlmap = null;
    }
    catch (Exception e)
    {
      e.printStackTrace();
      return false;
    }

    return true;
  }

  void afterUnmarshal(Unmarshaller u, Object p)
  {
    org.w3c.dom.Node node;
    org.w3c.dom.NamedNodeMap nodeMap;

    String name;
    Map<String, String> attrs;

    getProperties().clear();

    if (xmlmap != null)
      for (Object xmlNode: xmlmap)
        if (xmlNode instanceof org.w3c.dom.Node)
        {
          node = (org.w3c.dom.Node) xmlNode;
          nodeMap = node.getAttributes();

          name = node.getLocalName();
          attrs = new HashMap<String, String>();

          for (int i = 0, l = nodeMap.getLength(); i < l; i++)
          {
            node = nodeMap.item(i);
            attrs.put(node.getNodeName(), node.getNodeValue());
          }

          getProperties().put(name, attrs);
        }

    xmlmap = null;
  }

  public static void main(String[] args)
    throws Exception
  {
    SchemaBasedProperties props = new SchemaBasedProperties();
    Map<String, String> attrs;

    attrs = new HashMap<String, String>();
    attrs.put("ResId", "A_LABEL");
    props.getProperties().put("LABEL", attrs);

    attrs = new HashMap<String, String>();
    attrs.put("ResId", "A_TOOLTIP");
    props.getProperties().put("TOOLTIP", attrs);

    attrs = new HashMap<String, String>();
    attrs.put("Value", "hide");
    props.getProperties().put("DISPLAYHINT", attrs);

    javax.xml.bind.JAXBContext jc = javax.xml.bind.JAXBContext.newInstance(SchemaBasedProperties.class);

    Marshaller marshaller = jc.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    marshaller.marshal(props, new java.io.File("test.xml"));

    Unmarshaller unmarshaller = jc.createUnmarshaller();
    props = (SchemaBasedProperties) unmarshaller.unmarshal(new java.io.File("test.xml"));

    System.out.println(props.getProperties());
  }
}

My output as espected:

我预期的输出:

<SchemaBasedProperties>
    <LABEL ResId="A_LABEL"/>
    <TOOLTIP ResId="A_TOOLTIP"/>
    <DISPLAYHINT Value="hide"/>
</SchemaBasedProperties>

{LABEL={ResId=A_LABEL}, TOOLTIP={ResId=A_TOOLTIP}, DISPLAYHINT={Value=hide}}

You can use element name/value pair. I need attributes... Have fun!

您可以使用元素名称/值对。我需要属性...玩得开心!

回答by lukens

(Sorry, can't add comments)

(抱歉,无法添加评论)

In Blaise's answer above, if you change:

在上面布莱斯的回答中,如果你改变:

@XmlJavaTypeAdapter(MapAdapter.class)
public Map<String, String> getMapProperty() {
    return mapProperty;
}

to:

到:

@XmlJavaTypeAdapter(MapAdapter.class)
@XmlPath(".") // <<-- add this
public Map<String, String> getMapProperty() {
    return mapProperty;
}

then this should get rid of the <mapProperty>tag, and so give you:

那么这应该摆脱<mapProperty>标签,所以给你:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <map>
        <key>value</key>
        <key2>value2</key2>
    </map>
</root>

ALTERNATIVELY:

或者:

You can also change it to:

您也可以将其更改为:

@XmlJavaTypeAdapter(MapAdapter.class)
@XmlAnyElement // <<-- add this
public Map<String, String> getMapProperty() {
    return mapProperty;
}

and then you can get rid of AdaptedMapaltogether, and just change MapAdapterto marshall to a Documentobject directly. I've only tested this with marshalling, so there may be unmarshalling issues.

然后你可以AdaptedMap完全摆脱,直接改成MapAdaptermarshall到一个Document对象。我只用编组测试过这个,所以可能存在解组问题。

I'll try and find the time to knock up a full example of this, and edit this post accordingly.

我会试着找时间敲出一个完整的例子,并相应地编辑这篇文章。

回答by bonzai1990

I found easiest solution.

我找到了最简单的解决方案。

@XmlElement(name="attribute")
    public String[] getAttributes(){
        return attributes.keySet().toArray(new String[1]);
    }
}

Now it will generate in you xml output like this:

现在它将在您的 xml 输出中生成如下所示:

<attribute>key1<attribute>
...
<attribute>keyN<attribute>

回答by slartidan

When using xml-apis-1.0, you can serialize and deserialize this:

使用 xml-apis-1.0 时,您可以序列化和反序列化:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <map>
        <key>value</key>
        <key2>value2</key2>
    </map>
</root>

Using this code:

使用此代码:

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

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

@XmlRootElement
class Root {

    public XmlRawData map;

}

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Root root = (Root) unmarshaller.unmarshal(new File("src/input.xml"));

        System.out.println(root.map.getAsMap());

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

class XmlRawData {

    @XmlAnyElement
    public List<Element> elements;

    public void setFromMap(Map<String, String> values) {

        Document document;
        try {
            document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        }

        for (Entry<String, String> entry : values.entrySet()) {
            Element mapElement = document.createElement(entry.getKey());
            mapElement.appendChild(document.createTextNode(entry.getValue()));
            elements.add(mapElement);
        }
    }

    public Map<String, String> getAsMap() {
        Map<String, String> map = new HashMap<String, String>();

        for (Element element : elements) {
            if (element.getNodeType() == Node.ELEMENT_NODE) {
                map.put(element.getLocalName(), element.getFirstChild().getNodeValue());
            }
        }

        return map;
    }
}

回答by JavaJeff

I didn't see anything that really answered this very well. I found something that worked pretty well here:

我没有看到任何真正很好地回答这个问题的东西。我在这里发现了一些很好用的东西:

Use JAXB XMLAnyElement type of style to return dynamic element names

使用 JAXB XMLAnyElement 类型的样式返回动态元素名称

I modified it a bit to support hashmap trees. You could add other collections.

我对它进行了一些修改以支持哈希图树。您可以添加其他集合。

public class MapAdapter extends XmlAdapter<MapWrapper, Map<String, Object>> {
    @Override
    public MapWrapper marshal(Map<String, Object> m) throws Exception {
        MapWrapper wrapper = new MapWrapper();
        List elements = new ArrayList();
        for (Map.Entry<String, Object> property : m.entrySet()) {

            if (property.getValue() instanceof Map)
                elements.add(new JAXBElement<MapWrapper>(new QName(getCleanLabel(property.getKey())),
                        MapWrapper.class, marshal((Map) property.getValue())));
            else
                elements.add(new JAXBElement<String>(new QName(getCleanLabel(property.getKey())),
                        String.class, property.getValue().toString()));
        }
        wrapper.elements = elements;
        return wrapper;
    }

    @Override
    public Map<String, Object> unmarshal(MapWrapper v) throws Exception {
        // TODO
        throw new OperationNotSupportedException();
    }

    // Return a XML-safe attribute.  Might want to add camel case support
    private String getCleanLabel(String attributeLabel) {
        attributeLabel = attributeLabel.replaceAll("[()]", "").replaceAll("[^\w\s]", "_").replaceAll(" ", "_");
        return attributeLabel;
    }
}
class MapWrapper {
    @XmlAnyElement
    List elements;
}

Then to implement it:

然后实现它:

static class myxml {
    String name = "Full Name";
    String address = "1234 Main St";
    // I assign values to the map elsewhere, but it's just a simple
    // hashmap with a hashmap child as an example.
    @XmlJavaTypeAdapter(MapAdapter.class)
    public Map<String, Object> childMap;
}

Feeding this through a simple Marshaller gives output that looks like this:

通过一个简单的 Marshaller 提供它的输出如下所示:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<myxml>
    <name>Full Name</name>
    <address>1234 Main St</address>
    <childMap>
        <key2>value2</key2>
        <key1>value1</key1>
        <childTree>
            <childkey1>childvalue1</childkey1>
        </childTree>
    </childMap>
</myxml>

回答by mec_test_1

Seems like this question is kind of duplicate with another one, where I've collect some marshal/unmarshal solutions into one post. You may check it here: Dynamic tag names with JAXB.

似乎这个问题与另一个问题有点重复,我在一个帖子中收集了一些 marshal/unmarshal 解决方案。您可以在这里查看:Dynamic tag names with JAXB

In short:

简而言之:

  1. A container class for @xmlAnyElementshould be created
  2. An XmlAdaptercan be used in pair with @XmlJavaTypeAdapterto convert between the container class and Map<>;
  1. @xmlAnyElement应该创建一个容器类
  2. AnXmlAdapter可以成对使用@XmlJavaTypeAdapter,用于在容器类和 Map<> 之间进行转换;

回答by Martin Cassidy

Hymanson has an XmlMapper which will support this out of the box, no need to write any code at all.

Hymanson 有一个 XmlMapper 可以开箱即用地支持它,根本不需要编写任何代码。

Here's a nice tutorial https://www.baeldung.com/Hymanson-xml-serialization-and-deserialization

这是一个很好的教程 https://www.baeldung.com/Hymanson-xml-serialization-and-deserialization

Maven dependency:

Maven 依赖:

<dependency>
    <groupId>com.fasterxml.Hymanson.dataformat</groupId>
    <artifactId>Hymanson-dataformat-xml</artifactId>
    <version>2.9.8</version>
</dependency>

For writing a Mapto xml:

将 a 写入Mapxml:

Map<String, String> map = new HashMap<>();
map.put("SomeKey", "someValue");

XmlMapper mapper = new XmlMapper();
String xml = mapper.writeValueAsString(map);

Will give you

会给你

<HashMap><SomeKey>someValue</SomeKey></HashMap>

I was able to customise the root element by creating a HashMapsubclass

我能够通过创建HashMap子类来自定义根元素

@HymansonXmlRootElement(localName = "MyRootElement")
public class XmlHashMap<K, V> extends HashMap<K, V>
{

}

So now

所以现在

Map<String, String> map = new XmlHashMap<>();
map.put("SomeKey", "someValue");

XmlMapper mapper = new XmlMapper();
String xml = mapper.writeValueAsString(map);

Will give you

会给你

<MyRootElement><SomeKey>someValue</SomeKey></MyRootElement>