2009-11-24 21 views
2

我通过扩展BuilderSupport在Groovy中构建了一个自定义构建器。Groovy BuilderSupport的外部内容

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” 的节点。我已经尝试了许多变体,包括直接将文本块传递给构建器,而不将其封装在构建器中。它们都产生相同的结果。

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

回答

0

我认为你所描述的问题可以用slurper或parser更好地解决。

请参见:

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 [email protected] 
    println [email protected] 
    println [email protected] 
} 
+0

这些示例仍然假设要分析/ slurped的内容位于类路径中,而我的应用程序不会这样。我不想为我的配置使用XML - 我查看了XmlSlurper和XmlParser的源代码,它们都非常特定于XML。我必须从头开始编写我的slurper/parser,因为没有像BuilderSupport那样的公共基础。 – Chad 2009-11-24 18:43:38

+0

接缝我没有得到你的问题。我添加了一个例子来说明我的意思。也许你可以指出这个解决方案有什么问题。 – 2009-11-24 20:18:39

0

本来,我希望能够在外部文件中指定

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

。我特别试图避免使用XML和类似XML的语法来使这些文件更易于普通用户创建和修改。我目前的解决方案采用ConfigSlurper和文件如下:

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

ConfigSlurper给了我一张地图是这样的:

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

这是非常简单的使用这些值来创建我的对象,尤其是因为我能只需将属性/值映射传递给构造函数。

1

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

// 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) 
} 

它将等于您的代码上面。