简体   繁体   English

如何使用Groovy的MarkupBuilder呈现List

[英]How to render a List with Groovy's MarkupBuilder

I am converting a Map to XML using the Groovy MarkupBuilder . 我正在使用Groovy MarkupBuilder将Map转换为XML。 This Map can contain simple key/value pairs, other Maps, or Lists of Maps. 此地图可以包含简单的键/值对,其他地图或地图列表。 I am piggybacking from the code here . 我正在从这里的代码中捎带。

import groovy.xml.MarkupBuilder

def map = [
    key1:'value1',
    key2:'value2',
    nestedMap : [
        key1:'bar1',
        key2:'bar2'
    ],
    select : [
        [option:'foo1'],
        [option:'foo2']
    ]
]

Closure renderMap( Map map ){
    return { 
        for ( entry in map ){
            switch( entry.value.getClass() ){
                case Map :
                    "${entry.key}" renderMap( entry.value )
                break
                case List:
                    entry.value.collect { listEntry ->
                        "${entry.key}" renderMap( listEntry )
                    }
                    break
                default :
                     "${entry.key}"( "${entry.value}" )
                break
            }
        }
    }
}

StringWriter writer = new StringWriter()
new MarkupBuilder(writer).root renderMap(map)

println writer.toString()

This part I'm concerned about prints out: 这部分我关注打印出来:

  <select>
    <option>foo1</option>
  </select>
  <select>
    <option>foo2</option>
  </select>

However, I am wondering if there is a way to get the select to encapsulate both of the options, like so: 但是,我想知道是否有办法让select封装两个选项,如下所示:

<select>
    <option>foo1</option>
     <option>foo2</option>
  </select>

I've tried playing around with the placement of the key, but to no avail. 我试过玩钥匙放置,但无济于事。 Am I going about this all wrong, or should I not be using the builder? 我是不是错了,或者我不应该使用建设者?

I think this will do what you want. 我想这会做你想要的。 The first two overloads take a map or a collection, and return a composed closure that can be passed to the builder method of the enclosing element to add the contents of the map or collection to the builder. 前两个重载采用映射或集合,并返回一个组合闭包,该闭包可以传递给封闭元素的构建器方法,以将地图或集合的内容添加到构建器。

The third is a fallback, and just returns its arguments so they can be passed to the builder method. 第三个是回退,只返回其参数,以便将它们传递给构建器方法。 This handles the strings, but you could also pass it a closure if you want. 这会处理字符串,但如果需要,您也可以将其传递给它。 I replaced the second option element in the map you provided as an example of that. 我替换了您提供的地图中的第二个option元素作为示例。

ComposedClosure was added in Groovy 1.8, so this won't work in earlier versions. 在Groovy 1.8中添加了ComposedClosure ,因此在早期版本中不起作用。

import groovy.xml.MarkupBuilder

Closure buildxml(final Map map)
{
    final compose = { f, tag, content -> f >> { "$tag"(buildxml(content)) } }
    return map.inject(Closure.IDENTITY, compose)
}

Closure buildxml(final Collection col)
{
    final compose = { f, content -> f >> buildxml(content) }
    return col.inject(Closure.IDENTITY, compose)
}

def buildxml(final content)
{
    return content
}

def map = [
    key1:'value1',
    key2:'value2',
    nestedMap : [
        key1:'bar1',
        key2:'bar2'
    ],
    select : [
        [option:'foo1'],
        { option('foo2') },
    ],
]

final writer  = new StringWriter()
final builder = new MarkupBuilder(writer)

builder.root buildxml(map)

assert writer as String == '''\
<root>
  <key1>value1</key1>
  <key2>value2</key2>
  <nestedMap>
    <key1>bar1</key1>
    <key2>bar2</key2>
  </nestedMap>
  <select>
    <option>foo1</option>
    <option>foo2</option>
  </select>
</root>'''.stripIndent()

does

case List:
    "${entry.key}" entry.value.collect {
        renderMap it
    }
    break

get you anywhere? 带你去哪儿? not at a computer to check atm though, but it feels right? 虽然不是在电脑上检查atm,但感觉对吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM