Groovy/XSLT实现可变User节点XML到SOAP结构的转换问询
如何将包含可变节点的源XML转换为指定SOAP格式的目标XML?
我最近碰到一个XML转换的需求,需要把一个带有数量可变<User>节点的源XML转换成指定结构的SOAP格式目标XML。我一开始尝试用字符串拼接来构建目标结构,但卡在了动态迭代<User>节点生成对应<object>节点的环节,想请教下有没有Groovy脚本或者XSLT的解决方案。
源XML结构
<?xml version="1.0" encoding="UTF-8"?> <Response> <User> <person> <person_id>1234</person_id> </person> </User> <User> <person> <person_id>5678</person_id> </person> </User> </Response>
目标XML结构要求
<?xml version="1.0" encoding="UTF-8"?> <S:Body xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <queryResponse xmlns="urn:test.com" xmlns:ns2="urn:example.com"> <result> <object> <id>1234(*person_id from source message*)</id> <type>Employee</type> <person>*here the whole person number 1 object from source XML must be inserted*</person> <execution_timestamp></execution_timestamp> <version_id></version_id> </object> <object> <id>5678(*person_id from source message*)</id> <type>Employee</type> <person>*here the whole person number 2 object from source XML must be inserted*</person> <execution_timestamp></execution_timestamp> <version_id></version_id> </object> <numResults>*number of Users from source XML must be inserted here(in this case 2)*</numResults> </result> </queryResponse> </S:Body>
核心需求
- 每个源XML中的
<User>节点对应目标XML里的一个<object>节点 <object>的<id>字段取对应<User>下的<person_id>值<object>的<person>节点完整复制源XML中对应的<person>内容<numResults>字段填充源XML中<User>节点的总数量
方案一:XSLT转换(推荐)
XSLT是专门为XML转换设计的工具,非常适配这类场景,下面是完整的转换样式表:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:test.com" xmlns:ns2="urn:example.com"> <!-- 输出配置:格式化XML,保留UTF-8编码 --> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <!-- 匹配源XML的根节点<Response> --> <xsl:template match="/Response"> <S:Body> <queryResponse> <result> <!-- 遍历所有<User>节点,生成对应的<object> --> <xsl:for-each select="User"> <object> <!-- 提取person_id作为id值 --> <id><xsl:value-of select="person/person_id"/></id> <type>Employee</type> <!-- 完整复制整个<person>节点 --> <xsl:copy-of select="person"/> <execution_timestamp/> <version_id/> </object> </xsl:for-each> <!-- 统计<User>节点的总数量 --> <numResults><xsl:value-of select="count(User)"/></numResults> </result> </queryResponse> </S:Body> </xsl:template> </xsl:stylesheet>
使用方式:你可以用任何支持XSLT 1.0的工具(比如Java的TransformerFactory、在线XML转换工具),将源XML和上述XSLT文件作为输入,即可生成符合要求的SOAP XML。
方案二:Groovy脚本实现
Groovy对XML的解析和生成非常便捷,借助XmlSlurper(解析源XML)和MarkupBuilder(生成目标XML)可以快速实现需求:
@Grab('org.codehaus.groovy:groovy-xml:3.0.17') import groovy.xml.XmlSlurper import groovy.xml.MarkupBuilder // 读取源XML(可替换为文件读取:new File('source.xml').text) def sourceXml = '''<?xml version="1.0" encoding="UTF-8"?> <Response> <User> <person> <person_id>1234</person_id> </person> </User> <User> <person> <person_id>5678</person_id> </person> </User> </Response>''' // 解析源XML def response = new XmlSlurper().parseText(sourceXml) def users = response.User // 生成目标SOAP XML def writer = new StringWriter() def xmlBuilder = new MarkupBuilder(writer) xmlBuilder.setDoubleQuotes(true) xmlBuilder.mkp.xmlDeclaration(version: '1.0', encoding: 'UTF-8') xmlBuilder.'S:Body'(xmlns:S: 'http://schemas.xmlsoap.org/soap/envelope/') { 'queryResponse'(xmlns: 'urn:test.com', 'xmlns:ns2': 'urn:example.com') { result { // 遍历每个<User>生成对应的<object> users.each { user -> object { id(user.person.person_id.text()) type('Employee') // 完整复制<person>节点内容 mkp.yieldUnescaped(user.person.toString()) execution_timestamp() version_id() } } // 填充<User>节点数量 numResults(users.size()) } } } // 输出转换后的XML println writer.toString()
运行说明:直接执行该Groovy脚本,会在控制台输出符合要求的SOAP XML,你可以根据实际需求调整源XML的读取方式。
内容的提问来源于stack exchange,提问作者Phalanx
相关产品推荐
相关产品推荐

