December 17, 2014
Hot Topics:

Groovy Development

  • September 15, 2005
  • By Dick Wall
  • Send Email »
  • More Articles »

Native List and Map Syntax

Like Jython (my previous favorite JVM-based scripting language), Groovy has some very powerful support for lists and maps built in. For example, instead of having to say:

HashMap myMap = new HashMap();
myMap..put("1","Fred");
myMap.put("2","George");

You can use the much shorter and clearer:

groovyMap = ["1":"Fred", "2":"George"]

Give it a try in the GroovyConsole and run it; you should see the groovyMap contents printed to the command line standard output.

Likewise, list support is built in:

myList = [1,"2","Three",4]
Note: Boxing for the int values in the list is handled for you, so the above is perfectly valid Groovy syntax.

Not much exciting there, but the simplicity continues:

copyList = myList[1..2]

will create a list called copyList with the contents ["2","Three"] based on the second and third elements of myList.

This barely scratches the surface of collections in Groovy, but you should move on to the more interesting stuff. Suffice to say that much more information on the collections and the other language features can be found at http://groovy.codehaus.org/Language+Guide.

Closures

The reason I did bring collections up is because they are really useful for demonstrating closures. In a nutshell, a closure is a code block that does not have a name. One typical use for a closure is to run some block of code on every element in a collection.

A closure has enclosing braces, and then a part where parameters are declared, followed by a -> operator, and then the code block. So, for example:

groovyMap = ["Fred":1, "George":3, "Harry":2, "Tom":2]
groovyMap.each() { name, times ->
   for (i in 1..times) {
      System.out.print(name + " ");
   }
   System.out.println();
}

When executed, this will print each of the names the number of times matching the numerical argument associated with each in the map. Closures can also just be stored in a variable; for example:

def clos = { name, times ->
   for (i in 1..times) {
      System.out.print(name + " ");
   }
   System.out.println();
}

clos.call("James",4)

Will print James four times to the standard output. Note that while this might just look like a strange function definition, the closure could be passed in to a Groovy method to be applied to data from inside the method. This is very powerful and yet simple polymorphism. Smalltalk and Lisp programmers will immediately recognize the potential and power here.

Closures can be applied to all sorts of things. I have demonstrated simple collections here, but farther down I will demonstrate them on much more useful things, like XML nodes and SQL results sets.

Other Syntax Enhancements

There are many other syntactical enhancements that make programming Groovy a pleasure. For example: built-in support for regular expressions using the =~ operator, and an improved switch operator that can natively match strings and also perform range checks (is switch value in range 0..12).

Another important one is the Groovy expression language. This lets you insert variables and expressions into strings or other formatted output. For example:

println "hello ${name}"

will print "hello " followed by the value of the name variable. This comes in useful in the examples below. It can do more than just variable expansion, allowing you to navigate object hierarchies. You even can call methods and the return argument will be inserted into the string.

There are many more than could be covered in this article, so again I would like to point you at the language guide (http://groovy.codehaus.org/Language+Guide) because I really want to move on to the SQL and XML stuff.

Markup

There is one more important Groovy construct before you start laying your hands on XML and SQL. That is the idea of Markup. Markup is very cool. It is the ability to construct something (say, an XML file or Swing GUI) by using structured code that looks kind of like a Java class or method definition. It's hard to explain, but far easier to demonstrate.

import groovy.xml.MarkupBuilder;
def myXMLDoc = new MarkupBuilder()
myXMLDoc.library {
   section(id:"Programming") {
      book(title:"Java? Groovy!", author:"Duke McCoffee")
      book(title:"The art of hacking code", author:"Uber Hacker")
   }
}
println myXMLDoc

results in the XML snippet:

<library>
   <section id='Programming'>
      <book title='Java? Groovy!' author='Duke McCoffee' />
      <book title='The art of hacking code' author='Uber Hacker' />
   </section>
</library>

Not bad. When was the last time you were able to form an XML document in Java where the code to create it was about as compact as the resulting XML document (ignoring the import and the line to create the markup builder)?

XML Handling

You have just seen the compact way that XML can be output, but face it, although the notation is compact, there is nothing particularly hard about outputting XML, right? The hard part with XML is parsing it in; even the "easy" option of DOM in Java is pretty wordy. Fortunately, Groovy is as strong at parsing XML as it is at writing it. Once again, an example tells you more than any amount of description:

xmlData = """<library>
   <section id='Programming'>
      <book title='Java? Groovy!' author='Duke McCoffee' />
      <book title='The art of hacking code' author='Uber Hacker' />
   </section>
   <section id='Whimsy'>
      <book title='Ooh, la la' author='The Fops' />
   </section>
</library>"""
library = new groovy.util.XmlParser().parseText(xmlData)
library.section.each() { section ->
   println "Section = ${section['@id']}"
   section.book.each() { book ->
      println "Book: ${book['@title']} by ${book['@author']}"
   }
}

The first section is just putting an XML snippet into a string; the triple quotes let the string span several lines and include the newlines, so this is representative of what you might read out of an XML file. The line that reads:

library = new groovy.util.XmlParser().parseText(xmlData)

creates a groovy XML parser node that you can use within the rest of the example. The really interesting stuff happens below that, though.

Firstly, you assign the handle "library" to the node; you know in this case that your document's outer node is the "library" node, so that is just for readability. However, you also can start referring to the XML tags inside of that node by name.

library.section matches the section child tags inside the library node; the details are not too important, but you can think of it as returning a collection of those section nodes, which you can use a closure on. So, the line:

library.section.each() { section ->

iterates over the section nodes in library and calls the closure for each one, putting the node into the section variable before doing so; you then can refer to it from there. Apply this trick deep enough and you can parse the whole XML document, and equally easily just ignore the sections you are not interested in.

Also, farther down you start to use the XML attributes in the tags. For example, you access the ID attribute in the section tag, and the title and author attributes from the book tag. To do this, you use the xpath notation @attr-name in the context of a list or map lookup. For example:

println "Book: ${book['@title']} by ${book['@author']}"

obtains the title and author attributes out of the book node as though they were named map entries (which, in a sense, they are). Note also that the Groovy expression language is used to good effect here to dump the resulting values directly into a formatted string.

Now, I don't know about you, but this is among the simplest and best XML handling I have seen in any language, for both input and output. This example is small, but this same few lines of code could intelligently handle a library with hundreds of sections and books. A few more nested closures and it could handle some pretty large and complex XML schemas in a very few lines of code. Likewise, the output, with careful use of loops and closures there mixed in with the XML markup, could produce equally large and complex XML schemas in a similarly compact way.

You have won the first battle for your translators—easy XML handling—now what can you do about the SQL side (remember, these translators are for XML->SQL and SQL->XML)?





Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel