Reading JSON file inside F# using Json.NET - f#

Can't deserializes JSON retrieved from a file. Get an unhandled exception of type 'System.TypeInitializationException' occurred in
let deserializedFiles = JsonConvert.DeserializeObject<Files list>(json1)
The code follows:
let foo = new JsonTextReader(new StreamReader(jsonFile))
let json1 = JsonConvert.SerializeObject(foo.Read())
let deserializedFiles = JsonConvert.DeserializeObject<Files list>(json1)
Thanks,

Related

Format JSON string to iOS Dictionary string with =

First off, what do we call a dictionary with a format like this in iOS?
(
{
name = "Apple";
value = "fruit-1";
},
{
name = "Banana";
value = "fruit-2";
}
)
And for my main question. I somehow need to format a string of JSON, like this:
[{"name":"Apple","value":"fruit-1"},{"name":"Banana","value":"fruit-2"}]
into whatever that format is called (of the string above).
For context, the existing approach of my project uses CoreData where the Server response (which uses the mystery format above) gets saved locally as a String, and I want to follow that format.
EDIT: for more context, I really need to just get the first format into the database because a module of a project was built to read the data with that format (e.g. make use of NSString.propertyList()).
Using a library called ios hierarchy viewer, I can see the saved object in the device.
Original format, server json to db (core data) in Objective-C:
What I've been trying to do in Swift, server json to local using JSONSerialization:
First off, what do we call a dictionary with a format like this in iOS?
According to the documentation of NSString.propertyList(), that's a "text representation of a property list".
It's a wonky, non-standard pretty-printing obtained by calling NSArray.description or NSDictionary.description.
Here's an example that shows a round-trip of data:
// The opening `{` indentation is fucky, but that's how it's generated.
let inputPropertyList = """
(
{
name = "Apple";
value = "fruit-1";
},
{
name = "Banana";
value = "fruit-2";
}
)
"""
// The result is an `Any` because we don't know if the root structure
// of the property list is an array or a dictionary
let deserialized: Any = inputPropertyList.propertyList()
// If you want the description in the same format, you need to cast to
// Foundation.NSArray or Foundation.NSDictionary.
// Swift.Array and Swift.Dictionary have a different description format.
let nsDict = deserialized as! NSArray
let roundTrippedPropertyList = nsDict.description
print(roundTrippedPropertyList)
assert(roundTrippedPropertyList == inputPropertyList)
The second format you show is what you get when you display an object in the debug console. That's the output of the object's description property. It isn't a "JSON string", exactly.
If you want to convert your objets to a true JSON string, see below.
As Alexander pointed out, the first string in your question is the output from NSString's propertyList() function. The format looks quite similar to "pretty-printed" JSON, but it's different enough that it it won't work that way.
The `propertyList() function is a debugging-only function, and I don't know of an existing way to parse that back into objects. If that is the string that's being sent by your server, your server is broken. If that's what you see in core data when you log the contents of a field, it's probably a misunderstanding on your part.
To convert an object to pretty JSON, see this answer, where I created an extension to the Encodable format that implements a property "prettyJSON":
extension Encodable {
var prettyJSON: String {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
guard let data = try? encoder.encode(self),
let output = String(data: data, encoding: .utf8)
else { return "Error converting \(self) to JSON string" }
return output
}
}
That should work for any object that supports the Encodable protocol. (And your object should.)

How to model data from JSON array with no property name into swift so It can be parsed? SWIFT

Im stuck trying to model a JSON array which has no property name into my swift project with the goal of parsing the data and using it in my app. I know how to do this when there is a NAME for the array but I don't know how to make swift and this lackluster JSON understand each other. The path to the first "Company" in the JSON is "0.Company". The error I get is "Value of type 'WorkData' has no member '0'"
Im including pictures of my full project so it is easier to understand the structure of the code and what im trying to do. Please look at the picture for a clearer understanding I apologize if Im not explaining it well i'm new to programming.
import Foundation
class WorkData: Codable {
let WorkData: [WorkData]
let Company: String
let worklogDate: String
let issue: String
}
func parseData(jsonDataInput: Data) {
let decoder = JSONDecoder() // an object that decodes JSON data
do {
let decodedData = try decoder.decode(WorkData.self, from: jsonDataInput)
let Company = decodedData.0.Company
let worklogDate = decodedData.0.worklogDate
let issue = decodedData.0.issue
} catch {
print (error)
}
}
}
json
Trying to model JSON in Swift
Parsing JSON
You cannot start JSON with an array because JSON itself is an object {}
See example below:
{
"WorkData" : [
{"Company" : ""},
{"Company" : ""},
{"Company" : ""}
]
}
let decodedData = try decoder.decode(LocalizationsResponse.self, from: jsonDataInput)
decodedData will be an array

use of unresolved identifier 'JSONEncoder' swift4

for example I just want to convert this sample array into a JSON object
var test = [String : Any] ()
test["title"] = "title"
test["description"] = "description"
test["date"] = Date.init()
and I get this error:
use of unresolved identifier 'JSONEncoder'
print(JSONEncoder (test))
You are not using the encoder correctly. Try this
let encoder = JSONEncoder()
let json = try? encoder.encode(test)
Referencing app's document here, the only init method is like this, so you should not create the encoder itself to get you the JSON result.
init()
Creates a new, reusable JSON encoder with the default formatting
settings and encoding strategies.

Updating value - SwiftyJSON

I have a json object as below
{"level" :{"currentLevel":"1","score":"100"}}
I have this json data in my project folder and I am using SwiftyJSON to parse my son and read the values. Everything looks fine.
Now I need to update the score and I am trying as below
var json = JSON({"level" :{"currentLevel":"1","score":"100"}})
json["level"]["score"] = "200"
This works fine too and the json is updated but below try fails
var json = JSON({"level" :{"currentLevel":"1","score":"100"}})
var updatedScore:String = "200"
json["level"]["score"] = updatedScore
I get compile error
Type [Subscript] does not conform to Protocol 'StringLiteralConvertible'
Any suggestion on how to update a SwiftJSON JSON object with a variable would be helpful
Thank you
Update:My Solution
This is what I have done finally
var json = JSON({"level" :{"currentLevel":"1","score":"100"}})
var level = (json["level"] as JSON).dictionaryObject
let updatedScore = "200"
level!["currentLevel"] = updatedScore
json["level"] = JSON(level!)
And this works
Try the below if you are saving the json as dictionary
((json["level"]as nsdictionary)["score"] as NSString = updatedScore)

F# Interactive bug?

I've tried the following code in VS2010:
open System.Security.Cryptography
let rsaTest1 =
let ecKey = [|0uy..143uy|] // junk data for testing
let ecKeyMod = ecKey.[8..8+128-1]
let ecKeyExp = ecKey.[136..136+8-1]
let rsa = RSAParameters(Modulus = ecKeyMod, Exponent = ecKeyExp)
rsa
let rsaTest2 =
let ecKey = [|0uy..143uy|] // junk data for testing
let rsa = RSAParameters(Modulus = ecKey.[8..8+128-1], Exponent = ecKey.[136..136+8-1])
rsa
If I highlight all code and send it to F# Interactive (Alt+Enter), then rsaTest1 works, but rsaTest2 gives an error message,
System.NullReferenceException: Object reference not set to an instance of an object.
at <StartupCode$FSI_0004>.$FSI_0004.main#() in P:\proj\Tachograph\Project\CompuTachTest\CompuTachTest\rsaTest.fsx:line 16
However, if I change rsaTest2 from a value into a function and call it,
let rsaTest2 () =
let ecKey = [|0uy..143uy|] // junk data for testing
let rsa = RSAParameters(Modulus = ecKey.[8..8+128-1], Exponent = ecKey.[136..136+8-1])
rsa
let x = rsaTest2 ()
then there is no error. F# bug or my mistake?
This is most likely a bug - if you compile the posted snippet with fsc and run it, you get this for x64:
Unhandled Exception: System.InvalidProgramException: Common Language Runtime detected an invalid program.
at <StartupCode$test>.$Test.main#()
and this for x86:
Unhandled Exception: System.InvalidProgramException: JIT Compiler encountered an internal limitation.
at <StartupCode$test>.$Test.main#()
You should report it via Microsoft Connect.

Resources