Hmm das ist ein kompliziertes Problem. Ich gehe davon aus:
{"map":
{"Momentum":12, "Corporate":3, "Catalyst":1},
"javaClass":"java.util.HashMap"}
könnte eine variable Anzahl von Feldern enthalten. Und in JSON übersetzt sich die Notation in ein Objekt (JavaScript-Objekte sind im Grunde (oder sehr ähnlich) zu Maps). Ich weiß nicht, ob das direkt in F # übersetzt wird.
Es kann verhindert werden, dass F # statische Eingabe im Gegensatz zur dynamischen Typisierung von Javascript nicht erlaubt wird.
müssen Sie möglicherweise die Konvertierungsroutine selbst schreiben.
Ok ein paar kleine Fehler in den Datenverträge gibt es lässt die JsonMap neu definieren und entfernen Sie das „Javaclass“ -Attribut, da es nicht in th JSON Probe vorgesehen ist (es ist eine höhere Ebene nach oben), und es sieht aus, als ob die keyvaulepair mir nicht ist Serialisierung, lässt so unsere eigene Art definieren:
type JsonKeyValuePair<'T, 'S> = {
[<DataMember>]
mutable key : 'T
[<DataMember>]
mutable value : 'S
}
type JSONMap<'T, 'S> = {
[<DataMember>]
mutable map : JsonKeyValuePair<'T, 'S> array
}
und erstellen sie eine deserialize Funktion:
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
()
ich in der Lage bin str deserialisieren in die entsprechende Objektstruktur einfügen. Zwei Dinge, die ich gerne beantwortet sehen möchte, sind
1) Warum zwingt mich .NET, @ Zeichen nach den Feldnamen anzufügen? 2) Was ist der beste Weg, um die Konvertierung durchzuführen? Ich würde vermuten, dass ein abstrakter Syntaxbaum, der die JSON-Struktur repräsentiert, der Weg sein könnte, und dann diesen in die neue Zeichenkette zu parsen. Ich bin mit AST und ihrem Parsing allerdings nicht besonders vertraut.
Vielleicht könnte einer der F # -Experten helfen oder ein besseres Übersetzungsschema erstellen?
schließlich Zugabe zurück in dem Ergebnistyp:
[<DataContract>]
type Result<'T> = {
[<DataMember>]
mutable javaClass: string
[<DataMember>]
mutable result: 'T
}
und bekehrt Map-Funktion (Arbeiten in diesem Fall - aber hat viele Bereiche der Schwäche einschließlich rekursive Karten Definitionen 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
Es immer noch inisits auf dem @ Zeichen an verschiedenen Stellen - die ich nicht bekomme ...
Hinzufügen konvertieren w/Abhilfe für das Ampersand Ausgabe
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
Zugabe:
[<DataContract>]
über dem Rekord behebt das Problem Ampersand.
Ich bemerkte, dass, wenn ich F # Satzarten in RavenDB gespeichert, würden sie mit dem regulären Eigenschaftsnamen gespeichert werden und die gleichen Eigenschaftsnamen durch ein @ -Zeichen gefolgt. Ich vermute, dass die @ Version das Hintergrundfeld für die öffentliche Eigenschaft im Datensatztyp ist. Das Erstellen meiner eigenen Klasse anstelle der Verwendung eines Datensatzes hat die zusätzlichen @ -Eigenschaften beseitigt - Sie müssen möglicherweise so etwas tun. –