Hmm c'est un problème compliqué. Je suppose que:
{"map":
{"Momentum":12, "Corporate":3, "Catalyst":1},
"javaClass":"java.util.HashMap"}
peut contenir une quantité variable de champs. Et en notation JSON se traduit par un objet (les objets javascript sont fondamentalement (ou très similaires) aux cartes). Je ne sais pas si cela se traduira par F # directement.
Il peut être évité de ne pas être autorisé par le typage statique F # par rapport au typage dynamique de javascript.
vous devrez peut-être écrire la routine de conversion vous-même.
Ok il y a quelques petits bugs dans les contrats de données permet de redéfinir la JsonMap et de supprimer l'attribut « JavaClass » comme il est pas ième échantillon de JSON fourni (il est un niveau plus haut), et il semble que le keyvaulepair me ne sérialisation, donc permet de définir notre propre type:
type JsonKeyValuePair<'T, 'S> = {
[<DataMember>]
mutable key : 'T
[<DataMember>]
mutable value : 'S
}
type JSONMap<'T, 'S> = {
[<DataMember>]
mutable map : JsonKeyValuePair<'T, 'S> array
}
et créer une fonction deserialize:
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
()
Je suis en mesure de désérialiser une str dans la structure d'objet appropriée. Deux choses que j'aimerais voir répondre sont
1) Pourquoi est-ce que .NET m'oblige à ajouter @ caractères après les noms de champs? 2) Quelle est la meilleure façon de faire la conversion? Je suppose qu'un arbre de syntaxe abstraite représentant la structure JSON pourrait être le chemin à parcourir, et ensuite analyser cela dans la nouvelle chaîne. Je ne suis pas très familier avec AST et leur analyse. Peut-être que l'un des experts F # pourrait être en mesure d'aider ou de proposer un meilleur schéma de traduction?
enfin réintégrant dans le type de résultat:
[<DataContract>]
type Result<'T> = {
[<DataMember>]
mutable javaClass: string
[<DataMember>]
mutable result: 'T
}
et une fonction de carte de conversion (travaux dans ce cas - mais a beaucoup de points faibles, y compris les définitions de carte récursives, 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
Il est toujours indiqué sur le signe @ à divers endroits - que je ne reçois pas ...
convertir avec ajout/solution pour la question esperluette
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
ajouter:
[<DataContract>]
au-dessus du dossier résout le problème Ampersand.
Je remarqué que lorsque j'emmagasinés F # types d'enregistrement dans RavenDB, ils seraient stockés avec le nom de la propriété régulière, et le même nom de propriété suivi d'un signe @. Je soupçonne que la version @ est le champ de sauvegarde pour la propriété publique dans le type d'enregistrement. Créer ma propre classe au lieu d'utiliser un enregistrement s'est débarrassé des propriétés extra @ - vous devrez peut-être faire quelque chose comme ça. –