xmltomap

Java类实现Map转换为XML字符串及XML解析为Map的方法
public class XmlMapUtil {
	/**
	 * map转xml字符串
	 * 
	 * @param map
	 * @return
	 */
	public static String map2xml(Map<String, Object> map, String rootElement) {
		StringBuffer xmlStr = new StringBuffer("");
		if (map == null || map.isEmpty())
			return xmlStr.toString();
		xmlStr.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><" + rootElement + ">");
		map2Element(map, xmlStr,new HashMap<String,String>());
		xmlStr.append("</" + rootElement + ">");
		return xmlStr.toString();
	}
	
	
	/**
	 * map转xml字符串
	 * 
	 * @param map
	 * @return
	 */
	public static String map2xmlZz(Map<String, Object> map, String rootElement) {
		StringBuffer xmlStr = new StringBuffer("");
		if (map == null || map.isEmpty())
			return xmlStr.toString();
		xmlStr.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><" + rootElement + ">");
		map2ElementZz(map, xmlStr,new HashMap<String,String>());
		xmlStr.append("</" + rootElement + ">");
		return xmlStr.toString();
	}
	
	public static String map2xml(Map<String, Object> map, String rootElement,String mappingStr) {
		Map<String,String>mappingRelation = new HashMap<>();
		if( mappingStr!=null&&mappingStr.length()>0 ){
			String[] mappingStrs = mappingStr.split(",");
			for (String mapping : mappingStrs) {
				mappingRelation.put(mapping.toLowerCase(), mapping);
			}
		}
		StringBuffer xmlStr = new StringBuffer("");
		if (map == null || map.isEmpty())
			return xmlStr.toString();
		xmlStr.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><" + rootElement + ">");
		map2Element(map, xmlStr,mappingRelation);
		xmlStr.append("</" + rootElement + ">");
		return xmlStr.toString();
	}
	
	
	/**
	 * 递归map转xml字符串
	 * 
	 * @param map
	 * @param sb
	 */
	@SuppressWarnings("unchecked")
	private static void map2ElementZz(Map<String, Object> map, StringBuffer sb,Map<String,String> mapping) {
		Set<String> set = map.keySet();
		for (Iterator<String> it = set.iterator(); it.hasNext();) {
			String key = (String) it.next();
			String kkey = mapping.get(key);
			kkey = (kkey==null)?key:kkey;
			Object value = map.get(key);
			if (null == value)
				value = "";
			if (value instanceof List<?>) {
				List<Object> list = (List<Object>) map.get(key);
//				sb.append("<" + kkey + ">");
				for (int i = 0; i < list.size(); i++) {
					sb.append("<" + kkey + ">");
					Map<String, Object> hm = (Map<String, Object>) list.get(i);
					map2ElementZz(hm, sb,mapping);
					sb.append("</" + kkey + ">");
				}
//				sb.append("</" + kkey + ">");
			} else {
				if (value instanceof Map<?, ?>) {
					sb.append("<" + kkey + ">");
					map2ElementZz((Map<String, Object>) value, sb,mapping);
					sb.append("</" + kkey + ">");
				} else {
					sb.append("<" + kkey + ">" + value + "</" + kkey + ">");
				}

			}
		}
	}
	
	
	

	/**
	 * 递归map转xml字符串
	 * 
	 * @param map
	 * @param sb
	 */
	@SuppressWarnings("unchecked")
	private static void map2Element(Map<String, Object> map, StringBuffer sb,Map<String,String> mapping) {
		Set<String> set = map.keySet();
		for (Iterator<String> it = set.iterator(); it.hasNext();) {
			String key = (String) it.next();
			String kkey = mapping.get(key);
			kkey = (kkey==null)?key:kkey;
			Object value = map.get(key);
			if (null == value)
				value = "";
			if (value instanceof List<?>) {
				List<Object> list = (List<Object>) map.get(key);
				sb.append("<" + kkey + ">");
				for (int i = 0; i < list.size(); i++) {
//					sb.append("<" + kkey + ">");
					Map<String, Object> hm = (Map<String, Object>) list.get(i);
					map2Element(hm, sb,mapping);
//					sb.append("</" + kkey + ">");
				}
				sb.append("</" + kkey + ">");
			} else {
				if (value instanceof Map<?, ?>) {
					sb.append("<" + kkey + ">");
					map2Element((Map<String, Object>) value, sb,mapping);
					sb.append("</" + kkey + ">");
				} else {
					sb.append("<" + kkey + ">" + value + "</" + kkey + ">");
				}

			}
		}
	}

