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

例を簡略化する際にうまくいかないかもしれませんが、そのようなコードは機能します。

あなたの例では、学生は閉鎖呼び出しであるため、内部が混乱する可能性があります。

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 キャプターと同様で、スコープ内にローカル変数がある場合、ノードは生成されません。

于 2014-05-05T18:52:46.580 に答える