Skip to end of metadata
Go to start of metadata

Note: the following examples are snippets, not ready-to-run examples.

Groovy has native support for various markup languages from XML, HTML, SAX, W3C DOM, Ant tasks, Swing user interfaces and so forth.
This is all accomplished via the following syntax...

Whichever kind of builder object is used, the syntax is the same. What the above means is that the someBuilder object has a method called 'people' invoked with 2 parameters...

  • a Map of arguments ['kind':'folks', 'groovy':true]
  • a Closure object which when invoked will call 2 methods on the builder called 'person', each taking 2 parameters, a map of values and a closure...

So we can easily represent any arbitrary nested markup with ease using a simple concise syntax. No pointy brackets! (smile)

What's more is this is native Groovy syntax; so you can mix and match this markup syntax with any other Groovy features (iteration, branching, method calls, variables, expressions etc). e.g.

Trees, DOMs, beans and event processing

The really neat thing about GroovyMarkup is that its just a syntax which maps down to method calls. So it can easily support the building of any arbitrary object structure - so it can build any DOMish model, a bean structure, JMX MBeans, PicoComponents, Swing front ends, Ant tasks etc. What's more since its just normal method invocations it can naturally map to SAX event processing too.

Out of the box Groovy comes with a few different markup builders you can use :

  • NodeBuilder - creates a tree of Node instances which can be easily navigated in Groovy using an XPath-like syntax
  • DOMBuilder - creates a W3C DOM document from the markup its given
  • SAXBuilder - fires SAX events into a given SAX ContentHandler
  • MarkupBuilder - outputs XML / HTML markup to some PrintWriter for things like implementing servlets or code generation
  • AntBuilder - fires off Ant tasks using familiar markup for processing build tasks
  • SwingBuilder - creates rich Swing user interfaces using a simple markup

Examples

Here's a simple example which shows how you could iterate through some SQL result set and output a dynamic XML document containing the results in a custom format using GroovyMarkup

The interesting thing about the above is that the XML technology used at the other end could be push-event based (SAX) or pull-event based (StAX) or a DOM-ish API (W3C, dom4j, JDOM, EXML, XOM) or some JAXB-ish thing (XMLBeans, Castor) or just beans or just good old text files.
e.g. a pull parser could literally pull the data out of the database - or the data could be pushed into data some structure or piped straight to a file using IO or async NIO.

The use of GroovyMarkup means developers can hide the XML plumbing and focus on tackling the real problems we're trying to solve.

To see more examples of using GroovyMarkup try looking at our unit test cases

There is more detail on markup here Make a builder.

  • No labels

2 Comments

  1. These markup builders look really cool, but it took me quite a while of researching this to understand what was going on with them.

    What is actually happening when you do a method call on a builder is the method is intercepted by something called the Meta-Object Protocol, described in this article on the IBM site:

    http://www-128.ibm.com/developerworks/java/library/j-pg09205/

    Essentially, the method call is intercepted by invokeMethod() in the BuilderSupport superclass. You can see this method source code described here, though it isn't actually explained on that page:

    http://groovy.codehaus.org/Make+a+builder

    Also, what happens if you try to create an element that is a reserved keyword, or that uses a dash in its name? You should prepend an underscore — also, underscores in names that have an underscore prepended will be converted to dashes. Thus, to create an element called "class", user _class, or "hibernate-mapping", use _hibernate_mapping.

    Finally, there's the mystery of why, inside the closures in the example at the top of the page, the method calls inside the closure do not refer to a receiving object? This is because closures support a setDelegate call, which allows you to redirect method calls to a delegate object (in this case, the builder). Thus, the person() call is redirected to the someBuilder object.

  2. I discover that I can pass String as key. That means this code works .

    def someBuilder = new NodeBuilder()

    someBuilder.people('kind':'folks', groovy:true)  {

                           test( "xyz@abc" :'hello world') {

                            }

    }

    Is it a legal code , or just a bug ?