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

Spring Boot升级至2.5.0后XmlUtil.serialize抛出XML格式异常

Spring Boot升级后XmlUtil.serialize解析XML报错

将Spring Boot版本从2.4.13升级至2.5.0后,调用XmlUtil.serialize(parseXml)时触发以下错误:

groovy.lang.GroovyRuntimeException: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 2; The markup in the document preceding the root element must be well-formed

相关代码

XML格式化实现代码:

def formatXML(xmlInput) {
        def parseXml = null
    def formatXml = null
    if (xmlInput != null) {
        try {
            // Log the input XML content
           logger.debug("formatXml:"+xmlInput)

            // Parse the XML content
            parseXml = new XmlParser().parseText(xmlInput)
            logger.debug("parseXml:"+parseXml)
            // Serialize the parsed XML
            formatXml = XmlUtil.serialize(parseXml)
            
            // Log the formatted XML content
            println "Formatted XML: $formatXml"
        } catch (Exception e) {
            println "Error during XML formatting: $e"
            throw e
        }
    }
    return formatXml
}

解析后的XML对象

{http://ecomp.att.com/mso/request/vnfactivate/schema/v1}service-response[attributes={}; value=[{http://ecomp.att.com/mso/request/types/v1}request-id[attributes={}; value=[4c421bc2-9ed9-4b2b-88c3-e10dbbcc85b5]], {http://ecomp.att.com/mso/request/types/v1}request-action[attributes={}; value=[DisconnectLayer3Service]], {http://ecomp.att.com/mso/request/types/v1}source[attributes={}; value=[CCD]], {http://ecomp.att.com/mso/request/types/v1}ack-final-indicator[attributes={}; value=[n]]]]

输入的XML内容

<vnfactivate:service-response xmlns:vnfactivate="http://ecomp.att.com/mso/request/vnfactivate/schema/v1"
                                                xmlns:reqtype="http://ecomp.att.com/mso/request/types/v1">
                                        <reqtype:request-id>4c421bc2-9ed9-4b2b-88c3-e10dbbcc85b5</reqtype:request-id>
                                        <reqtype:request-action>DisconnectLayer3Service</reqtype:request-action>
                                        <reqtype:source>CCD</reqtype:source>
                                        <reqtype:ack-final-indicator>n</reqtype:ack-final-indicator>
                                </vnfactivate:service-response>

问题原因及解决方案

原因分析

Spring Boot 2.5.x升级了Groovy版本(从2.4.x配套的Groovy 2.5.x升级到Groovy 3.x),Groovy 3.x对XmlUtil.serialize()的行为做了变更:处理带命名空间的XML时,默认输出的XML格式存在异常(比如根元素前出现多余字符、命名空间前缀未正确绑定),触发SAX解析错误。

解决方案

方案1:用StreamingMarkupBuilder替代XmlUtil.serialize

手动构建XML输出,确保命名空间正确处理:

def formatXML(xmlInput) {
    def parseXml = null
    def formatXml = null
    if (xmlInput != null) {
        try {
            logger.debug("formatXml:" + xmlInput)
            parseXml = new XmlParser().parseText(xmlInput)
            logger.debug("parseXml:" + parseXml)
            
            // 使用StreamingMarkupBuilder序列化
            def writer = new StringWriter()
            def markupBuilder = new groovy.xml.StreamingMarkupBuilder()
            markupBuilder.encoding = "UTF-8"
            writer.write('<?xml version="1.0" encoding="UTF-8"?>\n')
            writer.write(markupBuilder.bind {
                mkp.declareNamespace(vnfactivate: "http://ecomp.att.com/mso/request/vnfactivate/schema/v1",
                                    reqtype: "http://ecomp.att.com/mso/request/types/v1")
                delegate.clone(parseXml)
            }.toString())
            formatXml = writer.toString()
            
            println "Formatted XML: $formatXml"
        } catch (Exception e) {
            println "Error during XML formatting: $e"
            throw e
        }
    }
    return formatXml
}

方案2:配置XmlUtil.serialize的输出属性

通过Apache XML Serializer的OutputFormat指定正确的命名空间处理规则:

import org.apache.xml.serialize.OutputFormat
import org.apache.xml.serialize.XMLSerializer

def formatXML(xmlInput) {
    def parseXml = null
    def formatXml = null
    if (xmlInput != null) {
        try {
            logger.debug("formatXml:" + xmlInput)
            parseXml = new XmlParser().parseText(xmlInput)
            logger.debug("parseXml:" + parseXml)
            
            // 配置输出格式
            def outputFormat = new OutputFormat()
            outputFormat.setEncoding("UTF-8")
            outputFormat.setIndenting(true)
            outputFormat.setIndent(4)
            outputFormat.setNamespaceAware(true)
            
            def writer = new StringWriter()
            def serializer = new XMLSerializer(writer, outputFormat)
            serializer.serialize(parseXml)
            formatXml = writer.toString()
            
            println "Formatted XML: $formatXml"
        } catch (Exception e) {
            println "Error during XML formatting: $e"
            throw e
        }
    }
    return formatXml
}

方案3:降级Groovy版本(不推荐)

若暂时无法修改代码,可在依赖管理中强制指定Groovy版本为2.5.x:
Maven

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.5.14</version>
            <type>pom</type>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Gradle

dependencies {
    implementation('org.codehaus.groovy:groovy-all:2.5.14') {
        force = true
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 20:42:14