Parsing JSON With No Tag F# - json

I am trying to deserialize the following JSON:
{
"-L3ELSSzZPRdjCRcFTrb":{
"senderId":"SWs56OIGzMdiCjSXahzDQX8zve92",
"senderName":"alberto",
"text":"Hi"
},
"-L3EN1NW5hHWBTEGC9ve":{
"senderId":"YMM45tgFFvYB7rx9PhC2TE5eW6D2",
"senderName":"David",
"text":"Hey"
}
}
To do so I have created the following two records:
type MessageContent =
{ senderId: string
senderName: string
text: string; }
type Messages =
{
messages_list : Map<string,MessageContent>;
}
Next, I call:
let messages_json = JsonConvert.DeserializeObject<Types.Messages>(html)
however, this produces the following result:
{{messages_list = null;}}
The problem seems to be that there is no messages_list tag in the JSON, so the converter cannot find this tag and returns null. How would I handle a jSON like this though where no initial tag is available?

The easiest way of doing this is probably by using the [<JsonExtensionData>] attribute and adding [<CLIMutable>]
Change your Messages type like this (you might also have to add [<CLIMutable>] to your MessageContent type)
[<CLIMutable>]
type Messages = { [<JsonExtensionData>] messages : IDictionary<string, JToken> }
Then you can deserialize it into a map like this
let msg = JsonConvert.DeserializeObject<Messages>(html)
let messagemap =
msg.messages
|> Seq.map (fun kvp -> kvp.Key, kvp.Value.ToObject<MessageContent>())
|> Map.ofSeq
which will leave you with a map of MessageContent records.

Related

JSON decoding from stream in Kotlin

I have a server set up to send messages over a local host port. I am trying to decode the serialized json messages sent by the server and get this error.
Error decoding message: kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 55: Expected EOF after parsing, but had instead at path: $
JSON input: .....mber":13,"Timestamp":5769784} .....
The Racer State messages are formatted in JSON as follows: { “SensorId”: “value”, “RacerBibNumber” : “value”, “Timestamp” : “value” }, where the value’s are character string representations of the field values. I have also tried changing my RacerStatus Class to take String instead of Int but to a similar error. Am I missing something here? The symbol that is missing in the error was not able to be copied over so I know it's not UTF-8.
I have also added
val inputString = bytes.toString(Charsets.UTF_8)
println("Received input: $inputString")
This gets
Received input: {"SensorId":0,"RacerBibNumber":5254,"Timestamp":3000203}
with a bunch of extraneous symbols at the end.
data class RacerStatus(
var SensorId: Int,
var RacerBibNumber: Int,
var Timestamp: Int
) {
fun encode(): ByteArray {
return Json.encodeToString(serializer(), this).toByteArray()
}
companion object {
fun decode(bytes: ByteArray): RacerStatus {
print(bytes[0])
try {
val mstream = ByteArrayInputStream(bytes)
return Json.decodeFromStream<RacerStatus>(mstream)
} catch (e: SerializationException) {
println("Error decoding message: $e")
return RacerStatus(0, 0, 0)
}
// return Json.decodeFromString(serializer(), mstream.readBytes().toString())
}
}
}
So I found an answer to my question. I added a regex to include just the json components I know my json contains.
val str = bytes.toString(Charsets.UTF_8)
val re = Regex("[^A-Za-z0-9{}:,\"\"]")
return Json.decodeFromString<RacerStatus>(re.replace(str,""))
I thought that Charsets.UTF_8 would remove the misc characters but it did not. Is there a more intiuative solution? Also is there a regex that would cover all possible values in json?

Using JsonProvider from Fsharp.Data for Binance-Request

I'm trying to work with the Binance-Connector for .NET. In the F#-Examples, we have the following:
let f =
let loggerFactory = LoggerFactory.Create(fun (builder:ILoggingBuilder) ->
builder.AddConsole() |> ignore
)
let logger = loggerFactory.CreateLogger()
let loggingHandler = new BinanceLoggingHandler(logger)
let httpClient = new HttpClient(loggingHandler)
let market = new Market(httpClient)
let result = market.TwentyFourHrTickerPriceChangeStatistics() |> Async.AwaitTask |> Async.RunSynchronously
0
result is a string and looks something like this:
{"symbol":"ETHBTC","priceChange":"0.00013400","priceChangePercent":"0.179","weightedAvgPrice":"0.07444089","prevClosePrice":"0.07467300","lastPrice":"0.07480700","lastQty":"0.04640000","bidPrice":"0.07480600","bidQty":"6.01380000","askPrice":"0.07480700","askQty":"48.54320000","openPrice":"0.07467300","highPrice":"0.07531600","lowPrice":"0.07357000","volume":"80296.33090000","quoteVolume":"5977.33041290","openTime":1650281947747,"closeTime":1650368347747,"firstId":335177449,"lastId":335313233,"count":135785}
This works as intended, but of course I want to work with the result.
So I tried to deserialize it with the JsonProvider:
type Simple = JsonProvider<result>
Which for some reason doesn't work. The error resides with and it says that the Constructor or value is not defined (FS0039)
A sample in the docs for JsonProvider is given as follows:
type Simple = JsonProvider<""" { "name":"John", "age":94 } """>
let simple = Simple.Parse(""" { "name":"Tomas", "age":4 } """)
simple.Age
simple.Name
How can I correctly cast the json to a type?
Best regards
JsonProvider<...> takes a static string parameter which is either a sample string or a sample file (local or online accessible) in order to let the provider infer the types from it.
So in your case it would be:
let [<Literal>] BinanceSample = """ [{"symbol":"ETHBTC","priceChange":"-0.00163000"}] """
type Binance = JsonProvider<BinanceSample>
Then you should be able to parse the JSON with:
let parsed = Binance.Parse(result)
PS: try to provide a JSON sample that is as complete as possible.

