Вызов метода изнутри StreamingMarkupBuilder
Я использую Groovy StreamingMarkupBuilder для динамической генерации XML на основе результатов нескольких SQL-запросов. Я хотел бы вызвать метод изнутри замыкания, но построитель разметки пытается создать узел XML, используя имя метода.
Вот пример того, что я пытаюсь сделать:
Map generateMapFromRow(GroovyRowResult row) {
def map = [:]
def meta = row.getMetaData()
// Dynamically generate the keys and values
(1..meta.getColumnCount()).each { column -> map[meta.getColumnName(column)] = row[column-1] }
return map
}
def sql = Sql.newInstance(db.url, db.user, db.password, db.driver)
def builder = new StreamingMarkupBuilder()
def studentsImport = {
students {
sql.eachRow('select first_name, middle_name, last_name from students') { row ->
def map = generateMapFromRow(row) // Here is the problem line
student(map)
}
}
}
println builder.bind(studentsImport).toString()
Это сгенерирует XML, подобный следующему:
<students>
<generateMapFromRow>
[first_name:Ima, middle_name:Good, last_name:Student]
</generateMapFromRow>
<student/>
<generateMapFromRow>
[first_name:Ima, middle_name:Bad, last_name:Student]
</generateMapFromRow>
<student/>
</students>
Я попытался переместить метод в класс и вызвать статически в классе, что тоже не работает.
Из-за особенностей работы StreamingMarkupBuilder, я боюсь, что на самом деле это невозможно, но я надеюсь, что это так.
1 ответ
Я могу потерять что-то во время упрощения примера, но такой код будет работать.
В вашем примере студенты - это закрывающий звонок, поэтому он может что-то испортить.
def builder = new groovy.xml.StreamingMarkupBuilder()
def generateMapFromRow = { ["$it": it] }
builder.bind {
10.times {
def map = generateMapFromRow(it) // Now closure is escaped, there is local variable with such name.
student(map)
}
}
Как сказано здесь: http://groovy.codehaus.org/Using+MarkupBuilder+for+Agile+XML+creation
При использовании компоновщиков разметки следует соблюдать осторожность, чтобы не перекрывать переменные, которые у вас есть в области видимости. Ниже приведен хороший пример
import groovy.xml.MarkupBuilder
def book = "MyBook"
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.shelf() {
book(name:"Fight Club") { // Will produce error.
}
}
println writer.toString()
Работа построителя аналогична захватчикам MethodMissing, и, если в области видимости есть локальная переменная, узел не будет создан.