67

問題は、JAXBマップのマーシャリングに関するものです。マップを次のような構造にマーシャリングする方法については、多くの例があります。

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

実際、これはJAXBによってネイティブにサポートされています。ただし、必要なのはXMLです。ここで、keyは要素名であり、valueはそのコンテンツです。

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

必要に応じて、JAXB開発者( https://jaxb.dev.java.net/guide/Mapping_your_favorite_class.html )が推奨する方法でマップアダプターを実装できませんでした。動的属性名:)

そのための解決策はありますか?

PS現在、XMLにマーシャリングするキーと値のペアの一般的なセットごとに専用のコンテナークラスを作成する必要があります。これは機能しますが、これらのヘルパーコンテナーをあまりにも多く作成する必要があります。

4

11 に答える 11

28

これを実行する正当な理由があるかもしれませんが、この種のXMLの生成は一般的に回避するのが最善です。なんで?これは、マップのXML要素がマップの実行時の内容に依存していることを意味するためです。また、XMLは通常、外部インターフェイスまたはインターフェイスレイヤーとして使用されるため、これは望ましくありません。説明させてください。

Xmlスキーマ(xsd)は、XMLドキュメントのインターフェースコントラクトを定義します。XSDからコードを生成できることに加えて、JAXBはコードからXMLスキーマを生成することもできます。これにより、インターフェイスを介して交換されるデータを、XSDで定義された事前に合意された構造に制限できます。

のデフォルトの場合Map<String, String>、生成されたXSDは、マップ要素が複数のエントリ要素を含むように制限します。各エントリ要素には、1つのxs:stringキーと1つのxs:string値が含まれている必要があります。これはかなり明確なインターフェース契約です。

説明するのは、実行時にマップのコンテンツによって名前が決定される要素をxmlマップに含めることです。次に、生成されたXSDは、コンパイル時にタイプが不明な要素のリストがマップに含まれている必要があることのみを指定できます。これは、インターフェイスコントラクトを定義するときに一般的に避けるべきものです。

この場合に厳密なコントラクトを実現するには、文字列ではなく、列挙型をマップのキーとして使用する必要があります。例えば

public enum KeyType {
 KEY, KEY2;
}

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

そうすれば、XMLの要素になりたいキーがコンパイル時に認識されるため、JAXBは、事前定義されたキーKEYまたはKEY2のいずれかを使用して、マップの要素を要素に制限するスキーマを生成できる必要があります。

一方、デフォルトで生成された構造を単純化したい場合

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

このようなもっと単純なものに

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

次のように、MapをMapElementsの配列に変換するMapAdapterを使用できます。

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;
    }
}
于 2013-03-22T09:24:20.283 に答える
26

提供されたコードは私には機能しませんでした。マップする別の方法を見つけました:

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

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

}

私はこのウェブサイトでコードを見つけました: http ://www.developpez.net/forums/d972324/java/general-java/xml/hashmap-jaxb/

于 2011-01-04T19:01:26.083 に答える
16

私はまだより良いソリューションに取り組んでいますが、MOXy JAXBを使用して、次のXMLを処理することができました。

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

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

}

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

}

AdpatedMapクラスは、すべての魔法が発生する場所です。コンテンツを表すためにDOMを使用します。@XmlAnyElementとObject型のプロパティの組み合わせを使用して、DOMを処理するJAXBイントロをだまします。

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

}

このソリューションには、MOXyJAXBの実装が必要です。次のエントリを使用して、モデルクラスにjaxb.propertiesという名前のファイルを追加することにより、MOXy実装を使用するようにJAXBランタイムを構成できます。

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

次のデモコードを使用して、コードを確認できます。

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);
    }
}
于 2010-10-15T19:36:30.107 に答える
12

これに本当によく答えるようなものは見当たりませんでした。私はここでかなりうまくいくものを見つけました:

JAXB XMLAnyElementタイプのスタイルを使用して、動的要素名を返します

ハッシュマップツリーをサポートするように少し変更しました。他のコレクションを追加することもできます。

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 {
    HashMap<String, Object> returnval = new HashMap();
    for (Object o : v.elements) {
        Element e = (Element) o;
        if (e.getChildNodes().getLength() > 1) {
            MapWrapper mw = new MapWrapper();
            mw.elements = new ArrayList();
            for (int count = 0; count < e.getChildNodes().getLength(); count++) {
                if (e.getChildNodes().item(count) instanceof Element) {
                    mw.elements.add(e.getChildNodes().item(count));
                }
            }
            returnval.put(e.getTagName(), unmarshal(mw));
        } else {
            returnval.put(e.getTagName(), e.getTextContent());
        }
    }
    return returnval;
}


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

次に、それを実装するには:

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

単純なマーシャラーを介してこれをフィードすると、次のような出力が得られます。

<?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>
于 2015-09-09T15:34:10.227 に答える
3

アダプターなしの解決策があります。一時的なマップはxml-elementsに変換され、その逆も同様です。

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

見た目の私の出力:

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

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

要素の名前と値のペアを使用できます。属性が必要です...楽しんでください!

于 2014-06-16T08:06:32.677 に答える
3

