2010-02-06 8 views
19

como desarrollador tcl que comienza con groovy, estoy un poco sorprendido con la lista y el soporte de mapas en groovy. Tal vez me estoy perdiendo algo aquí.Groovy: ¿no hay un stringToMap listo para usar?

Estoy acostumbrado a convertir entre cadenas, listas y matrices/mapas en tcl sobre la marcha. En TCL, algo así como

"['a':2,'b':4]".each {key, value -> println key + " " + value} 

sería posible, mientras que en maravilloso, los pasos de cada comando a través de cada carácter de la cadena.

Esto sería un gran problema si pudiera usar algo como el comando dividir o tokenizar, pero como una lista serializada o un mapa no es solo "a: 2, b: 4", es un poco más difícil de analizar.

Parece que los desarrolladores de griffon usan una biblioteca de stringToMap (http://code.google.com/p/stringtomap/) pero el ejemplo tampoco puede hacer frente a los mapas serializados.

Así que mi pregunta es ahora: ¿cuál es la mejor manera de analizar un mapa o una lista en groovy?

Saludos, Ralf

PS: se trata de una cuestión maravilloso, pero he marcado con griales, porque necesito esta funcionalidad para griales donde me gustaría transmitir mapas a través de la URL

actualización: Esto sigue siendo una pregunta abierta para mí ... así que aquí están algunas versiones de aquellos que tienen el mismo problema:

  • cuando se enciende un mapa en una cadena, un .toString() se re sult en algo que no se puede volver a convertir en un mapa en todos los casos, pero un .inspect() le dará una cadena que se puede evaluar de nuevo a un mapa!
  • en Grails, hay una .encodeAsJSON() y JSON.parse(String) - ambos funcionan muy bien, pero no ha obtenido todavía Lo que el intérprete hará con funciones JSON (posible problema de seguridad)
+3

Si está utilizando grails y quiere un mapa, miraría POSTING un mensaje JSON.Probablemente sea más fácil de generar en el lado del cliente y hay cosas integradas en Grails para evaluar JSON. –

+0

thanx. ¡Json podría ser una muy buena alternativa! – rdmueller

+1

Pasar los mapas a través de la URL en Grails suena como un trabajo para mapeos de URL. Consulte la sección Variables incrustadas de la guía del usuario de Grails (sección 6.4.2). Puede definir una estructura de URL personalizada para pasar el mapa que desee, es decir, http://myapp.com/controller/action/key1/value1/key2/value2 No funcionará demasiado bien para mapas multidimensionales , o enormes estructuras de datos, pero yo diría que no deberían pasarse a través de las URL de todos modos. –

Respuesta

8

No exactamente nativa maravilloso, pero útil para la serialización de JSON:

import groovy.json.JsonBuilder 
import groovy.json.JsonSlurper 

def map = ['a':2,'b':4 ] 
def s = new JsonBuilder(map).toString() 
println s 

assert map == new JsonSlurper().parseText(s) 

con meta -programación:

import groovy.json.JsonBuilder 
import groovy.json.JsonSlurper 

Map.metaClass.toJson = { new JsonBuilder(delegate).toString() } 
String.metaClass.toMap = { new JsonSlurper().parseText(delegate) } 

def map = ['a':2,'b':4 ] 
assert map.toJson() == '{"a":2,"b":4}' 
assert map.toJson().toMap() == map 

unfortun Por cierto, no es posible anular el método toString() ...

+1

Supongo que esta es una solución limpia ... con un poco de metaprogramación , esta funcionalidad se puede agregar fácilmente a la clase String ... – rdmueller

+0

... y a la clase Map ... – rdmueller

3

Creo que busca una combinación de ConfigObject y ConfigSlurper. Algo como esto haría el truco.

def foo = new ConfigObject() 
foo.bar = [ 'a' : 2, 'b' : 4 ] 

// we need to serialize it 
new File('serialized.groovy').withWriter{ writer -> 
    foo.writeTo(writer) 
} 

def config = new ConfigSlurper().parse(new File('serialized.groovy').toURL())  

// highest level structure is a map ["bar":...], that's why we need one loop more 
config.each { _,v -> 
    v.each {key, value -> println key + " " + value} 
} 
+0

gracias, ¡es bueno saber sobre el tragón! – rdmueller

21

Es posible que desee probar algunos de sus escenarios utilizando evaluar, podría hacer lo que busca.

def stringMap = "['a':2,'b':4]" 
def map = evaluate(stringMap) 

assert map.a == 2 
assert map.b == 4 

def stringMapNested = "['foo':'bar', baz:['alpha':'beta']]" 
def map2 = evaluate(stringMapNested) 

assert map2.foo == "bar" 
assert map2.baz.alpha == "beta" 
+0

gracias. ¡Supongo que esto está cerca de lo que estaba buscando! – rdmueller

+0

wow. ¡Solo noté que la solución es un gran riesgo de seguridad! Si los datos se pasan a través de la URL y hacemos una evaluación(), ¡todo puede suceder! Así que supongo que la solución JSON será la mejor manera ... – rdmueller

+3

Puede usar la clase 'Eval' que es un simple ayudante en la parte superior de GroovyShell:' def map = Eval.me ("['a': 2, 'b': 4] ")' –

1

Si no desea utilizar evaluar(), hacer en su lugar:

def stringMap = "['a':2,'b':4]" 
stringMap = stringMap.replaceAll('\\[|\\]','') 
def newMap = [:] 
stringMap.tokenize(',').each { 
kvTuple = it.tokenize(':') 
newMap[kvTuple[0]] = kvTuple[1] 
} 
println newMap 
+0

Eso es bastante limitado, ya que solo funcionará con Strings. Por ejemplo, en su ejemplo, los valores que se ponen en newMap serán las cadenas "2" y "4", no los números 2 y 4. –

Cuestiones relacionadas