Home > Blockchain >  How to search polymorphic JSON objects in c#?
How to search polymorphic JSON objects in c#?

Time:02-04

For example:

json:

{
    "ObjectA": {
        "id": 1,
        "name": "steve",
        "hobbies": 1
    },
    "ObjectB": {
        "id": 2,
        "name": "dave",
        "age": 55
    }
}

c# class:

public class ObjectA
{
    public int id { get; set; }
    public string name { get; set; }
    public int hobbies { get; set; }
}

public class ObjectB
{
    public int id { get; set; }
    public string name { get; set; }
    public int age { get; set; }
}

public class Root
{
    public ObjectA ObjectA { get; set; }
    public ObjectB ObjectB { get; set; }
}

Now I guess that the ObjectA and ObjectB could inherit from a base class giving:

public class ObjectBase
{
    public int id { get; set; }
    public string name { get; set; }
}

public class ObjectA : ObjectBase
{
    public int hobbies { get; set; }
}

public class ObjectB : ObjectBase
{
    public int age { get; set; }
}

public class Root
{
    public ObjectA ObjectA { get; set; }
    public ObjectB ObjectB { get; set; }
}

Now I could create a object from the json using:

Root object = JsonConvert.DeserializeObject<Root>(json);

My question is, for a given id, how could I find the corresponding name or i guess even more useful and as a precursor to name - the corresponding property of object

In practice there would be many objects, so to manually check object.ObjectA.id etc. would be impractical.

CodePudding user response:

Name only lookup

If you need to look up the name property based on the id then you can do that with the following code:

var semiParsed = JsonConvert.DeserializeObject<Dictionary<string, JObject>>(json);
var name = (from node in semiParsed.Values
            let id = (int)node.GetValue("id")
            where id == lookupId
            select (string)node.GetValue("name"))
    .FirstOrDefault();

Console.WriteLine(name);
  • First we deserialize the json into a collection
    • The top most properties' name will be the keys of the Dictionary
    • The top most properties' object will be treated as JObjects (semi parsed jsons)
  • Then we perform a Linq to Json query
    • We iterate through the JObjects and retrieve their id property
      • GetValue returns a JToken and since we know it is a number, we cast it to int
    • We perform a filtering based on the lookupId
    • And we select the name property's value
  • Finally we need to issue a FirstOrDefault method call because the previous query returns an IEnumerable<string>

Here I have assumed that the the id is unique. If the provided lookupId is not defined inside the json then the result will be null.

Wrapping object lookup

If you need to perform a look up for the wrapping object then you need to use Json.NET Schema as well:

var generator = new JSchemaGenerator();
JSchema schemaA = generator.Generate(typeof(ObjectA));
JSchema schemaB = generator.Generate(typeof(ObjectB));

var semiParsed = JsonConvert.DeserializeObject<Dictionary<string, JObject>>(json);
var theNode = (from node in semiParsed.Values
            let id = (int)node.GetValue("id")
            where id == lookupId
            select node)
        .FirstOrDefault();

if (theNode == null)
    return;

if (theNode.IsValid(schemaA))
{
    var objA = theNode.ToObject<ObjectA>();
    Console.WriteLine(objA.hobbies);
} else if (theNode.IsValid(schemaB))
{
    var objB = theNode.ToObject<ObjectB>();
    Console.WriteLine(objB.age);
}
  • First we generate two json schemas from the class definitions
  • Then we perform almost the same query the only difference here is the select part
    • We return here the whole JObject object instead of just its name
  • Finally perform a schema validation
    • If the retrieved json matches to schemaA then we can safely convert (ToObject) to ObjectA
    • We check the json against schemaB as well

CodePudding user response:

the simpliest way would be convert your json to dictionary of JObjects

var dict = JObject.Parse(json).Properties().ToDictionary(jo => jo.Value["id"],jo=>jo.Value);

var searchId=2;

var name = dict[searchId]["name"];  // dave
  •  Tags:  
  • Related