(申し訳ありませんが、コメントを追加できません)

上記のBlaiseの回答で、変更した場合:

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

に:

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

次に、これでタグが削除されるはず<mapProperty>なので、次のようにします。

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

代わりに:

次のように変更することもできます。

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

AdaptedMapそうすれば、完全に取り除くことができ、直接オブジェクトMapAdapterにマーシャルするように変更することができます。Documentこれはマーシャリングでのみテストしたので、マーシャリング解除の問題がある可能性があります。

私はこれの完全な例をノックアップする時間を見つけて、それに応じてこの投稿を編集します。

于 2014-08-28T11:52:19.483 に答える
2

この質問は別の質問と重複しているようです。ここでは、いくつかのマーシャル/アンマーシャルソリューションを1つの投稿にまとめました。ここで確認できます:JAXBを使用した動的タグ名

要するに:

  1. のコンテナクラスを@xmlAnyElement作成する必要があります
  2. XmlAdapterと組み合わせて使用​​して@XmlJavaTypeAdapter、コンテナクラスとMap<>の間で変換できます。
于 2016-06-23T07:41:28.993 に答える
0

xml-apis-1.0を使用する場合、これをシリアル化および逆シリアル化できます。

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

このコードの使用:

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;
    }
}
于 2015-05-06T18:52:19.540 に答える
0

JacksonにはXmlMapperがあり、これをすぐにサポートします。コードを記述する必要はまったくありません。

これが素晴らしいチュートリアルです https://www.baeldung.com/jackson-xml-serialization-and-deserialization

Mavenの依存関係:

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

Mapxmlに書き込む場合:

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

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

あなたに与えます

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

HashMapサブクラスを作成してルート要素をカスタマイズすることができました

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

}

だから今

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

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

あなたに与えます

<MyRootElement><SomeKey>someValue</SomeKey></MyRootElement>
于 2020-01-13T18:19:45.873 に答える
0

ほとんどの人がmarshallingここでのみ言及しているmarshallingunmarshallingMap<String,Object>

import jakarta.xml.bind.JAXBElement;
import jakarta.xml.bind.annotation.XmlAnyElement;
import jakarta.xml.bind.annotation.adapters.XmlAdapter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.xml.namespace.QName;
import lombok.Getter;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


public class MoxyMapAdapter extends XmlAdapter<MapWrapper, Map<String, Object>> {

  @Override
  public Map<String, Object> unmarshal(MapWrapper value) {
    
    final Map<String, Object> extensions = new HashMap<>();
    //Loop across all elements within value
    for (Object obj : value.getElements()) {
      Element element = (Element) obj;

      final NodeList children = element.getChildNodes();

      if (children.getLength() == 1) {
        extensions.put(element.getNodeName(), element.getTextContent());
      } else {
        List<Object> child = new ArrayList<>();
        for (int i = 0; i < children.getLength(); i++) {
          final Node n = children.item(i);
          if (n.getNodeType() == Node.ELEMENT_NODE) {
            MapWrapper wrapper = new MapWrapper();
            List childElements = new ArrayList();
            childElements.add(n);
            wrapper.elements = childElements;
            child.add(unmarshal(wrapper));
          }
        }
        extensions.put(element.getNodeName(), child);
      }
    }
    return extensions;
  }


  @Override
  public MapWrapper marshal(Map<String, Object> extensions) throws Exception {
    if (extensions == null) {
      return null;
    }

    MapWrapper wrapper = new MapWrapper();

    List elements = new ArrayList();

    //Loop through the Extensions MAP
    for (Map.Entry<String, Object> property : extensions.entrySet()) {

        //If the Value type is MAP then recurse through the loop
        if (property.getValue() instanceof Map) {
          elements
              .add(new JAXBElement<MapWrapper>(new QName(namespaceURI, localPart, prefix), MapWrapper.class, marshal((Map) property.getValue())));
        } else if (property.getValue() instanceof String) {
          // If the Value type is String then directly create JAXBElement
          elements.add(new JAXBElement<String>(new QName(namespaceURI, localPart, prefix), String.class, property.getValue().toString()));
        } else if (property.getValue() instanceof ArrayList) {
          //If the Value type is ArrayList then it contains Duplicate key values so Loop through it
          for (Object dupItems : (ArrayList<String>) property.getValue()) {
            if (dupItems instanceof Map) {
              elements.add(new JAXBElement<MapWrapper>(new QName(namespaceURI, localPart, prefix), MapWrapper.class, marshal((Map) dupItems)));
            } else {
              elements.add(new JAXBElement<String>(new QName(namespaceURI, localPart, prefix), String.class, dupItems.toString()));
            }
          }
        }
    }
    wrapper.elements = elements;
    return wrapper;
  }
}


class MapWrapper {

  @Getter
  @XmlAnyElement
  List elements;
}
于 2021-06-09T12:16:29.780 に答える
-1

私は最も簡単な解決策を見つけました。

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

これで、次のようなxml出力が生成されます。

<attribute>key1<attribute>
...
<attribute>keyN<attribute>
于 2014-11-11T18:07:31.580 に答える