Map转Xml

   一、前言

由于开发需求,需要定制化xml文件。考虑到xml类似map的键值对原理,因此将数据先封装成map,再将map转换为xml。由于xml有顺序而已,因此要保证数据封装成map时是有序的,于是采用了LinkedHashMa

  • 二、思路(递归)

    • 2.1Xml的生成使用Document类

该类有以下几个主要的方法

Element rootElement = Doc. addElement   :创建根元素

Element  chridElement = Element.addElement  :创建父元素对应的子元素

Element. addAttribute     :添加元素的属性

Element.setText          :设置元素的值

  • 2.2.使用迭代器Iterator,依次拿出map中的值

  • ①当key所以对应的value数据类型为LinkedHashMap(因为这里嵌套的时LinkedHashMap,如果是其他类型也可以,比如json),说明还有嵌套的map,于是将key设为父节点,接着进入循环当key所对应的value数据类型为string 的时候,说明为子节点,进行值的设置。

  • 三、特殊情况

  • 下面是做项目的时候遇到的特殊情况,进行了特殊处理。当然,应该有其他解法

    3.1.两个子标签一样

    • Xml文件要求
  •        <Receivers>

                <Receiver>WHGGPT</Receiver>

                <Receiver>WHGGPT</Receiver>

            </Receivers>

    因为map规定key值不可以相同,所以我的想法是,在map的时候设置类似的值,然后根据Recrivers进行判断

    • Map方面的设置
  • Map<String,String> Receivers = new LinkedHashMap<String,String>();

    Receivers.put("Receivers1", Receivers1);

    Receivers.put("Receivers2", Receivers2);

     

    • 取值的处理
  • if(key.startsWith("Receivers")){        //特殊处理,传输xml多个接收者的情况

                      Element keyElement = rootElement.addElement("Receiver");

                      keyElement.setText( (String) map.get(key));

                  }

    3.2.父标签和子标签一样

    ①xml要求

        <ApplyDetail>

                <ApplyDetail>

                    …………………..

                </ApplyDetail>

         </ApplyDetail>

             ②Map方面无需处理

             ③取值处理,添加多一个父节点就可以

    if(key.equals("ApplyDetail")){                   //特殊处理

                      Element keyElement0 = rootElement.addElement(key);

                      Element keyElement = keyElement0.addElement(key);

                      Map map2 = (Map) map.get(key);

                      loopMap(map2,keyElement);

                  }

     

     四、完整代码 

package com.ceb.test.xmltest;

import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;

import com.ceb.createxml.DeclareXml;
import com.ceb.createxml.MaptoXml;

public class TestSmart {
	public static void main(String[] args){
		Map<String,Object> map = new LinkedHashMap<String,Object>();
		Map<String,String> head = new LinkedHashMap<String,String>();
		Map<String,Object> Declaration = new LinkedHashMap<String,Object>();
		Map<String,String> Register = new LinkedHashMap<String,String>();
		String MessageType = "00001";  //设置该xml的类型,可以忽略
		String Version = "1.0";
		head.put("MessageType",MessageType);
		head.put("Version",Version);
		String Name ="我是name";
		String note = "我是note";
		Register.put("Name",Name);
		Register.put("note", note);
		Declaration.put("Register",Register);
		map.put("Head",head);
		map.put("Declaration",Declaration);
		File file = new File("F:/textxml.xml");
		TestSmarMll.generDeclareXml(file,map,"00001");
	}
}

 

package com.ceb.test.xmltest;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMLWriter;

import com.ceb.createxml.MaptoXml;

