1

I am trying to match a complex json-object to a user-defined filter/predicate by using Json.NET and System.Linq.Dynamic. Here is my code:

var json = @"{""Name"":""Jane Doe"",""Occupation"":""FBI Consultant""}";
dynamic person = JObject.Parse(json);
var people = new[] { person };
var isMatch = people.Where("Name=@0", "Jane Doe").Any();
Console.WriteLine(isMatch);

This gives me an error on the line with the Where-statement:

No property or field 'Name' exists in type 'Object'

If I instead use an anonymous object, by replacing the second line with this, it works as it should:

var person = new { Name = "Jane Doe", Occupation = "FBI Consultant"};

Is there another way to deserialize the json string that will allow me to query it by a string predicate to check if the json object matches?

EDIT: The json-string and Where-statement is dynamic and is supplied by the user. There are lots of properties, and i do not know their names before executing the code. Both the name of the field and the value is supplied by the user.

Espo
  • 41,399
  • 21
  • 132
  • 159
  • This can be helpful: http://stackoverflow.com/questions/18734996/how-to-use-linq-with-dynamic-collections – Miłosz Wieczorek Feb 10 '17 at 14:42
  • [`SelectToken`](http://www.newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm) using the wildcard `*` operator may meet your needs. See [Searching for a specific JToken by name in a JObject hierarchy](https://stackoverflow.com/a/29782523/3744182). – dbc Feb 10 '17 at 17:01

4 Answers4

0

Replace your Where statement with this:

var isMatch = people.Where(x => x.Name == "Jane Doe").Any();

Which can be simplified as:

var isMatch = people.Any(x => x.Name == "Jane Doe");

This may not be what you want, but simple System.Linq can fulfill your needs easily.

For the case you want to do this dynamically:

var isMatch = people.Any(x => x.GetValue("Name") == "Jane Doe");
meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
  • My needs are to query an object inside a json-string by a string predicate, so you are right, this will not help me. – Espo Feb 10 '17 at 15:03
  • @Espo I truly understand you, but if you still want to consider using just Json you can review again my answer. – meJustAndrew Feb 10 '17 at 15:29
0
var json = @"{""Name"":""Jane Doe"",""Occupation"":""FBI Consultant""}";
dynamic person = JObject.Parse(json);
var people = new List<object>(){ person };
var filedName = "Name";
var searchValue = "Jane Doe";    

var any = people.Any(p => p.GetType().GetProperty(filedName).GetValue(p, null) as string == searchValue);
Maciej Kozieja
  • 1,812
  • 1
  • 13
  • 32
0

EDIT

Thank you for your comments, that is actually making a difference. Sorry for a bit late answer, but maybe it still would be helpful.

Below complete test that works with dynamic parameter name and parameter value:

        // Given
        var json = @"{""Name"":""Jane Doe"",""Occupation"":""FBI Consultant""}";
        var person = JObject.Parse(json);
        var people = new[] {person};

        // When
        var isMatch = people.Any(p => p.GetValue("Name").Value<string>() == "Jane Doe");

        // Then
        Assert.IsTrue(isMatch);
  • I need to use a string predicate/filter. Both the name of the field and the value is supplied by the user so this will not help me, sorry. – Espo Feb 10 '17 at 15:01
0

After reading the answers and also others posts i created this solution:

void Main()
{
    var json = @"{""Name"":""Jane Doe"",""Occupation"":""FBI Consultant"", ""Info"": {""Age"":28, ""Gender"":""Female""}}";
    Console.WriteLine("Match Name: " + json.JsonMatch("Name", "Jane Doe"));
    Console.WriteLine("Match Age: " + json.JsonMatch("Info.Age", "28"));
}

public static bool JsonMatch(this string json, string key, string value)
{
    dynamic obj = JObject.Parse(json);
    var values = obj.PropertyValues();
    foreach (var element in values)
    {
        if (element.Path == key)
        {
            return element.Value == value;
        }
        if (element.Path == null)
        {
            foreach (var subelement in element)
            {
                if (subelement.Path == key)
                {
                    return subelement.Value == value;
                }
            }
        }
    }
    return false;
}

Hope it helps somebody.

Espo
  • 41,399
  • 21
  • 132
  • 159