How to encode a list of records to JSON in Reason?

Given a record type and a list of records:
type note = {
text: string,
id: string
};
let notes: list complete_note = [{text: "lol", id: "1"}, {text: "lol2", id: "2"}]
How do I encode this to JSON using bs-json module?
What I tried: I tried to manually create JSON string using string interpolation in bucklescript, but that's definitely not something I want to do :)
notes
|> Array.of_list
|> Array.map (
fun x => {
// What should I do?
}
)
|> Json.Encode.stringArray
|> Js.Json.stringify;
Disclaimer, I'm not a Reason expert, so the code might be non-idiomatic. It may also have errors, as I don't have the BuckleScript installed, so I didn't test it.
So, if you want to represent each note as a JSON object with text and id fields, then you can use the Js.Json.objectArray function to create a JSON document from an array of JS dictionaries. The easiest way to create a dictionary would be to use the Js.Dict.fromList function, that takes a list of pairs.
notes
|> Array.of_list
|> Array.map (fun {id, text} => {
Js.Dict.fromList [("text", Js.Json.string text), ("id", Js.Json.string id)]
})
|> Js.Json.objectArray
|> Js.Json.stringify;

How to create JSON format from Realm "Results" using Object Mapper

I try to create JSON format from Realm Results using Object Mapper. So, I created two generic methods to do that. Fisrt method create array form Results and looks like that:
var allRealmData: Results<Project>? // in this variable I save all Project Objects first
func makeAnArrayFromResults<T>(object: T.Type) -> [T]?{
var array = [T]()
guard let mainArray = allRealmData else { return nil }
for i in mainArray {
if let object = i as? T {
array.append(object)
}
}
return array
}
then I would like to use Object Mapper to change this array to JSON Object, but when I try do it, I receive an error and don't know how can I resolve it. My second method looks like that:
func createJSON<T: Object>(object: T.Type){
let array = makeAnArrayFromResults(object)
let json = Mapper().toJSONString(array!, prettyPrint: true) //here error
}
error info: Cannot invoke "toJSONString" with an argument list of type"([T], prettyPrint: Bool)".
Do you have any sugestions how can I create JSON from Result in Realm?
Firstly, makeAnArrayFromResults<T> is really just map:
let someRealmResults: Results<Project>?
...
let array = someRealmResults?.map { $0 } // => [Project]?
As far as the Object Mapper integration goes, it looks like you don't have a toJSONString function defined that satisfies the first argument type constraints of [Person].
There's quite a bit of discussion in Object Mapper's issue tracker about interoperability with Realm that you may find useful: https://github.com/Hearst-DD/ObjectMapper/issues/475

How to parse JSON in Swift 2?

I have a PHP web api that returns json in the following format:
{"users":[
{"user": {id:"1","name":"ahmad"}},
...
]}
In my Swift 2 code, I am able to retrieve the data above store it in an NSArray named users
Now, I need to iterate throw each user to convert it into an object:
for user in users {
print("found: \(user)")
}
That ouputs something like:
found: {
user = {
id = 1;
name = ahmad;
};
}
but when I try to access any element of that object I get an error:
let id = user["user"]["id"] //does not work: Xcode wont compile
let id2 = user["user"]!["id"]! //does not work: Xcode wont compile
let id3 = user!["user"]!["id"]! //does not work: Xcode wont compile
Then I tried :
if let u=user["user"] { //does not work: Xcode wont compile
// do somthing
}
I put a break point at print("\(user)") to see what is going on, and here is what I found:
When I print the description of each individual user I get:
How can I access the elements of this JSON data in Swift 2?
A NSArray only holds AnyObject so you have to cast it (to Array<Dictionary<String, Dictionary<String, String>>>. Below you see the shorthand):
// this is a forced cast and you probably get runtime errors if users cannot be casted
for user in users as! [[String : [String : String]]] {
print("found: \(user)")
}