Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using JSON.NET to access JSON attributes to create a C# dictionary

Tags:

json

c#

json.net

I want to convert what is ultimately a dictionary in JSON to a C# dictionary without much ado.
Am I barking up the wrong tree by using the JSON.NET library here? The JArray class doesn't want to give me anything to access the attribute (only the value) ie it tells me the value but never the "key".
I can't quite believe no one else would find this limiting, so am assuming I'm missing something. My muddled attempt is this:

Given this json:

{
 "appSettings" : [
    {"rows": "5"},
    {"columns" : "7"}
  ]
}

I would like to select this into a dictionary like this:

var dict = jsonObject["appSettings"].Select(s => new 
{
    key = s.Name,    // wish this property existed
    value = s.Value  // wish this property existed
}).ToDictionary(s => s.key, s => s.value);

This is my UnitTest:

[Test]
public void CanLoadJsonAppSettings()
{
var json = @"
    ""{appSettings"" : [ 
      {""ViewRows"" : ""1""},
      {""ViewColumns"" : ""2""}
    ]}";
    var dict = CreateJsonDictionary(json);
    Assert.That(dict.Count, Is.EqualTo(2));
}

public CreateJsonDictionary(string jsonText)
{
  var jsonObject = JObject.Parse(jsonText);

  return jsonObject["appSettings"].Select(s => new 
  { 
    key = s.Name,
    value = s.Value
  }).ToDictionary(s => s.key, s => s.value);
}

EDIT: Thanks to @jim, we are a little closer. For completeness, I will document the slightly awkward step I needed in order to get at the object I needed:

I had to change my JSON. Instead of using an array (as in the code above) I used a more simple/truer dictionary:

var json = @"
{ 
  ""appSettings"" : { 
    ""ViewRows""    : ""1"",
    ""ViewColumns"" : ""2""
    }
}";

Then I had to Parse, get a JSON JObject, then convert back to a string, and then Deserialize:

var jo = JObject.Parse(jsonText);
var appSettings = jo["appSettings"];
var appSettings = JsonConvert.DeserializeObject<Dictionary<string, string>>(appSettings.ToString());

So part of my problem, was getting JSON confused. Even so, if there is a more elegant way to do this, I'm all ears.

EDIT2: I still had to solve the original problem above, converting a JSON array to a dictionary. Once my JSON is corrected to contain proper name/value pairs:

"connectionStrings": [
{"name" : "string1", "value" : "value1"},
{"name" : "string2", "value" :"value2"},
]

This is the code that solved it (nb it looks a lot like my original attempt):

var jsonObj = JObject.Parse(jsonText);
var conStrings = jsonObj.Properties().Select(s => 
  new {
  key = s.Name,
  value = s.Value.ToString()
}).ToDictionary(s => s.key, s => s.value);

And this only works if you have no other arrays.

like image 323
PandaWood Avatar asked Jan 31 '11 07:01

PandaWood


3 Answers

Panda,

Verbatim from james newton king himself on SO to a similar question:

// Json.NET does this...

string json = @"{""key1"":""value1"",""key2"":""value2""}";
Dictionary<string, string> values 
    = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);

you can find the thread here:

How can I deserialize JSON to a simple Dictionary<string,string> in ASP.NET?

hope this helps (tho not 100% certain on how this works with complex tree structures)

like image 183
jim tollan Avatar answered Oct 05 '22 12:10

jim tollan


This is the MS way to do this, but it's quite complex and I really think than YvesR's solution might be easier to implement.

http://atsung.wordpress.com/2008/08/07/javascriptserializer-example/

like image 36
David Mårtensson Avatar answered Oct 05 '22 12:10

David Mårtensson


To convert js assosiative array into dictionary, use may use converter which is as follows:

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace MyJsonConverters
{
    public class AssosiativeArrayConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType.GetInterface(typeof(IDictionary<,>).Name) != null;
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject jObject = JObject.Load(reader);

            var result = Activator.CreateInstance(objectType);
            var addMethod = result.GetType().GetMethod("Add");
            var dictionaryTypes = objectType.GetGenericArguments();

            foreach (JProperty property in jObject.Properties())
            {
                var key = Convert.ChangeType(property.Name, dictionaryTypes[0]);

                var value = serializer.Deserialize(property.Value.CreateReader(), dictionaryTypes[1]);

                addMethod.Invoke(result, new[] { key, value });
            }

            return result;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
}

then usage is as follows:

Dictionary<string, string> dictionary;
dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(value, new AssosiativeArrayConverter);

where T is your Dictionary e.g. Dictionary or whatever you like.

Json which is deserialized in my case looks like follows:

{ "MyDictionary": { "key1": [ "value1", "value2", "value3" ], "key2": [ ] }

like image 23
tekado Avatar answered Oct 05 '22 13:10

tekado