	/**
	 * xml字符串转map
	 * 
	 * @param xml
	 * @return
	 * @throws BizException
	 */
	public static Map<String, Object> xml2map(String xml) throws BizException {
		Document doc = null;
		try {
			// 将xml字符串转为document对象
			doc = DocumentHelper.parseText(xml);
		} catch (DocumentException e) {
			throw new BizException("响应参数解析失败!");
		}
		Map<String, Object> map = new HashMap<>();
		if (doc == null) {
			return map;
		} else {
			// 获取根节点
			Element rootElement = doc.getRootElement();
			element2map(rootElement, map);
		}
		return map;
	}


	/**
	 * 递归原则 : 一个map对应一个xml节点,key为当前xml节点名,value为当前xml节点子集
	 * 如果xml节点没有子节点(叶子节点),那么map的key为xml节点名,value为xml节点文本内容
	 * 如果xml节点有一个子节点,那么map的key为xml节点名,value为xml节点子集
	 * 如果xml节点有多个子节点,对应map的key不存在(每一次),map的key为xml节点名,value为xml节点子集
	 * 如果xml节点有多个子节点,对应map的key已存在,且value为map类型(第二次),map的key为xml节点名,值从map类型转为list
	 * ,而list中添加2份当前xml节点子集
	 * 如果xml节点有多个子节点,对应map的key已存在,且value为list类型(第三/多次),那么直接加到list中去.
	 * 
	 * @param elmt
	 * @param map
	 * @see [类、类#方法、类#成员]
	 */
	@SuppressWarnings("unchecked")
	public static void element2map(Element elmt, Map<String, Object> map) {
		if (null == elmt) {
			return;
		}
		String name = elmt.getName();

		// 判断当前节点的内容是否为文本(最里面一层节点)
		if (elmt.isTextOnly()) {
			map.put(name, elmt.getText());
		} else {
			Map<String, Object> mapSub = new HashMap<>();

			// 获取当前节点的所有子节点
			List<Element> elements = (List<Element>) elmt.elements();

			// 利用递归获取节点值
			for (Element elmtSub : elements) {
				element2map(elmtSub, mapSub);
			}
			Object first = map.get(name);

			// 判断
			if (null == first) {
				map.put(name, mapSub);
			} else {
				if (first instanceof List<?>) {
					((List<Map<String, Object>>) first).add(mapSub);
				} else {
					List<Object> listSub = new ArrayList<Object>();
					listSub.add(first);
					listSub.add(mapSub);
					map.put(name, listSub);
				}
			}
		}
	}
	/**
	 * xml字符串转map
	 * 
	 * @param xml
	 * @return
	 * @throws BizException
	 */
	public static List<Object> xml2map2(String xml) throws BizException {
		Document doc = null;
		try {
			// 将xml字符串转为document对象
			doc = DocumentHelper.parseText(xml);
		} catch (DocumentException e) {
			throw new BizException("响应参数解析失败!");
		}
		List<Object> list=new ArrayList<Object>();
		
		if (doc == null) {
			return list;
		} else {
			// 获取根节点
			Element rootElement = doc.getRootElement();
			list=element2mapForCir(rootElement);
		}
		return list;
	}
	
	
	/**
	 * 递归原则 : map的key的value不是文本就是list
	 *           list的大小为非文本子节点个数的map+文本(map) ,list.get(0)为文本hashMap
	 * @param elmt
	 * @param map
	 * @see [类、类#方法、类#成员]
	 */
	@SuppressWarnings("unchecked")
	public static  List<Object>  element2mapForCir(Element elmt) {
		List<Object> list=new ArrayList<Object>();
		if (null == elmt) {
			return list;
		}
		Map<String, Object> map = new HashMap<>();

		String name = elmt.getName();
		if(list==null ){
			list=new ArrayList<Object>();
			list.add(new HashMap<String, Object>());
		}else if(list.size()==0){
			list.add(new HashMap<String, Object>());
		}else{
			
		}
		// 判断当前节点的内容是否为文本(最里面一层节点)
		if (elmt.isTextOnly()) {
			((Map<String, Object>)list.get(0)).put(name, elmt.getText());
		} else {
			// 获取当前节点的所有子节点
			List<Element> elements = (List<Element>) elmt.elements();
			List<Object> list2=new ArrayList<Object>();

			// 利用递归获取节点值
			for (Element elmtSub : elements) {
				List<Object> listSub=new ArrayList<Object>();
				Map<String, Object> mapSub = new HashMap<>();
				listSub=element2mapForCir(elmtSub);
//				mapSub.put(name, listSub);
				list2.add(listSub);
			}
			map.put(name, list2);
			list.add(map);
		}
		
		return list;
	}
}

