Jonas Praem
Jonas Praem

Reputation: 2444

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

In extension to this question, I am now trying to replace the XML node's attribute.

I am already writing to the body of the XML using the below code.

def root = new XmlSlurper().parseText(
'''<root>
     <service>
       <receiver>
         <endpoint type="type1">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 )

I want to check if the type attribute exists. If it does I want to change its value to say "type2".

Is there an equivalent method to replaceBody() which replaces attributes?

or do I have to implement this differently?

Upvotes: 1

Views: 5274

Answers (2)

Rao
Rao

Reputation: 21369

Here is just one-liner to update the required attribute:

root.'**'.findAll{it.name() == 'endpoint' && it.attributes().get('type') }*.@type= 'type_value'

Below is the additional info based on referring to the previous questions data. Let us assume that there are more endpoints such local_tst01, local_tst02 and you want to have different type value (do not want the same type value for each of the endpoint for the sake of flexibility). In that case, you can use below script.

Here also you can use a map of endpoint name and desired type value as below:

typeBinding = ['local_tst01': 'type01', 'local_tst02': 'type02', 'local_tst03': 'type03']

However, let us assume that there is no type for endpoint and as per the OP, type should not be there in the output for the endpoint whose name is local_tst03, say:

<endpoint name='local_tst01' type='123'>URL1</endpoint>
<endpoint name='local_tst02' type='xyz'>URL2</endpoint>
<endpoint name='local_tst03'>URL3</endpoint>

Here is complete script:

def xml = """<project name='Common'>
  <service name='name' pattern='something' isReliable='maybe'>
    <receiver name='name' isUsingTwoWaySsl='maybe' isWsRmDisabled='maybe' 
       targetedByTransformation='maybe'>
      <endpoint name='local_tst01' type='123'>URL1</endpoint>
      <endpoint name='local_tst02' type='xyz'>URL2</endpoint>
      <endpoint name='local_tst03'>URL3</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>"""


//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']
def typeBinding = ['local_tst01': 'type01', 'local_tst02': 'type02', 'local_tst03': 'type03']
pXml = new XmlSlurper().parseText(xml)
//update endpoint value
endpointBinding.collect { k, v -> pXml.'**'.find{it.name() == 'endpoint' && it.@name == k }.replaceBody(v)}

//update type
typeBinding.collect { k, v -> pXml.'**'.find{it.name() == 'endpoint' && it.attributes().get('type') && it.@name == k }?.@type = v}  

println groovy.xml.XmlUtil.serialize( pXml )

​You can quickly try this online Demo

Upvotes: 4

daggett
daggett

Reputation: 28564

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

root.service.each { service ->
    service.receiver.endpoint.each { endpoint ->
        endpoint.replaceBody("**"+endpoint.text())
        if(endpoint.@type=='type1')endpoint.@type='type-01'
        else endpoint.@type='type-99'
    }
}

println groovy.xml.XmlUtil.serialize( root )

or you can get all attributes as a Map with endpoint.attributes()

Upvotes: 1

Related Questions