Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy replace node values in xml with xpath

Tags:

xml

groovy

xpath

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?

like image 998
Peter Avatar asked Oct 19 '22 11:10

Peter


1 Answers

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,

like image 168
albciff Avatar answered Oct 22 '22 00:10

albciff