public class TestSmarMll {
	public static void generDeclareXml(File file, Map map, String xmltype) {

		Document doc = DocumentHelper.createDocument();//获取Document对象

		Element rootElement = doc.addElement(xmltype);
		rootElement.addAttribute("xsi:noNamespaceSchemaLocation","xx.xsd");
		rootElement.addAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
		MaptoXml.loopMap(map, rootElement);
		XMLWriter writer;
		try {
			writer = new XMLWriter(new FileOutputStream(file),
					MaptoXml.getForm());
			writer.setEscapeText(false);// 字符是否转义,默认true
			writer.write(doc);
			writer.close();

		} catch (UnsupportedEncodingException | FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}
package com.ceb.createxml;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;

import org.dom4j.Element;
import org.dom4j.io.OutputFormat;

import sun.misc.BASE64Encoder;

public class MaptoXml {
	
	/**
	 * 将map依照层次转化
	 * @param map
	 * @param rootElement
	 */
	public static void loopMap(Map map,Element rootElement){
		Iterator<String> it = map.keySet().iterator();
		while(it.hasNext()){
			String key = it.next();
			String typeName =map.get(key).getClass().getName();
			System.out.println(key);
			System.out.println(getType(typeName));
			if(!getType(typeName).equals("LinkedHashMap")){
				//if(!getType(typeName).equals("JSONObject")){
				if(key.startsWith("Receivers")){        //特殊处理,传输xml多个接收者的情况
					Element keyElement = rootElement.addElement("Receiver");
					keyElement.setText( (String) map.get(key));
				}
				else{
					Element keyElement = rootElement.addElement(key);
					keyElement.setText((String) map.get(key));
				}
			}
			else if(getType(typeName).equals("LinkedHashMap")){
				//else if(getType(typeName).equals("JSONObject")){
				if(key.equals("ApplyDetail")){						//特殊处理
					Element keyElement0 = rootElement.addElement(key);
					Element keyElement = keyElement0.addElement(key);
					Map map2 = (Map) map.get(key);
					loopMap(map2,keyElement);
				}
				else{
					Element keyElement = rootElement.addElement(key);
					Map map2 = (Map) map.get(key);
					loopMap(map2,keyElement);
				}
			}
		}
	}
	/**
	 * 获取数据类型,用于判断是否添加子元素
	 * @param typeName
	 * @return
	 */
	public static String getType(String typeName){
		int length= typeName.lastIndexOf(".");
		String type =typeName.substring(length+1);
		return typeName.substring(length+1);
	}
	/**
	 * 解决默认第二行为空的情况
	 * @return
	 */
	public static OutputFormat getForm(){
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setIndentSize(4);//改为4
        format.setNewLineAfterDeclaration(false);
        return format;
	}
}

四、说明 

由于代码是在项目里提取出来的,所有如果那里有错了,运行不了代码,请提问。或者什么对特殊情况改进方法,也多多指点。 

 

<think> 我们注意到用户的问题已经从JSONXML向了MapXML,但之前的引用都是关于如何在Spring配置文件中使用XML配置来注入Map集合(例如在bean定义中通过<map>标签配置Map属性)。然而,用户当前的问题是在Spring框架中将Map对象换为XML格式,这通常是指将Java中的Map数据结构序列化为XML字符串。 根据用户提供的引用,并没有直接关于MapXML的内容。但是我们可以结合之前讨论的JSONXML以及Spring的内容协商机制,来回答如何将Map换为XML。 实际上,在Spring框架中,如果我们有一个Map对象,并希望将它返回为XML格式,我们可以利用Spring MVC的内容协商机制,或者使用Jackson库手动换(因为Jackson支持将Map序列化为XML)。 因此,我们可以提供两种方法: 方法一:使用Spring MVC的内容协商(自动) - 在控制器方法中返回Map对象,并配置Spring的内容协商机制,使得当客户端请求XML格式时,Spring自动将Map序列化为XML。 - 需要添加Jackson XML依赖。 方法二:手动使用Jackson的XmlMapper将Map换成XML字符串。 下面详细说明: ### 方法一:使用Spring MVC的内容协商(自动换) 1. 添加依赖:确保项目中包含Jackson XML数据格式支持。 ```xml <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency> ``` 2. 编写控制器方法,返回Map对象,并设置produces属性包含MediaType.APPLICATION_XML_VALUE。 ```java import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @RestController public class MapToXmlController { @GetMapping(value = "/map-to-xml", produces = MediaType.APPLICATION_XML_VALUE) public Map<String, Object> getMapAsXml() { Map<String, Object> map = new HashMap<>(); map.put("name", "John"); map.put("age", 30); map.put("city", "New York"); return map; } } ``` 3. 当客户端请求该URL时,设置Accept头为`application/xml`,即可得到XML格式的响应。 例如,使用curl测试: ```bash curl -H "Accept: application/xml" http://localhost:8080/map-to-xml ``` 响应结果类似于: ```xml <HashMap> <name>John</name> <age>30</age> <city>New York</city> </HashMap> ``` 注意:默认情况下,Map序列化为XML时,根元素名称是Map的实现类名(如HashMap)。如果需要自定义根元素名称,可以使用`@JacksonXmlRootElement`注解,但注意该注解需要作用在一个包装类上,而不是直接作用在Map上。因此,我们可以将Map包装在一个对象中。 例如,自定义一个包装类: ```java import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import java.util.Map; @JacksonXmlRootElement(localName = "customRoot") public class MapWrapper { private Map<String, Object> map; // getter和setter } ``` 然后在控制器中返回这个包装类: ```java @GetMapping(value = "/map-to-xml", produces = MediaType.APPLICATION_XML_VALUE) public MapWrapper getMapAsXml() { Map<String, Object> innerMap = new HashMap<>(); innerMap.put("name", "John"); innerMap.put("age", 30); innerMap.put("city", "New York"); MapWrapper wrapper = new MapWrapper(); wrapper.setMap(innerMap); return wrapper; } ``` 这样得到的XML根元素就会是`<customRoot>`,然后里面是各个条目。不过这样结构会多一层。 如果不希望包装,则只能接受默认的根元素名称(即Map实现类的类名)。或者,我们可以通过配置XmlMapper来改变默认的根元素名称,但这需要自定义消息换器,相对复杂。 ### 方法二:手动换(使用Jackson的XmlMapper) 如果你需要将Map换为XML字符串(例如,在服务层中处理,而不是通过HTTP响应),可以直接使用XmlMapper。 1. 添加依赖(同上)。 2. 在代码中使用XmlMapper: ```java import com.fasterxml.jackson.dataformat.xml.XmlMapper; public class MapToXmlConverter { public String convertMapToXml(Map<String, Object> map) throws Exception { XmlMapper xmlMapper = new XmlMapper(); return xmlMapper.writeValueAsString(map); } } ``` 3. 调用这个方法即可将Map换成XML字符串。 同样,默认根元素是Map的实现类名。如果需要自定义根元素,我们可以使用`@JacksonXmlRootElement`注解,但同样需要包装类。另一种方式是使用XmlMapper的配置: ```java XmlMapper xmlMapper = new XmlMapper(); // 设置根元素名称 xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 可选:忽略null值 // 创建一个包装Map的ObjectNode,并设置根名称(但这种方法并不直接支持设置根名称) // 替代方案:使用包装类,或者使用以下技巧: // 将Map写为一个属性,然后设置根名称,但这样会多一层结构。 // 简单的做法是接受默认的根名称,或者使用包装类。 ``` 由于Map本身没有元数据,所以无法直接添加注解。因此,如果需要自定义根元素名称,建议使用包装类。 示例:使用包装类并指定根元素名称 ```java @JacksonXmlRootElement(localName = "myRoot") public class MyMapWrapper { private Map<String, Object> data; // getter and setter } ``` 然后换: ```java MyMapWrapper wrapper = new MyMapWrapper(); wrapper.setData(map); String xml = xmlMapper.writeValueAsString(wrapper); ``` 得到的XML结构为: ```xml <myRoot> <data> <name>John</name> <age>30</age> <city>New York</city> </data> </myRoot> ``` 注意:这样会多一层`<data>`,因为包装类中有一个名为data的属性。如果希望去掉这一层,可以将Map的条目直接作为包装类的顶级元素?这可以通过在包装类上使用`@JacksonXmlProperty`和`@JacksonXmlElementWrapper`等注解来调整,但通常不直接支持将Map展开而不带属性名。 另一种思路:不使用包装类,而是使用一个自定义的JavaBean,属性就是Map的各个键。但这需要动态生成类,不实用。 因此,在大多数情况下,如果对根元素名称要求不严格,可以直接使用默认的。 ### 总结 在Spring框架中将Map换为XML有两种主要方式: 1. 利用Spring MVC的内容协商机制(自动),适用于返回HTTP响应的场景。 2. 手动使用XmlMapper进行换,适用于任何需要XML字符串的场景。 默认情况下,Map序列化为XML的根元素是Map实现类的类名(如HashMap)。如果需要自定义根元素名称,建议使用包装类并用`@JacksonXmlRootElement`注解指定。 注意:以上方法依赖Jackson XML库。 根据用户提供的引用,之前讨论的XML配置注入Map(引用[1]、[2]、[3]、[4])是关于如何在Spring的bean定义中配置Map属性,与这里的MapXML(序列化)是不同的概念。 如果用户真的是想了解如何在Spring配置文件中配置Map属性,那么请参考用户提供的引用(例如引用[1]和[4])。但根据问题“将Map换为XML”,我们理解的是序列化MapXML字符串。 相关问题: 1. Spring MVC中如何自定义XML序列化时的根元素名称? 2. Jackson库在序列化MapXML时如何处理复杂对象? 3. 除了Jackson,Spring还支持哪些XML序列化库? 4. 如何在Spring Boot中配置默认的XML序列化行为? </think> 在Spring框架中将Map换为XML,主要有两种实现方式:通过Spring MVC的内容协商机制(自动序列化)和手动使用Jackson库换。以下基于您的引用资料和实际需求详细说明: --- ### 一、自动序列化:Spring MVC内容协商机制(推荐) **原理** 通过Spring的内容协商机制,当控制器返回Map对象时,框架自动根据客户端要求的`Accept`头(如`application/xml`)生成XML。需添加Jackson XML依赖支持。 #### 实现步骤 1. **添加依赖**(关键步骤) 在`pom.xml`中添加Jackson XML支持: ```xml <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency> ``` 2. **定义控制器** 直接返回Map对象,并声明支持XML格式: ```java import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @RestController public class MapController { @GetMapping(value = "/map", produces = MediaType.APPLICATION_XML_VALUE) public Map<String, Object> getMap() { Map<String, Object> map = new HashMap<>(); map.put("name", "John"); map.put("age", 30); map.put("roles", List.of("admin", "user")); // 支持嵌套集合 return map; // 自动XML } } ``` 3. **客户端请求** 设置`Accept: application/xml`头: ```bash curl -H "Accept: application/xml" http://localhost:8080/map ``` 4. **输出XML示例** ```xml <HashMap> <name>John</name> <age>30</age> <roles> <roles>admin</roles> <roles>user</roles> </roles> </HashMap> ``` > **注**:根标签默认使用Map实现类名(如`HashMap`)。若需自定义根标签名,需使用`@JacksonXmlRootElement`注解封装Map[^2]。 --- ### 二、手动换:使用Jackson库 **适用场景** 当需要直接操作XML字符串(如写入文件或自定义处理)时,手动换更灵活。 #### 实现步骤 1. **添加依赖**(同上) 2. **使用XmlMapperMap** ```java import com.fasterxml.jackson.dataformat.xml.XmlMapper; import java.util.Map; public class MapToXmlConverter { public String convert(Map<String, Object> map) throws Exception { XmlMapper xmlMapper = new XmlMapper(); return xmlMapper.writeValueAsString(map); } } ``` 3. **封装自定义根标签** 通过包装类指定根标签名: ```java import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import java.util.Map; @JacksonXmlRootElement(localName = "UserData") // 自定义根标签 public class MapWrapper { private Map<String, Object> data; // Getter/Setter } ``` 换时: ```java MapWrapper wrapper = new MapWrapper(); wrapper.setData(map); String xml = xmlMapper.writeValueAsString(wrapper); ``` 输出: ```xml <UserData> <data> <name>John</name> <age>30</age> </data> </UserData> ``` --- ### 三、关键配置说明 1. **XML标签命名规则** - Map的Key直接作为XML子标签名(如`<name>John</name>`)。 - 嵌套集合(如List)使用重复标签(如`<roles>admin</roles>`)[^2][^4]。 2. **引用其他Bean**(结合您的引用[^1][^4]) 若Map需注入Spring管理的Bean: ```xml <bean id="mapBean" class="java.util.HashMap"> <constructor-arg> <map> <entry key="account" value-ref="accountService"/> <!-- 引用Bean --> <entry key="config" value="12345"/> <!-- 字面值 --> </map> </constructor-arg> </bean> ``` --- ### 四、常见问题解决 1. **根标签名称问题** - **方案**:用`@JacksonXmlRootElement`封装Map。 2. **空值处理** - 添加注解忽略空值: ```java xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); ``` 3. **日期格式化** - 在Map的Value对象中使用`@JsonFormat`: ```java public class User { @JsonFormat(pattern = "yyyy-MM-dd") private Date birth; } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值