<think> 我们面临的问题是将XML转换为Map后,再从中取出特定键的值并转换为List<Map<String, Object>>时,出现了类型转换异常(java.util.HashMap cannot be cast to java.util.List)。根据引用[3]中的类似问题(java.util.HashMap$Values cannot be cast to java.util.List),我们可以推断问题出在类型不匹配上。 ### 原因分析 1. **类型不匹配**:在转换过程中,我们试图将一个`Map`对象(实际上是`HashMap`)强制转换为`List`类型,而这两个类型没有继承关系,因此会抛出`ClassCastException`。 2. **数据结构理解错误**:XML转换为Map后,其结构可能并不是我们预期的。例如,假设XML结构如下: ```xml <root> <msg> <item> <key1>value1</key1> <key2>value2</key2> </item> <item> <key1>value3</key1> <key2>value4</key2> </item> </msg> </root> ``` 使用Hutool的`XmlUtil.xmlToMap`转换后,`msg`键对应的值可能是一个`Map`(代表`<msg>`元素),这个`Map`中可能有一个键(例如`item`)对应着一个`List`(当有多个`item`时)或者一个`Map`(当只有一个`item`时)。因此,如果我们直接尝试将`msg`对应的值(可能是`Map`)强制转换为`List`,就会出错。 ### 解决方案 1. **检查数据结构**:首先需要确认转换后的Map中,`msg`键对应的值的实际类型。可以通过打印其类型和内容来观察: ```java Object msgValue = map.get("msg"); System.out.println(msgValue.getClass()); // 输出实际类型 System.out.println(msgValue); // 输出内容 ``` 2. **根据实际类型处理**: - 情况1:如果`msg`对应的值是一个`List`(在多个同名的子元素时,Hutool会转换为List),那么可以直接进行转换: ```java List<Map<String, Object>> list = (List<Map<String, Object>>) map.get("msg"); ``` - 情况2:如果`msg`对应的值是一个`Map`(只有一个子元素时),那么需要将这个`Map`放入一个新的`List`中: ```java Map<String, Object> msgMap = (Map<String, Object>) map.get("msg"); List<Map<String, Object>> list = new ArrayList<>(); list.add(msgMap); ``` - 情况3:有时`msg`对应的值可能是一个`Map`,但其中包含一个键(例如`item`)对应着单个`Map`或`List<Map>`。此时我们需要根据这个键来获取: ```java Object msgValue = map.get("msg"); if (msgValue instanceof Map) { Map<String, Object> msgMap = (Map<String, Object>) msgValue; Object items = msgMap.get("item"); if (items instanceof List) { // 说明有多个item,此时items就是List<Map<String, Object>> list = (List<Map<String, Object>>) items; } else if (items instanceof Map) { // 只有一个item,将其放入List list = new ArrayList<>(); list.add((Map<String, Object>) items); } } ``` 3. **使用Hutool的转换工具**:Hutool提供了`XmlUtil`的另一个方法`xmlToBean`,可以直接将XML转换为Java对象,这样类型更安全。我们可以定义一个与XML结构对应的Java类,然后用它来接收数据。 ### 示例代码 假设XML结构如下: ```xml <response> <msg> <item> <name>John</name> <age>30</age> </item> <item> <name>Jane</name> <age>25</age> </item> </msg> </response> ``` #### 方法1:手动处理Map(根据实际结构) ```java import cn.hutool.json.XML; import java.util.ArrayList; import java.util.List; import java.util.Map; // 将XML转换为Map String xmlStr = ...; // 你的XML字符串 Map<String, Object> map = XML.xmlToMap(xmlStr); // 获取msg对应的值(是一个Map,因为<msg>是一个元素) Map<String, Object> msgMap = (Map<String, Object>) map.get("response").get("msg"); Object items = msgMap.get("item"); List<Map<String, Object>> resultList = new ArrayList<>(); if (items instanceof List) { // 多个item的情况 resultList = (List<Map<String, Object>>) items; } else if (items instanceof Map) { // 单个item的情况 resultList.add((Map<String, Object>) items); } ``` #### 方法2:使用Java Bean(推荐) 定义Java类: ```java public class Response { private List<Map<String, Object>> msg; // 或者更精确地,可以定义成List<Person>,但这里为了通用性使用Map // getter和setter } ``` 转换: ```java Response response = XML.xmlToBean(xmlStr, Response.class); List<Map<String, Object>> list = response.getMsg(); ``` ### 避免错误的关键点 1. **不要直接强制转换**:在不确定Map中值的实际类型时,不要直接将其转换为`List`,而应该先判断类型。 2. **考虑单元素和多元素的情况**:XML解析工具在处理单个元素和多个元素时行为可能不同,需要兼容两种情况。 3. **使用类型安全的转换**:如Hutool的`xmlToBean`,可以避免手动处理类型转换的麻烦。 ### 总结 出现`java.util.HashMap cannot be cast to java.util.List`错误的原因是直接强制转换了不兼容的类型。解决方案是: - 先确认实际的数据结构(打印类型和内容) - 根据实际类型进行转换(兼容单元素和多元素的情况) - 推荐使用`xmlToBean`进行类型安全的转换 通过以上方法,即可避免该错误。 --- §§相关问题§§ 1. Hutool工具中XML与Map转换的详细规则是什么? 2. 如何定义Java Bean来映射复杂的XML结构? 3. XML解析时如何处理同名元素重复出现的情况? 4. 使用Hutool的XmlUtil进行XML转换时有哪些注意事项? 5. 如何将List<Map>结构转换为XML字符串? [^1]: XML返回数据与接收类型不匹配导致的转换错误 [^2]: Gson解析JSON时LinkedTreeMap与HashMap的转换问题 [^3]: List分组转换时出现的类型转换异常 [^4]: Map转String时类型不匹配错误 </think>要解决 `java.util.HashMap cannot be cast to java.util.List` 错误,根本原因是 Hutool 的 `xmlToMap()` 方法在解析 XML 时,对于嵌套结构的处理逻辑与预期不一致。以下是详细分析和解决方案: ### 错误原因分析 1. **Hutool 的 XML 解析机制**: - 当 XML 中存在多个同名节点时,Hutool 会将其转换为 `List<Map>` 类型 - 当只有单个节点时,会直接转换为 `Map` 类型(而非包含单个元素的 List) - 错误发生在将单节点的 `Map` 对象强制转换为 `List` 类型时 2. **数据结构不匹配**: ```java // 错误转换 ❌ List<Map<String, Object>> list = (List<Map<String, Object>>) map.get("msg"); ``` 当 `msg` 对应单个节点时,实际类型是 `Map`,无法直接转换为 `List` --- ### 解决方案(3种方法) #### 方法1:类型检查 + 自动封装(推荐) ```java import cn.hutool.core.util.XmlUtil; import java.util.*; // 解析XML Map<String, Object> map = XmlUtil.xmlToMap(xmlContent); // 安全获取msg值 Object msgValue = map.get("msg"); List<Map<String, Object>> resultList = new ArrayList<>(); if (msgValue instanceof List) { // 多个节点:已经是List类型 resultList = (List<Map<String, Object>>) msgValue; } else if (msgValue instanceof Map) { // 单个节点:封装为List resultList.add((Map<String, Object>) msgValue); } // 此时resultList始终是有效的List ``` #### 方法2:强制统一为List格式(使用 Hutool 配置) ```java import cn.hutool.core.map.MapUtil; import cn.hutool.json.JSONUtil; // 转换为JSON字符串(自动处理数组格式) String json = JSONUtil.toJsonStr(map); // 重新解析为Map(强制数组转换) Map<String, Object> normalizedMap = JSONUtil.toBean(json, Map.class); // 安全获取 List<Map<String, Object>> list = (List<Map<String, Object>>) MapUtil.get(normalizedMap, "msg", Collections.emptyList()); ``` #### 方法3:自定义 XML 解析规则 ```java import org.dom4j.Document; import org.dom4j.Element; import java.util.stream.Collectors; // 使用dom4j直接解析 Document doc = new SAXReader().read(new File("data.xml")); Element root = doc.getRootElement(); List<Map<String, Object>> msgList = root.elements("msg").stream() .map(msgElement -> { Map<String, Object> itemMap = new HashMap<>(); msgElement.elements().forEach(e -> itemMap.put(e.getName(), e.getTextTrim()) ); return itemMap; }) .collect(Collectors.toList()); ``` --- ### 关键预防措施 1. **始终检查类型**: ```java // 安全转换模板 Object value = map.get(key); if (value instanceof List) { // 处理列表 } else if (value instanceof Map) { // 封装为列表 } else { // 其他类型处理 } ``` 2. **Hutool 类型提示配置**: ```java // 启用自动识别列表类型 XmlUtil.setGlobalConfig(XmlConfig.create().setIgnoreElementCase(false)); ``` 3. **数据结构验证**: ```java // 打印结构诊断 map.forEach((k, v) -> System.out.println(k + " : " + v.getClass().getSimpleName()) ); ``` --- ### 错误示例 VS 正确实践 | **场景** | **错误代码** | **正确代码** | |---------|-------------|-------------| | 单节点XML | `(List)map.get()` | 方法1的类型检查 | | 带命名空间 | 直接转换 | 自定义dom4j解析 | | 动态XML源 | 无类型检查 | 方法2的JSON中转 | > **根本原则**:Hutool 的 `xmlToMap()` 在单元素时会返回 `Map`,多元素返回 `List`。强制转换前必须进行类型检查[^1][^2]。 --- ### 结构化数据处理流程 ```mermaid graph TD A[XML输入] --> B(Hutool xmlToMap转换) B --> C{检查msg字段类型} C -->|List| D[直接使用] C -->|Map| E[封装为List] C -->|其他类型| F[转换异常处理] D --> G[得到List<Map>] E --> G F --> G ``` 通过以上方法,可彻底避免类型转换错误,并能正确处理单节点和多节点的情况。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值