Search code examples
groovyxmlslurper

Groovy XmlSlurper replace node with given child node value


I'd be grateful for help with the following problem. (I am new to Groovy, and I can't find any specific examples addressing my issue).

Using XmlSlurper I am trying to replace an XML node which has a child with a certain value. For example, I want to transform:

<assets>
    <!--zero to many asset nodes beforehand-->
    <asset>
        <name>MyPackageName</name>
        <data>
            <stringValue>my string value</stringValue>
        </data>
    </asset>
    <!--zero to many asset nodes afterwards-->
</assets>

into:

<assets>
    <!--zero to many asset nodes beforehand-->
    <asset>
        <name>MyPackageName</name>
        <data/>
    </asset>
    <!--zero to many asset nodes afterwards-->
</assets>

I can't find any examples of code which navigate to find my asset with the name MyPackageName.

My failing attempt is:

    def assets = new XmlSlurper().parseText(deviceXml)
    assets.asset[name.text()=="MyPackageName"].replaceNode{
        asset{
            name("MyPackageName")
            data()
        }
    }

I get a groovy.lang.MissingPropertyException exception for a missing property for "asset" so clearly my syntax to find my node is wrong.


Solution

  • The following example does the job:

    import groovy.xml.XmlUtil
    import groovy.xml.StreamingMarkupBuilder
    
    def input = '''<assets>
        <!--zero to many asset nodes beforehand-->
        <asset>
            <name>MyPackageName</name>
            <data>
                <stringValue>my string value</stringValue>
            </data>
        </asset>
        <!--zero to many asset nodes afterwards-->
    </assets>'''
    
    def xml = new XmlSlurper().parseText(input)
    
    xml.asset.data.replaceNode {}
    
    println XmlUtil.serialize(new StreamingMarkupBuilder().bind {
      mkp.yield xml
    } )
    

    The second way of updating it:

    import groovy.xml.XmlUtil
    import groovy.xml.StreamingMarkupBuilder
    
    def input = '''<assets>
        <!--zero to many asset nodes beforehand-->
        <asset>
            <name>MyPackageName</name>
            <data>
                <stringValue>my string value</stringValue>
            </data>
        </asset>
        <!--zero to many asset nodes afterwards-->
    </assets>'''
    
    def assets = new XmlSlurper().parseText(input)
    assets.asset.replaceNode {
        asset {
            name("MyPackageName")
            data()
        }
    }
    
    println XmlUtil.serialize(new StreamingMarkupBuilder().bind {
      mkp.yield assets
    } )
    

    With looking for a particular node:

    import groovy.xml.XmlUtil
    import groovy.xml.StreamingMarkupBuilder
    
    def input = '''<assets>
        <!--zero to many asset nodes beforehand-->
        <asset>
            <name>MyPackageName</name>
            <data>
                <stringValue>my string value</stringValue>
            </data>
        </asset>
        <!--zero to many asset nodes afterwards-->
    </assets>'''
    
    def assets = new XmlSlurper().parseText(input)
    assets.asset.find {it.name.text() == 'MyPackageName' }. replaceNode {
        asset {
            name("MyPackageName")
            data()
        }
    }
    
    println XmlUtil.serialize(new StreamingMarkupBuilder().bind {
      mkp.yield assets
    } )