Hmm este es un problema complicado. Supongo que esto:
{"map":
{"Momentum":12, "Corporate":3, "Catalyst":1},
"javaClass":"java.util.HashMap"}
podría contener una cantidad variable de campos. Y en la notación JSON se traduce a un objeto (los objetos javascript son básicamente (o muy similares) a los mapas). No sé si esto se traducirá directamente en F #.
Se puede evitar que no se permita mediante el tipado estático de F # en comparación con el tipado dinámico de javascript.
puede que tenga que escribir la rutina de conversión usted mismo.
OK Hay un par de pequeños errores en los contratos de datos permite redefinir el JsonMap y retire el "JavaClass" atributo, ya que no está en la muestra JSON ° proporcionado (que es un nivel más arriba), y parece que la keyvaulepair a mí, no es serializando, por lo que permite definir nuestro propio tipo:
type JsonKeyValuePair<'T, 'S> = {
[<DataMember>]
mutable key : 'T
[<DataMember>]
mutable value : 'S
}
type JSONMap<'T, 'S> = {
[<DataMember>]
mutable map : JsonKeyValuePair<'T, 'S> array
}
y crear una función deserializar:
let internal deserializeString<'T> (json: string) : 'T =
let deserializer (stream : MemoryStream) =
let jsonSerializer
= Json.DataContractJsonSerializer(
typeof<'T>)
let result = jsonSerializer.ReadObject(stream)
result
let convertStringToMemoryStream (dec : string) : MemoryStream =
let data = Encoding.Unicode.GetBytes(dec);
let stream = new MemoryStream()
stream.Write(data, 0, data.Length);
stream.Position <- 0L
stream
let responseObj =
json
|> convertStringToMemoryStream
|> deserializer
responseObj :?> 'T
let run2() =
let json = "{\"[email protected]\":[{\"[email protected]\":\"a\",\"[email protected]\":1},{\"[email protected]\":\"b\",\"[email protected]\":2}]}"
let o = deserializeString<JSONMap<string, int>> json
()
soy capaz de deserializar un str ing dentro de la estructura de objeto apropiada. Dos cosas que me gustaría ver respondidas son
1) ¿por qué .NET me obliga a agregar @ caracteres después de los nombres de los campos? 2) ¿Cuál es la mejor manera de hacer la conversión? Supongo que un árbol sintáctico abstracto que representa la estructura JSON podría ser el camino a seguir y luego analizarlo en la nueva cadena. No estoy muy familiarizado con AST y su análisis sin embargo.
¿Quizás alguno de los expertos de F # podría ayudar o proponer un mejor esquema de traducción?
por último la adición de nuevo en el tipo de resultado:
[<DataContract>]
type Result<'T> = {
[<DataMember>]
mutable javaClass: string
[<DataMember>]
mutable result: 'T
}
y una función de mapa de conversión (funciona en este caso - pero tiene muchas áreas de debilidad que incluyen las definiciones mapa recursivas etc.):
let convertMap (json: string) =
let mapToken = "\"map\":"
let mapTokenStart = json.IndexOf(mapToken)
let mapTokenStart = json.IndexOf("{", mapTokenStart)
let mapObjectEnd = json.IndexOf("}", mapTokenStart)
let mapObjectStart = mapTokenStart
let mapJsonOuter = json.Substring(mapObjectStart, mapObjectEnd - mapObjectStart + 1)
let mapJsonInner = json.Substring(mapObjectStart + 1, mapObjectEnd - mapObjectStart - 1)
let pieces = mapJsonInner.Split(',')
let convertPiece state (piece: string) =
let keyValue = piece.Split(':')
let key = keyValue.[0]
let value = keyValue.[1]
let newPiece = "{\"key\":" + key + ",\"value\":" + value + "}"
newPiece :: state
let newPieces = Array.fold convertPiece [] pieces
let newPiecesArr = List.toArray newPieces
let newMap = String.Join(",", newPiecesArr)
let json = json.Replace(mapJsonOuter, "[" + newMap + "]")
json
let json = "{\"id\":1, \"result\": {\"map\": {\"Momentum\":12, \"Corporate\":3, \"Catalyst\":1}, \"javaClass\":\"java.util.HashMap\"} } "
printfn <| Printf.TextWriterFormat<unit>(json)
let json2 = convertMap json
printfn <| Printf.TextWriterFormat<unit>(json2)
let obj = deserializeString<Result<JSONMap<string,int>>> json2
Todavía aparece en el signo @ en varios lugares, que no entiendo ...
añadiendo convertir w/solución para el problema de signo
let convertMapWithAmpersandWorkAround (json: string) =
let mapToken = "\"map\":"
let mapTokenStart = json.IndexOf(mapToken)
let mapObjectEnd = json.IndexOf("}", mapTokenStart)
let mapObjectStart = json.IndexOf("{", mapTokenStart)
let mapJsonOuter = json.Substring(mapTokenStart , mapObjectEnd - mapTokenStart + 1)
let mapJsonInner = json.Substring(mapObjectStart + 1, mapObjectEnd - mapObjectStart - 1)
let pieces = mapJsonInner.Split(',')
let convertPiece state (piece: string) =
let keyValue = piece.Split(':')
let key = keyValue.[0]
let value = keyValue.[1]
let newPiece = "{\"[email protected]\":" + key + ",\"[email protected]\":" + value + "}"
newPiece :: state
let newPieces = Array.fold convertPiece [] pieces
let newPiecesArr = List.toArray newPieces
let newMap = String.Join(",", newPiecesArr)
let json = json.Replace(mapJsonOuter, "\"[email protected]\":[" + newMap + "]")
json
let json = "{\"id\":1, \"result\": {\"map\": {\"Momentum\":12, \"Corporate\":3, \"Catalyst\":1}, \"javaClass\":\"java.util.HashMap\"} } "
printfn <| Printf.TextWriterFormat<unit>(json)
let json2 = convertMapWithAmpersandWorkAround json
printfn <| Printf.TextWriterFormat<unit>(json2)
let obj = deserialize<Result<JSONMap<string,int>>> json2
añadiendo:
[<DataContract>]
por encima del récord corrige el problema Ampersand.
he notado que cuando Almacené tipos F # registro en RavenDB, serían almacenados con el nombre de la propiedad regular, y el mismo nombre de la propiedad seguido por un signo @. Sospecho que la versión @ es el campo de respaldo para la propiedad pública en el tipo de registro. Al crear mi propia clase en lugar de utilizar un registro, eliminé las propiedades @ adicionales, es posible que tenga que hacer algo como eso. –