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
相关产品推荐
相关产品推荐

