5

I want to replace the node values in a xml in groovy. I have the values in xpath in a hashmap like:

 def param = [:]       
 param["/Envelope/Body/GetWeather/CityName"] = "Berlin"
 param["/Envelope/Body/GetWeather/CountryName"] = "Germany"

XML File:

 <?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope   xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header/>
  <soapenv:Body>
      <web:GetWeather xmlns:web="http://www.webserviceX.NET">
          <web:CityName>Test</web:CityName>
          <web:CountryName>Test</web:CountryName>
      </web:GetWeather>
  </soapenv:Body>
</soapenv:Envelope>

How can I replace the node values?

Peter
  • 1,011
  • 2
  • 16
  • 39

1 Answers1

3

You can try using XmlSlurper instead probably it's an easy way. You can define your map using the node name as a key and the text as a value iterate over it changing the node in the Xml. You can use something similar the code below:

import groovy.util.XmlSlurper
import groovy.xml.XmlUtil

def xmlString = '''<soapenv:Envelope   xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header/>
  <soapenv:Body>
      <web:GetWeather xmlns:web="http://www.webserviceX.NET">
          <web:CityName>Test</web:CityName>
          <web:CountryName>Test</web:CountryName>
      </web:GetWeather>
  </soapenv:Body>
</soapenv:Envelope>'''

def param = [:]       
param["CityName"] = "Berlin"
param["CountryName"] = "Germany"

// parse the xml
def xml = new XmlSlurper().parseText(xmlString)

// for each key,value in the map
param.each { key,value ->
    // change the node value if the its name matches
    xml.'**'.findAll { if(it.name() == key) it.replaceBody value }
}

println XmlUtil.serialize(xml)

Another possible solution

Instead if you want to use the complete path not only the node name to change its value (to be more robust) you can define you XPath using . notation instead of / notation and avoid root node name (in your case Envelope) because in the parsed xml object it's already there. So changing your XPath you can have something like:

def param = [:]       
// since envelope is the root node it's not necessary
param["Body.GetWeather.CityName"] = "Berlin"
param["Body.GetWeather.CountryName"] = "Germany"

All together in the code:

import groovy.util.XmlSlurper
import groovy.xml.XmlUtil

def xmlString = '''<soapenv:Envelope   xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header/>
  <soapenv:Body>
      <web:GetWeather xmlns:web="http://www.webserviceX.NET">
          <web:CityName>Test</web:CityName>
          <web:CountryName>Test</web:CountryName>
      </web:GetWeather>
  </soapenv:Body>
</soapenv:Envelope>'''

def param = [:]       
// since envelope is the root node it's not necessary
param["Body.GetWeather.CityName"] = "Berlin"
param["Body.GetWeather.CountryName"] = "Germany"

def xml = new XmlSlurper().parseText(xmlString)

param.each { key,value ->
    def node = xml
    key.split("\\.").each {
      node = node."${it}"
    }
    node.replaceBody value
}

println XmlUtil.serialize(xml)

Note that in the second solution I use this snippet:

    def node = xml
    key.split("\\.").each {
      node = node."${it}"
    }

This snippet it's from this answer and comment which is a workaround to solve . path based using variables (a good workaround IMO :))

Hope this helps,

Community
  • 1
  • 1
albciff
  • 18,112
  • 4
  • 64
  • 89
  • Hi, this helps for this example, but I need something more generic. For example when the xml looks like how should I deal with this? Thats way i wanted to use xpath – Peter May 21 '15 at 12:00
  • @Peter You can use the second approach in the answer, with the second approach you can add the `path` to your elements in your map. – albciff May 21 '15 at 12:02
  • Hi, I have to try your another solution, just tried the first one – Peter May 21 '15 at 12:04
  • @Peter nice, hope it helps `:)` – albciff May 21 '15 at 12:05