BuilderSupportでDSL

GroovyでDSLを作るときに便利なBuilderSupportを使う簡単な例です。

public class MyBuilder extends BuilderSupport{
    protected Object createNode(Object name) {
        def obj = new Expando(name:name,children:,attributes:[:])
        return obj
    }

    protected Object createNode(Object name, Map attributes) {
        def obj = new Expando(name:name,attributes:attributes,children:)
        return obj
    }
    
    protected void setParent(Object parent, Object child) {
        parent.children << child
    }

    protected Object createNode(Object name, Object value) {
        return null
    }
    protected Object createNode(Object name, Map attributes, Object value) {
        return null
    }
   
}

def builder = new MyBuilder()

def ret = builder.aaa{
  target01(prop1:"aaa"){
    child01(name:"name01",class:"child.Child01")
    child02(name:"name02",class:"child.Child02")
  }
  target02(prop1:"bbb"){
    child03(name:"name03",class:"child.Child03")
    child04(name:"name04",class:"child.Child04")
  }

}

println "$ret"

結果

{name=aaa, children=[{name=target01, attributes={prop1=aaa}, children=[{name=child01, attributes={name=name01, class=child.Child01}, children=}, {name=child02, attributes={name=name02, class=child.Child02}, children=}]}, {name=target02, attributes={prop1=bbb}, children=[{name=child03, attributes={name=name03, class=child.Child03}, children=}, {name=child04, attributes={name=name04, class=child.Child04}, children=}]}], attributes={}}

参考URL:
http://groovy.codehaus.org/Make+a+builder

BuilderSupportを継承し、abstructメソッドをオーバーライドします(サンプルに不要なメソッドは空実装にしてnullを返しています)
また、上記参考URLでは、ノードを作成するのにNodeクラスを使ってる例がありますが、値を取り出すのが面倒だったりするので、
Expandoでname,attribute,childrenだけ持ったインスタンスを作って返しています。
ノードの親子関係はsetParent()で親への追加の仕方を記述しておくとBuilderSupportが親子関係を設定してくれています。