You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Groovy使用StreamingMarkupBuilder向闭包传参生成XML的实现问题

问题说明

运行环境:Groovy 2.4, Spring 5.3.13
使用StreamingMarkupBuilder生成XML序列化输出未达预期,原有代码框架如下:

public void createMsgToStreamOut( String strCreatedAt, String strEntity, String strIdNum, String strEvent) {
    def streamBuilder = new StreamingMarkupBuilder();
    streamBuilder.encoding = "UTF-8"
    def xml = streamBuilder.bind{ strCreatedAt, strEntity, strIdNum, strEvent -> 
        >> some magic goes here
    }
    def xmlStr = XmlUtil.serialize( xml)
    println xmlStr;
}

createMsgToStreamOut( "2022-09-10T12:13:14.567", "Matter", "907856", "create");

预期输出XML结构:

<?xml version="1.0" encoding="UTF-8"?>
<message>
  <timestamp>2022-09-10T12:13:14.567</timestamp>
  <entity>Matter</entity>
  <number>907856</number>
  <event>create</event>
</message>

需求为实现bind闭包参数传入、符合要求的XML生成逻辑,同时支持后续输出流对接Kafka生产者。

实现方案

原有代码核心错误:StreamingMarkupBuilder的bind方法接收的闭包无需在参数列表重复声明外层方法入参,重复声明会导致参数被识别为闭包内部未赋值的绑定变量,无法获取实际传入值。闭包可直接访问外层作用域的方法参数。

基础生成打印实现

import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil

void createMsgToStreamOut(String strCreatedAt, String strEntity, String strIdNum, String strEvent) {
    def streamBuilder = new StreamingMarkupBuilder()
    streamBuilder.encoding = "UTF-8"
    def xml = streamBuilder.bind {
        message {
            timestamp(strCreatedAt)
            entity(strEntity)
            number(strIdNum)
            event(strEvent)
        }
    }
    def xmlStr = XmlUtil.serialize(xml)
    println xmlStr
}

// 测试调用
createMsgToStreamOut("2022-09-10T12:13:14.567", "Matter", "907856", "create")

运行后可直接输出符合预期格式的XML内容。

对接Kafka流式实现

无需先生成完整字符串再发送,直接对接输出流可降低内存占用:

import groovy.xml.StreamingMarkupBuilder
import org.apache.kafka.clients.producer.KafkaProducer
import org.apache.kafka.clients.producer.ProducerRecord
import java.io.ByteArrayOutputStream

void sendMsgToKafka(String strCreatedAt, String strEntity, String strIdNum, String strEvent, KafkaProducer<String, byte[]> kafkaProducer, String kafkaTopic) {
    def streamBuilder = new StreamingMarkupBuilder()
    streamBuilder.encoding = "UTF-8"
    
    def xmlClosure = {
        message {
            timestamp(strCreatedAt)
            entity(strEntity)
            number(strIdNum)
            event(strEvent)
        }
    }

    // 直接写入输出流,跳过中间字符串生成
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream()
    outputStream.withWriter("UTF-8") { writer ->
        writer << streamBuilder.bind(xmlClosure)
    }

    // 组装消息发送到Kafka
    ProducerRecord<String, byte[]> record = new ProducerRecord<>(kafkaTopic, outputStream.toByteArray())
    kafkaProducer.send(record)
}

注意事项

  • 若需显式给bind闭包传参,可通过闭包Binding对象设置变量后传入,当前场景直接访问外层方法参数是最简洁的实现
  • Groovy 2.4版本下XmlUtil.serialize会自动按照设置的编码生成XML声明头,无需额外配置
  • 高性能场景下可直接将Writer对接Kafka的字节缓冲区,避免ByteArrayOutputStream的额外内存拷贝

内容的提问来源于stack exchange,提问作者code_warrior

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 18:27:33