Jonas Praem
Jonas Praem

Reputation: 2454

How to modify XML node value, when iterating through the file with XMLSlurper

I am currently iterating through an XML file like this:

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

root.service.each { service ->
  service.receiver.endpoint.each { endpoint ->
    println "\t\tEndpoint: ${endpoint.text()}"
    }
}

I want to first read the endpoint.text() , and afterwards modify the value of the node, so the file contains a new value. I am reading the node attributes fine, as it is. But how do I write to it afterwards?

I looked at this question, and understand how to write to an existing file. But what I am asking is, can it be done in a more elegant matter, when I am already iterating through the file to read some of it's content? I am hoping there is a more efficient way that suits the way I am iteraring through the file.

So am hoping there is a way to do something like this:

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

root.service.each { service ->
  service.receiver.endpoint.each { endpoint ->
    println "\t\tEndpoint: ${endpoint.text()}"
    // ****WRITE TO NODE****
    }
}

hope it makes sense.

Also, here is some example XML:

<project name='Common'>
  <service name='name' pattern='something' isReliable='maybe'>
    <receiver name='name' isUsingTwoWaySsl='maybe' isWsRmDisabled='maybe' 
       targetedByTransformation='maybe'>
      <endpoint name='local_tst01'>URL</endpoint>
      <endpoint name='local_tst02'>URL</endpoint>
      <endpoint name='local_tst03'>URL</endpoint>
      <environment name='dev' default='local_dev' />
      <environment name='tst01' default='test' />
      <environment name='tst02' default='local_tst02' />
    </receiver>
    <operation name='name'>
      <sender>sender</sender>
      <attribute name='operation' type='String'>name</attribute>
    </operation>
  </service>
</project>

Upvotes: 3

Views: 8353

Answers (2)

Rao
Rao

Reputation: 21389

Here is the little variant to update the endpoints.

This is flexible so that you can choose what endpoint will need to have the new url as per the name attribute as defined in the below endpointBinding map. Of course, you can change the values as needed.

//Set your endpoint name attribute value and new endpoint url in a map
//This would be flexible to have the respective url
def endpointBinding = ['local_tst01': 'http://example01.com', 'local_tst02': 'http://example02.com', 'local_tst03': 'http://example03.com']

pXml = new XmlSlurper().parseText(xml)

//Update the values in xml as per the binding defined above
endpointBinding.collect { k, v -> pXml.'**'.find{it.name() == 'endpoint' && it.@name == k }.replaceBody(v) }    

println groovy.xml.XmlUtil.serialize( pXml )

You can quickly try the same online Demo

Upvotes: 2

daggett
daggett

Reputation: 28634

don't know why replaceBody method is protected but it works:

def root = new XmlSlurper().parseText(
'''<root>
    <service>
        <receiver>
            <endpoint>123</endpoint>
            <endpoint>456</endpoint>
        </receiver>
    </service>
</root>''')

root.service.each { service ->
    service.receiver.endpoint.each { endpoint ->
        endpoint.replaceBody("**"+endpoint.text())
    }
}

println groovy.xml.XmlUtil.serialize( root )

Upvotes: 4

Related Questions