如何将自定义节点作为multimap:Message1的首个子节点插入XML?
问题
使用XMLSlurper读取现有XML文件,需将自定义创建的结构插入指定位置——作为multimap:Message1的首个子节点。目前xml.append()会将节点添加到XML末尾,尝试多种方法均未成功,怀疑是命名空间前缀导致问题。
源XML内容
<?xml version='1.0' encoding='UTF-8'?> <multimap:Messages xmlns:multimap="http://example.com"> <multimap:Message1> <ns1:CostCenter xmlns:ns1="urn:example-com"> <item> <POSID>123</POSID> <POSID_FORMATED>P.12.3</POSID_FORMATED> <YYBEZ>Apple</YYBEZ> </item> <item> <POSID>456</POSID> <POSID_FORMATED>P.45.6</POSID_FORMATED> <YYBEZ>Banana</YYBEZ> </item> </ns1:CostCenter> <ns0:CostCenter xmlns:ns0="urn:sap-com:document:sap:rfc:functions"> <item> <KOSTL>0815</KOSTL> <LTEXT_DE>Supermarket</LTEXT_DE> </item> <item> <KOSTL>6666</KOSTL> <LTEXT_DE>Online Shop</LTEXT_DE> </item> </ns0:CostCenter> </multimap:Message1> </multimap:Messages>
当前代码
def Message processData() { def countries = ["DE","SP","IT"] def countriesCode = ["Germany","Spain","Italy"] def countryList = new Node(null, "CountryList") countries.eachWithIndex { country, index -> def part = countryList.appendNode("part") part.appendNode("CountryCode", countriesCode[index]?.trim()) part.appendNode("Country", country?.trim()) } // 使用xml.append(countryList)会将节点添加到XML末尾 // 以下代码会将节点添加到multimap:Messages标签之后,但无法放入multimap:Message1下 xml.children().add(1,countryList) def updatedXml = XmlUtil.serialize(xml) }
尝试过的方法:
- 使用路径
xml.Message1.children().add(1,countryList) - 使用
replaceBody()函数 - 查找节点:
def msg1Node = xml.'multimap:Message1'.first()后尝试添加
解决方案
核心问题是命名空间的正确引用和XMLSlurper返回的GPathResult与Node对象的兼容处理,按以下方式修改代码即可实现需求:
方法一:直接在目标节点下创建结构(推荐)
避免Node与GPathResult的兼容问题,直接在multimap:Message1节点内创建并插入自定义结构:
def Message processData() { def countries = ["DE","SP","IT"] def countriesCode = ["Germany","Spain","Italy"] // 定义multimap命名空间的完整URI def multimapNs = "http://example.com" // 获取目标节点multimap:Message1 def msg1Node = xml."${multimapNs}:Message1".first() // 先保存原有的子节点 def originalChildren = msg1Node.children().collect() // 清空目标节点,先添加自定义的CountryList msg1Node.children().clear() def countryList = msg1Node.appendNode("CountryList") // 填充CountryList的内容 countries.eachWithIndex { country, index -> def part = countryList.appendNode("part") part.appendNode("CountryCode", countriesCode[index]?.trim()) part.appendNode("Country", country?.trim()) } // 把原有的子节点添加回目标节点,确保CountryList是首个子节点 originalChildren.each { msg1Node.append(it) } def updatedXml = XmlUtil.serialize(xml) return updatedXml }
方法二:转换Node为GPathResult后插入
如果坚持先用Node创建自定义结构,可将其序列化为XML字符串后再解析为GPathResult对象:
def Message processData() { def countries = ["DE","SP","IT"] def countriesCode = ["Germany","Spain","Italy"] def multimapNs = "http://example.com" // 创建自定义Node结构 def countryList = new Node(null, "CountryList") countries.eachWithIndex { country, index -> def part = countryList.appendNode("part") part.appendNode("CountryCode", countriesCode[index]?.trim()) part.appendNode("Country", country?.trim()) } // 将Node转换为XML字符串并去掉声明,再解析为GPathResult def countryListXml = XmlUtil.serialize(countryList).replaceAll(/<\?xml.*?\>/, "") def countryListNode = new XmlSlurper().parseText(countryListXml) // 获取目标节点并插入自定义结构到首位 def msg1Node = xml."${multimapNs}:Message1".first() def originalChildren = msg1Node.children().collect() msg1Node.children().clear() msg1Node.append(countryListNode) originalChildren.each { msg1Node.append(it) } def updatedXml = XmlUtil.serialize(xml) return updatedXml }
关键说明
- 定位命名空间节点时,必须使用完整的命名空间URI而非前缀,XMLSlurper内部通过URI识别命名空间,前缀仅为别名。
- 操作GPathResult的子节点时,需先收集原有子节点、清空后重新添加,确保自定义结构处于首位。
内容的提问来源于stack exchange,提问作者ChrisMS
相关产品推荐
相关产品推荐

