2009-11-24 55 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) 
} 

它將等於您的代碼上面。