0

For a project that I am working on, I'm trying to replicate a JSON file that was created with JavaScript in C#. For this project I have to label images before I can run them through a Neural Network, and to annotate those images I use via. The resulting JSON file looks like this.

"Dog.png173732": {
    "filename": "Dog.png",
    "size": 173732,
    "regions": [
        {
            "shape_attributes": {
                "name": "polygon",
                "all_points_x": [
                    189,
                    192,
                    229,
                    230
                ],
                "all_points_y": [
                    2,
                    148,
                    148,
                    2
                ]
            },
            "region_attributes": {
                "Animal": "Dog"
            }
        }
    ],
    "file_attributes": {}
},

To replicate this in C#, I created a class with multiple getters and setters, while using the Nuget package JSON.Net, to serialize my JSON.

public class Animal
{
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string Filename { get; set; }
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public int? Size { get; set; }
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public List<Animal> Regions { get; set; }
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public List<Animal> Shape_attributes { get; set; }
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string Name { get; set; }
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public List<int> All_points_x { get; set; }
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public List<int> All_points_y { get; set; }
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public List<Animal> Region_attributes { get; set; }
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string Animal { get; set; }


    public void CreateJSON()
    {
        string output = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) +
            @"\source\repos\Testing\";

        var root = new Animal()
        {
            Filename = "Dog.png",
            Size = 173732,
            Regions = new List<Animal>()
            {
                new Animal()
                {
                    Size = null,

                    Shape_attributes = new List<Animal>()
                    {
                        new Animal()
                        {
                            Name = "polygon",
                            All_points_x = All_points_x,
                            All_points_y = All_points_y
                        }
                    },

                    Region_attributes = new List<Animal>()
                    {
                        new Animal()
                        {
                            Animal = "Dog"
                        }
                    }
                }
            }
        };

        var json = JsonConvert.SerializeObject(root, new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        });

        File.WriteAllText(output + "testing.json", json);
    }

Once I execute the following code, my output is as follows.

{
    "filename": "Dog.png",
    "size": 173732,
    "regions": [
        {
            "shape_attributes": [
                {
                    "name": "polygon",
                    "all_points_x": [
                        389,
                        43
                    ],
                    "all_points_y": [
                        33,
                        215
                    ]
                }
            ],
            "region_attributes": [
                {
                    "animal": "Dog"
                }
            ]
        }
    ]
}

How can I adjust my code to better replicated via's Json file? Is there a better way that I could be doing things?

2
  • I am not going to play 'find whats different in these 2 things', but you could feed the original JSON to VS and it will create the correct classes for you. Commented Nov 4, 2020 at 23:36
  • 1
    You are pretty close, it's just the Animal inside region attributes and the fact that the filename and filesize are a property on the parent object that are missing (and the file_attributes. Do you only have to write out the information, or do you also have to read it in? If you have to write it out, just add JsonProperty("Animal") and serialize IDictionary<string,object> where the dictionary has your key, and the object is the animal Commented Nov 4, 2020 at 23:43

2 Answers 2

3

How about something like this...

First I created classes for each of the inner bits of your structure:

public class RegionAttributes
{
    public string Animal { get; set; }
}

public class ShapeAttributes
{
    public string name { get; set; }
    public List<int> all_points_x { get; set; }
    public List<int> all_points_y { get; set; }
}

public class Region
{
    public ShapeAttributes shape_attributes { get; set; }
    public RegionAttributes region_attributes { get; set; }
}

public class Thing
{
    public string filename { get; set; }
    public int size { get; set; }
    public List<Region> regions { get; set; }
    public dynamic file_attributes { get; set; }
}

You should be able to see that the hierarchy of these classes matches the hierarchy of your JSON.

Then I initialize one of these Things:

var thing = new Dictionary<string, Thing>
{
    {
        "Dog.png173732", new Thing
        {
            filename = "Dog.png",
            size = 173732,
            regions = new List<Region>
            {
                new Region
                {
                    shape_attributes = new ShapeAttributes
                    {
                        name = "polygon",
                        all_points_x = new List<int> {189, 192, 229, 230},
                        all_points_y = new List<int> {2, 148, 148, 2},
                    },
                    region_attributes = new RegionAttributes
                    {
                        Animal = "dog",
                    }
                }
            },
            file_attributes = new object()
        }
    }
};

Again, you can see the similarity of the structure in the code to the structure of the JSON. Finally, I do this (using the Newtonsoft JSON package):

var result = JsonConvert.SerializeObject(thing, Formatting.Indented);

This results in this string:

{
  "Dog.png173732": {
    "filename": "Dog.png",
    "size": 173732,
    "regions": [
      {
        "shape_attributes": {
          "name": "polygon",
          "all_points_x": [
            189,
            192,
            229,
            230
          ],
          "all_points_y": [
            2,
            148,
            148,
            2
          ]
        },
        "region_attributes": {
          "Animal": "dog"
        }
      }
    ],
    "file_attributes": {}
  }
}

I think that's a match. You'll probably want to use attributes to get C#-ish names in the C# code and JSON-ish names in the JSON output. But, there you go...

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! Your dedication is awesome!
2

You were quite close to it, but your structure was missing. There are a couple of things you could look at, for example, the NamingStrategy that the json object is using is called SnakeCase and NewtonSoft has a default implementation for this strategy.

To set the default convention, you could make it available through:

JsonConvert.DefaultSettings = () => {
    return new JsonSerializerSettings() {
        ContractResolver = new DefaultContractResolver {
            NamingStrategy = new SnakeCaseNamingStrategy()
        },
        Formatting = Formatting.Indented
    };
};

This then allows you to use normal C# naming conventions for your poco structure, which could look like this:

public class Root : Dictionary<string, Animal> {
}

public class Animal {
  public string Filename { get; set; }
  public long Size { get;set; }
  public IList<Region> Regions { get;set; }
  [JsonExtensionData]
  public IDictionary<string, object> Properties { get;set; }
}

public class Region {
  public ShapeAttribute ShapeAttributes { get; set; }
  public RegionAttribute RegionAttributes { get; set; }
}

public class ShapeAttribute {
  public string Name { get; set; }
  public IList<int> AllPointsX { get; set; }
  public IList<int> AllPointsY { get; set; }
}

public class RegionAttribute {
  [JsonProperty("Animal")]
  public string Animal { get;set; }
}   

This has 2 caveats, the Animal property inside the RegionAttribute class, should be defined directly (as it capitalized), and for all remaining unspecified properties (like file_attributes) I added an IDictionary<string, object> Properties that would hold all non-specified properties on the Animal object.

I provided a sample based on your data in this dotnetfiddle

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.