2

我正在使用 Groovy 的StreamingMarkupBuilder根据几个 SQL 查询的结果动态生成 XML。我想从闭包内部调用一个方法,但标记生成器尝试使用方法名称创建一个 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 工作方式的性质,我担心它实际上不可能做到这一点,但我希望它是。

4

1 回答 1

1

在示例简化过程中我可能会松懈,但这样的代码会起作用。

在您的示例中,students 是一个闭包调用,因此它可能会在里面弄乱。

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()

Builder 的工作类似于 MethodMissing Captors,如果作用域中有局部变量,则不会产生节点。

于 2014-05-05T18:52:46.580 回答