JAXB如何对HashMap<String, HashMap<String, String>>进行编组生成XML
嵌套HashMap生成指定格式XML的可行方案
方案1:自定义JAXB XmlAdapter适配嵌套Map结构
JAXB默认对Map的序列化格式不符合要求的核心原因是默认的Map适配器会生成<entry key="xxx" value="xxx"/>结构,你可以自己实现XmlAdapter来改写序列化逻辑,适配任意深度的嵌套Map:
- 第一步:定义适配器类,递归处理Map嵌套场景
import javax.xml.bind.annotation.adapters.XmlAdapter; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Element; import org.w3c.dom.Document; import java.util.Map; public class NestedMapAdapter extends XmlAdapter<Object, Map<String, Object>> { @Override public Object marshal(Map<String, Object> map) throws Exception { Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); Element root = doc.createElement("map"); buildMapElement(doc, root, map); return root; } private void buildMapElement(Document doc, Element parent, Map<String, Object> map) { for (Map.Entry<String, Object> entry : map.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); Element keyElement = doc.createElement(key); if (value instanceof Map) { Element innerMap = doc.createElement("map"); buildMapElement(doc, innerMap, (Map<String, Object>) value); keyElement.appendChild(innerMap); } else { keyElement.setTextContent(value.toString()); } parent.appendChild(keyElement); } } @Override public Map<String, Object> unmarshal(Object v) throws Exception { // 不需要反序列化可以留空,按需实现 return null; } }
- 第二步:在你要序列化的类的Map字段上加上注解,指定使用自定义适配器:
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import java.util.Map; @XmlRootElement public class YourDataWrapper { @XmlJavaTypeAdapter(NestedMapAdapter.class) private Map<String, Object> data; // 按需补充getter、setter方法 }
之后正常调用JAXB的序列化逻辑就能生成你要的格式。
方案2:直接用StAX流式写XML,不需要依赖JAXB
如果不想折腾JAXB的适配逻辑,对性能要求高或者嵌套层级非常深,可以直接用JDK自带的StAX API手写生成,逻辑更直观可控:
import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamWriter; import java.io.StringWriter; import java.util.Map; public class MapToXmlGenerator { public String generate(Map<String, Object> rootMap) throws Exception { StringWriter sw = new StringWriter(); XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(sw); // 写根map标签 writer.writeStartElement("map"); writeMapContent(writer, rootMap, " "); writer.writeEndElement(); writer.flush(); return sw.toString(); } private void writeMapContent(XMLStreamWriter writer, Map<String, Object> map, String indent) throws Exception { for (Map.Entry<String, Object> entry : map.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); // 写入换行和缩进保证格式工整 writer.writeCharacters("\n" + indent); writer.writeStartElement(key); if (value instanceof Map) { // 处理嵌套Map场景 writer.writeCharacters("\n" + indent + " "); writer.writeStartElement("map"); writeMapContent(writer, (Map<String, Object>) value, indent + " "); writer.writeCharacters("\n" + indent + " "); writer.writeEndElement(); writer.writeCharacters("\n" + indent); } else { // 普通值直接写入文本内容 writer.writeCharacters(value.toString()); } writer.writeEndElement(); } writer.writeCharacters("\n" + indent.substring(0, Math.max(0, indent.length() - 4))); } }
这种方式不需要额外引入第三方依赖,生成的XML格式可以完全自定义,缩进规则也能自行调整。
方案3:用模板引擎生成
如果生成逻辑后续可能经常调整,不想频繁修改Java代码,可以用FreeMarker、Thymeleaf这类模板引擎,提前写好XML模板,把嵌套Map作为参数传入渲染即可,适合需要灵活调整XML结构的场景。
内容的提问来源于stack exchange,提问作者Ghosterus
相关产品推荐
相关产品推荐

