基于Groovy多级Map递归生成带属性与子节点的XML方案问询
嘿,我刚好折腾过类似的需求!用Groovy的MarkupBuilder来递归处理这种每层都带attributes和elements的嵌套Map生成XML,简直是量身定做的方案,比手动拼接字符串舒服太多了。
我直接给你上可运行的代码示例,再拆解关键点:
第一步:定义你的嵌套Map结构
先模拟一个符合你要求的多层数据结构(你可以直接替换成自己的真实数据):
def xmlData = [ // 顶层(根节点)的属性 attributes: [xmlVersion: "1.0", lang: "en"], // 根节点下的子元素列表 elements: [ [ name: "user", attributes: [id: "1001", status: "active"], elements: [ [name: "name", text: "John Doe"], [name: "contact", attributes: [type: "email"], text: "john@example.com"], [ name: "address", attributes: [zip: "90210"], elements: [ [name: "street", text: "123 Main St"], [name: "city", text: "Los Angeles"] ] ] ] ], [ name: "user", attributes: [id: "1002", status: "inactive"], elements: [ [name: "name", text: "Jane Smith"] ] ] ] ]
第二步:编写递归构建XML的函数
核心就是利用MarkupBuilder的闭包特性,递归遍历每个层级的元素:
import groovy.xml.MarkupBuilder def buildXmlNode(MarkupBuilder builder, Map nodeData) { // 处理节点的必填/可选字段,避免空指针 def nodeName = nodeData.name ?: "unknown-node" def nodeAttrs = nodeData.attributes ?: [:] def childElements = nodeData.elements ?: [] def nodeText = nodeData.text ?: "" // 动态创建节点:用GString指定节点名,传入属性Map builder."${nodeName}"(nodeAttrs) { // 如果节点有文本内容,先输出文本 if (nodeText) { mkp.yield(nodeText) } // 递归处理所有子元素 childElements.each { child -> buildXmlNode(builder, child) } } }
第三步:生成并输出XML
把递归函数和MarkupBuilder结合起来,生成最终的XML字符串:
def writer = new StringWriter() def xmlBuilder = new MarkupBuilder(writer) // 先创建根节点(这里我把根节点名设为"root",你可以根据需求修改) xmlBuilder.root(xmlData.attributes) { // 递归处理根节点下的所有子元素 xmlData.elements.each { childNode -> buildXmlNode(xmlBuilder, childNode) } } // 打印生成的XML println writer.toString()
运行结果
上面的代码会生成这样的XML(自动格式化,可读性拉满):
<root xmlVersion='1.0' lang='en'> <user id='1001' status='active'> <name>John Doe</name> <contact type='email'>john@example.com</contact> <address zip='90210'> <street>123 Main St</street> <city>Los Angeles</city> </address> </user> <user id='1002' status='inactive'> <name>Jane Smith</name> </user> </root>
关键细节说明
- 动态节点名:用
builder."${nodeName}"这种GString语法,完美支持从Map里读取节点名称,不用写死节点类型 - 空值容错:用
?:运算符处理缺失的attributes、elements字段,避免运行时抛出空指针异常 - 文本内容支持:额外加了
text字段的处理,如果你不需要可以直接删掉这部分逻辑 - 递归逻辑:在节点的闭包内部递归调用
buildXmlNode,自动维护XML的嵌套结构,完全不用手动管理标签的开闭
要是你还有特殊需求(比如自定义XML声明、命名空间、格式化规则),直接在MarkupBuilder初始化的时候加参数就行,比如:
// 开启缩进,指定编码,添加XML声明 def xmlBuilder = new MarkupBuilder(writer) xmlBuilder.setDoubleQuotes(true) // 用双引号包裹属性值 xmlBuilder.setIndent(" ") // 缩进用两个空格 xmlBuilder.mkp.xmlDeclaration(version: "1.0", encoding: "UTF-8")
内容的提问来源于stack exchange,提问作者Asinus Rex
相关产品推荐
相关产品推荐

