为了账号安全,请及时绑定邮箱和手机立即绑定

JAXB:如何封送映射为<key> value </ key>

/ 猿问

JAXB:如何封送映射为<key> value </ key>

HUX布斯 2019-10-16 14:51:26

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


<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开发人员推荐的方式成功实现Map适配器(https://jaxb.dev.java.net/guide/Mapping_your_favorite_class.html),根据需要,他-动态属性名:)


有什么解决办法吗?


PS当前,我必须为要编组到XML的每组典型的键/值对创建专用的容器类-它可以工作,但是我必须创建太多此类帮助器容器。


查看完整描述

3 回答

?
侃侃尔雅

提供的代码对我不起作用。我找到了另一种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;

    }

}

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/


查看完整回答
反对 回复 2019-10-16
?
拉丁的传说

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


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


在a的默认情况下Map<String, String>,生成的XSD将限制map元素包含多个entry元素,每个entry必须包含一个xs:string键和一个xs:string值。那是一个非常清晰的接口合同。


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


要在这种情况下达成严格的约定,应使用枚举类型(而不是字符串)作为映射的键。例如


public enum KeyType {

 KEY, KEY2;

}


@XmlJavaTypeAdapter(MapAdapter.class)

Map<KeyType , String> mapProperty;

这样,在编译时就知道了要成为XML元素的键,因此JAXB应该能够生成一个架构,该架构将使用预定义的键KEY或KEY2之一将map的元素限制为元素。


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


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

您可以使用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;

    }

}


查看完整回答
反对 回复 2019-10-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类型的属性的组合来欺骗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;

    }


}

此解决方案需要MOXy JAXB实现。您可以通过在模型类中添加一个名为jaxb.properties的文件,并使用以下条目来配置JAXB运行时以使用MOXy实现:


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

    }

}


查看完整回答
反对 回复 2019-10-16

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信