Хм, это сложная проблема.Я предполагаю это:
{"map":
{"Momentum":12, "Corporate":3, "Catalyst":1},
"javaClass":"java.util.HashMap"}
может содержать переменное количество полей.А в JSON нотация переводится в объект (объекты JavaScript в основном (или очень похожи) на карты).Я не знаю, переведет ли это непосредственно на F #.
Это может быть запрещено статической типизацией F # по сравнению с динамической типизацией javascript.
вам, возможно, придется написать процедуру преобразования самостоятельно.
Ok тампара небольших ошибок в контрактах данных позволяет переопределить JsonMap и удалить атрибут «javaclass», поскольку его нет в предоставленном примере JSON (это более высокий уровень), и похоже, что пара ключей для меняне сериализуем, поэтому давайте определим наш собственный тип:
type JsonKeyValuePair<'T, 'S> = {
[<DataMember>]
mutable key : 'T
[<DataMember>]
mutable value : 'S
}
type JSONMap<'T, 'S> = {
[<DataMember>]
mutable map : JsonKeyValuePair<'T, 'S> array
}
и создадим функцию десериализации:
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 = "{\"map@\":[{\"key@\":\"a\",\"value@\":1},{\"key@\":\"b\",\"value@\":2}]}"
let o = deserializeString<JSONMap<string, int>> json
()
Я могу десериализовать строку в соответствующую структуру объекта.Я хотел бы получить ответ на две вещи:
1). Почему .NET заставляет меня добавлять символы @ после имен полей?2) Каков наилучший способ сделать преобразование?Я бы предположил, что можно использовать абстрактное синтаксическое дерево, представляющее структуру JSON, а затем проанализировать его в новой строке.Я не очень знаком с AST и их анализом.
Возможно, кто-то из экспертов F # сможет помочь или придумать лучшую схему перевода?
, наконец, добавив обратнов типе результата:
[<DataContract>]
type Result<'T> = {
[<DataMember>]
mutable javaClass: string
[<DataMember>]
mutable result: 'T
}
и функция преобразования карты (работает в этом случае - но имеет много слабых мест, включая определения рекурсивных карт и т. д.):
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
По-прежнему инициируетсяна знак @ в разных местах - что я не получаю ...
добавление конвертации с обходным путем для проблемы с амперсандом
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 = "{\"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, "\"map@\":[" + 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
добавление:
[<DataContract>]
над записью исправляет проблему амперсанда.