Search

Dark theme | Light theme
Showing posts with label Groovy:Goodness GroovyGoodness:XML. Show all posts
Showing posts with label Groovy:Goodness GroovyGoodness:XML. Show all posts

May 26, 2011

Groovy Goodness: Change XML Structure

We know how easy it is to read XML and to write XML. Recently someone asked during a workshop if it is possible to change the XML structure as easy. I found the answer on the Groovy website. It turns out we can simple use XmlSlurper and we can traverse the structure to change existing node values and attributes. We use appendNode() and replaceNode() to work with nodes using a builder syntax.

@Grapes(
    @Grab(group='xmlunit', module='xmlunit', version='1.3')
)
import org.custommonkey.xmlunit.*
import groovy.xml.*

def xml = '''
<todo>
    <item priority="2">
        <title>Look into GPars</title>
    </item>
    <item priority="1">
        <title>Start developing Griffon App</title>
    </item>
    <item priority="2">
        <title>Grails 1.4 M1</title>
    </item>
    <item priority="3">
        <title>GWT Sample</title>
    </item>
</todo>
'''

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

// Change node values.
def items = todo.item.findAll { 
   it.@priority.toInteger() < 3 
}
items.each { item -> 
    item.title = "DO: " + item.title 
}

// Change attribute value.
def gpars= todo.item.find { 
    it.title =~ /.*GPars.*/ 
}
gpars.@priority = '1'

// Add extra item node.
todo.appendNode {
    item(priority: 2) {
        title 'Work on blog post'
    }
}

// Change node.
def grailsItem = todo.item.find { 
    it.title.toString().contains('Grails') 
}
grailsItem.replaceNode { node ->
    item(who: 'mrhaki', priority: node.@priority) {
        title 'Download Grails 1.4 M1'       
    }
}

// Remove node. Index value based on result directly after parsing.
// So here we remove the item about GWT.
todo.item[3].replaceNode {}

// Create output.
def newTodo = new StreamingMarkupBuilder().bind { 
    mkp.yield todo 
}.toString()

def expected = '''
<todo>
    <item priority="1">
        <title>DO: Look into GPars</title>
    </item>
    <item priority="1">
        <title>DO: Start developing Griffon App</title>
    </item>
    <item who="mrhaki" priority="2">
        <title>Download Grails 1.4 M1</title>
    </item>
    <item priority="2">
        <title>Work on blog post</title>
    </item>
</todo>
'''

// Check to see expected XML equals new todo XML.
XMLUnit.ignoreWhitespace = true
def difference = new Diff(newTodo, expected)
assert difference.similar()

October 16, 2009

Groovy Goodness: Navigating with GPath

Groovy has GPath, a path expression language to navigate in XML or POJOs. We can use a simple dot-notation to identify elements in XML or a set of POJOs. This results in clean and dense code.

def xml = '''
<languages>
    <language id="1" jvm="true">Groovy</language>
    <language id="2" jvm="true">Java</language>
    <language id="3" jvm="false">Ruby</language>
</languages>
'''

def languages = new XmlSlurper().parseText(xml)
// Navigate in XML with GPath.
assert 3 == languages.language.size()
assert 'Groovy' == languages.language.find { it.'@id' == 1 }.text()
assert ['Groovy', 'Java', 'Ruby'] == languages.language.collect { it.text() }
assert 1 == languages.language.find { it == /Groovy/ }['@id'].toInteger()

// Navigating with GPath through object graph.
assert 75 == String.metaClass.methods.name.size()
assert ['copyValueOf', 'format', 'valueOf'] == String.metaClass.methods.findAll { it.static }.name.unique()
assert ['replace', 'replace', 'replaceAll', 'replaceFirst'] == String.metaClass.methods.name.grep(~/replace.*/)
assert ['class', 'bytes', 'empty'] == String.metaClass.properties.name
assert ['java.lang.Class', 'byte[]', 'boolean'] == String.metaClass.properties.type.canonicalName