使用Groovy BuilderSupport的外部内容

时间:2009-11-24 02:27:59

标签: groovy builder

我通过扩展BuilderSupport在Groovy中构建了一个自定义构建器。在配置几乎每个构建器代码示例时,它都能很好地工作:

def builder = new MyBuilder()
builder.foo {
    "Some Entry" (property1:value1, property2: value2)
}

这当然是完美的。问题是我不希望我正在构建的信息出现在代码中。我希望将这些信息放在某个文件中,该文件由构建器读入并构建到对象中。我无法弄清楚如何做到这一点。

我甚至无法通过在代码中移动简单条目来完成这项工作。 这有效:

def textClosure = { "Some Entry" (property1:value1, property2: value2) }
builder.foo(textClosure)

因为textClosure是一个闭包。

如果我这样做:

def text = '"Some Entry" (property1:value1, property2: value2)'
def textClosure = { text }
builder.foo(textClosure)

仅为“foo”节点调用构建器。我已经尝试了很多变种,包括将文本块直接传递给构建器而不将其包装在闭包中。它们都会产生相同的结果。

我是否有某种方法可以将一段任意文本传递给我的构建器,以便它能够正确地解析和构建它?

3 个答案:

答案 0 :(得分:1)

你的问题是String不是Groovy代码。 ConfigSlurper处理此问题的方法是使用Script将文本编译为GroovyClassLoader#parseClass的实例。如,

// create a Binding subclass that delegates to the builder
class MyBinding extends Binding {
    def builder
    Object getVariable(String name) {
        return { Object... args ->  builder.invokeMethod(name,args) }
    }   
}

// parse the script and run it against the builder
new File("foo.groovy").withInputStream { input ->
    Script s = new GroovyClassLoader().parseClass(input).newInstance()
    s.binding = new MyBinding(builder:builder)
    s.run()
}

Binding的子类只返回一个闭包,用于将调用委托给构建器的所有变量。所以假设foo.groovy包含:

foo {
    "Some Entry" (property1:value1, property2: value2)
}

这相当于上面的代码。

答案 1 :(得分:0)

我认为您描述的问题可以通过slurper或解析器更好地解决。

请参阅:

http://groovy.codehaus.org/Reading+XML+using+Groovy%27s+XmlSlurper http://groovy.codehaus.org/Reading+XML+using+Groovy%27s+XmlParser

用于基于XML的示例。

在你的情况下。给定XML文件:

<foo>
    <entry name='Some Entry' property1="value1" property2="value2"/>
</foo>

你可以用以下方式啜饮:

def text = new File("test.xml").text
def foo = new XmlSlurper().parseText(text)
def allEntries = foo.entry
allEntries.each { 
    println it.@name
    println it.@property1
    println it.@property2
}

答案 2 :(得分:0)

最初,我希望能够指定

"Some Entry" (property1:value1, property2: value2)

在外部文件中。我特别试图避免使用XML和类似XML的语法来使常规用户更容易创建和修改这些文件。我当前的解决方案使用ConfigSlurper,文件现在看起来像:

"Some Entry"
{ 
   property1 = value1 
   property2 = value2 
}

ConfigSlurper给我一张这样的地图:

["Some Entry":[property1:value1,property2:value2]]

使用这些值来创建我的对象非常简单,特别是因为我可以将属性/值映射传递给构造函数。