M.Y. Babt
M.Y. Babt

Reputation: 2891

F#: JsonConvert.SerializeObject() saves the same data multiple times

I am new to programming and F# is my first language.

I followed the advice given to me in this thread to use NewtonSoft.Json. Here are some relevant parts of my code:

    [<CLIMutable>]
    [<JsonObject(MemberSerialization=MemberSerialization.OptOut)>]
    type FighterSummary =
        { 
            mutable fighter: string; 
            mutable record: string option; 
            mutable reach: float option; 
            mutable stance: string option; 
        }

    let fighterFilesDir = @"G:\Fighter Pages"
    let fighterFiles = Directory.GetFiles(fighterFilesDir)
    let fighterGroups = splitArrayIntoGroups fighterFiles 50

    for group in fighterGroups do
        let fighterStats =   seq { 
                                    for file in group do
                                        let html = File.ReadAllText(file)
                                        let fighterOverview = getFighterSummary html
                                        printfn "Extracted %s's overview." (Path.GetFileNameWithoutExtension(file))
                                        yield fighterOverview
                                    } 
                                    |> Seq.toArray
        let fileName = Path.GetFileNameWithoutExtension(group.[0]) + " -- " + Path.GetFileNameWithoutExtension(group.[group.Count() - 1])
        let saveFilePath = @"G:\Fighter Data JSON Files\" + fileName + ".json"
        File.WriteAllText(saveFilePath, JsonConvert.SerializeObject(fighterStats))

I have tested the functions getFighterSummary and splitArrayIntoGroups using F# Interactive. They work splendidly.

When I save a record of type FighterSummary to JSON, I see something like this for each different fighter:

{"fighter@": "Alessio Sakara",
"record@": {
    "Case": "Some",
    "Fields": ["19-11-0 (1 NC)"]
},
"reach@": {
    "Case": "Some",
    "Fields": [182.88]
},
"stance@": {
    "Case": "Some",
    "Fields": ["Orthodox"]
},
"fighter": "Alessio Sakara",
"record": {
    "Case": "Some",
    "Fields": ["19-11-0 (1 NC)"]
},
"reach": {
    "Case": "Some",
    "Fields": [182.88]
},
"stance": {
    "Case": "Some",
    "Fields": ["Orthodox"]}

The information about each fighter is saved twice -- the first time with an "@" at the end of each field name, the second time without.

What I want instead is for the information about the fighter to be saved only once, without "@" at the end of each field name.

I have read the answers here, in response to a question posted by someone who faced a similar problem. I have tried implementing the suggestions provided there, but they didn't work.

I would appreciate it if anyone can help me with this problem. Thank you.

EDIT:

I also have trouble deserializing JSON. When I run

JsonConvert.DeserializeObject<FighterSummary>(File.ReadAllText(@"G:\Fighter Data JSON Files\Fighters.json"))

I get the following error message:

System.Reflection.CustomAttributeFormatException: 'MemberSerialization' property specified was not found. ---> System.Reflection.CustomAttributeFormatException: 'MemberSerialization' property specified was not found.

Upvotes: 0

Views: 172

Answers (1)

Daniel Fabian
Daniel Fabian

Reputation: 3838

Notice, that in the post you mentioned, they used [<CliMutable>] but the members themselves were not mutable. While looking at your code, I don't see, why you would need mutable (in F#). The mutable keyword allows assignment using <- which is rarely used in F#. The [<CliMutable>] is there, so that the compiled code is mutable, but it remains immutable in F# code.

This is sometimes useful when you want to use the record e.g. using reflection. And JSON.Net should be able to handle things, if you just [<CliMutable>] but not make the mutable keyword in F#.

Upvotes: 1

Related Questions