Click here to Skip to main content
15,887,175 members
Please Sign up or sign in to vote.
1.00/5 (2 votes)
See more:
How can I use Intersect to compare list? Here, I am getting exception:
Newtonsoft.Json.JsonReaderException: 'After parsing a value an unexpected character was encountered: ". Path 'functionalities', line 1, position 278.'


What I have tried:

C#
Dictionary<int, string> blocked = new Dictionary<int, string>();

blocked.Add(5, "CREATE");
blocked.Add(6, "UPDATE");
blocked.Add(9, "UNION");
blocked.Add(12, "SELECT");

var blockedList = blocked.Select(x => x.Value.Trim());

string jsondata = @"{""Id"":null,""FName"":""create"",""LName"":""Denny"","
"DateofJoining"":null,""Date"":""2023 - 08 - 01T00: 00:00"",""CreatedBy"":""ICC0000389"",""levels"":{""RoleId"":""0"",""RoleName"":""select"","
"IsActive"":false,""CreatedDate"":null,""CreatedBy"":""Admin""},"
"functionalities"":[{""levelID"":0,""levelName"":""create""}]"","
"functionalityList"":[]}""}"; 

var jsonDictionary = JsonConvert.DeserializeObject
<Dictionary<object, object>>(jsondata).ToDictionary
(k => k.Key, k => (k.Value ?? ""));
var jsonDictionaryList = jsonDictionary.Select(x => x.Value.ToString().ToUpper().Trim());

var matches = blockedList.Intersect(jsonDictionaryList);

foreach (string match in matches)
{
    Console.WriteLine(match);
}


How can I find the 'select' and 'create' words from jsonDictionary object?
Posted
Updated 19-Aug-23 10:10am
v3
Comments
PIEBALDconsult 16-Aug-23 10:15am    
It's good to see that you have now begun using JSON.
For what reason are you trying to detect SQL keywords in your JSON data?
Rajesh Kumar 2013 16-Aug-23 23:43pm    
To find junk words(sql keyword) from entering from textboxes.
PIEBALDconsult 18-Aug-23 19:40pm    
For what purpose?
PIEBALDconsult 16-Aug-23 10:22am    
Also, rather than using a Dictionary for your SQL keyword list, use a HashSet.
Rajesh Kumar 2013 16-Aug-23 23:44pm    
How can I use HashSet instead of Dictionary regarding my question?

Your JSON is invalid. When you update the JSON to a valid string, the program works. Run it through a validator and you'll see that there is an extra quote at the end of the functionalities array and again at the end of the functionalityList array.

Corrected Json:

{
    "Id": null,
    "FName": "create",
    "LName": "Denny",
    "DateofJoining": null,
    "Date": "2023 - 08 - 01T00: 00:00",
    "CreatedBy": "ICC0000389",
    "levels": {
        "RoleId": "0",
        "RoleName": "select",
        "IsActive": false,
        "CreatedDate": null,
        "CreatedBy": "Admin"
    },
    "functionalities": [{
            "levelID": 0,
            "levelName": "create"
        }
    ]," functionalityList ":[]
}
 
Share this answer
 
First thing, your JSON data is invalid. Here is the corrected data:
JavaScript
{
   "Id":null,
   "FName":"create",
   "LName":"Denny",
   "DateofJoining":null,
   "Date":"2023 - 08 - 01T00: 00:00",
   "CreatedBy":"ICC0000389",
   "levels":{
      "RoleId":"0",
      "RoleName":"select",
      "IsActive":false,
      "CreatedDate":null,
      "CreatedBy":"Admin"
   },
   "functionalities":[
      {
         "levelID":0,
         "levelName":"create"
      }
   ],
   "functionalityList":[
      
   ]
}

NOTE: To fix it, I used: JSON Formatter & Validator[^]

Now we can convert to a variable:
C#
string jsondata = @"{""Id"":null,""FName"":""create"",""LName"":""Denny"",""DateofJoining"":null,""Date"":""2023 - 08 - 01T00: 00:00"",""CreatedBy"":""ICC0000389"",""levels"":{""RoleId"":""0"",""RoleName"":""select"",""IsActive"":false,""CreatedDate"":null,""CreatedBy"":""Admin""},""functionalities"":[{""levelID"":0,""levelName"":""create""}],""functionalityList"":[]}";

Next, I generated the model from the JSON data using: JSON Utils: Generate C#, VB.Net, SQL TAble and Java from JSON[^]. Here is the model generated:
C#
public class Levels
{

    [JsonProperty("RoleId")]
    public string RoleId { get; set; }

    [JsonProperty("RoleName")]
    public string RoleName { get; set; }

    [JsonProperty("IsActive")]
    public bool IsActive { get; set; }

    [JsonProperty("CreatedDate")]
    public object CreatedDate { get; set; }

    [JsonProperty("CreatedBy")]
    public string CreatedBy { get; set; }
}

public class Functionality
{

    [JsonProperty("levelID")]
    public int LevelID { get; set; }

    [JsonProperty("levelName")]
    public string LevelName { get; set; }
}

public class UserData
{

    [JsonProperty("Id")]
    public object Id { get; set; }

    [JsonProperty("FName")]
    public string FName { get; set; }

    [JsonProperty("LName")]
    public string LName { get; set; }

    [JsonProperty("DateofJoining")]
    public object DateofJoining { get; set; }

    [JsonProperty("Date")]
    public string Date { get; set; }

    [JsonProperty("CreatedBy")]
    public string CreatedBy { get; set; }

    [JsonProperty("levels")]
    public Levels Levels { get; set; }

    [JsonProperty("functionalities")]
    public IList<Functionality> Functionalities { get; set; }

    [JsonProperty("functionalityList")]
    public IList<object> FunctionalityList { get; set; }
}

As you can see, it's a single record, not a dictionary.

Now you can deserialize the JSON data:
C#
UserData data = JsonConvert.DeserializeObject<UserData>(jsondata);

There is only one user record, there are multiple fields that could be matched. You need to decide which one. Look at the corrected Json data above.
 
Share this answer
 
v2
Comments
Rajesh Kumar 2013 17-Aug-23 0:14am    
Here
matches
getting empty, but 'levels' list containing a 'create' word that one should be find. It is not finding now, why?
string jsondata = @"{""Id"":null,""FName"":""Raj"",""LName"":""Denny"",""DateofJoining"":null,""Date"":""2023 - 08 - 01T00: 00:00"",""CreatedBy"":""ICC0000389"",""levels"":{""RoleId"":""0"",""RoleName"":""select"",""IsActive"":false,""CreatedDate"":null,""CreatedBy"":""Admin""},""functionalities"":[{""levelID"":0,""levelName"":""create""}],""functionalityList"":[]}";
var jsonDictionary = JsonConvert.DeserializeObject<Dictionary<object, object>>(jsondata).ToDictionary(k => k.Key, k => (k.Value ?? ""));
var jsonDictionaryList = jsonDictionary.Select(x => x.Value.ToString().ToUpper().Trim());

var matches = blockedList.Intersect(jsonDictionaryList);
Graeme_Grant 17-Aug-23 0:25am    
It's not a Dictionary JSON data structure. The last code line in my answer shows how to deserialize.
Rajesh Kumar 2013 17-Aug-23 1:37am    
Okay, can you please update with answer by using HashSet instead of using Dictionary regarding the 'PIEBALDconsult' comment? Because, still I can not find the 'select' and 'create' words from 'matches' variable.
Graeme_Grant 17-Aug-23 1:55am    
Again, it's a single record. To quote:

There is only one user record, there are multiple fields that could be matched. You need to decide which one. Look at the corrected Json data above.
Rajesh Kumar 2013 17-Aug-23 2:05am    
I need to check k.Value only from 'jsonDictionary' varible and also need to compare the values to 'blocked' variable. If k.Value is contain any value from 'blocked' list then need to find out. How can I do with HashSet in c#?
Based on our discussion in the first solution, I have posted this as a separate solution as it is a very different approach and more involved then the first solution.

Okay, So you want to convert all JSON Properties & values to a Dictionary<string, object>. Then you want to see if there are any matches with blocked keywords. You also want to store blocked keywords in a HashSet<T>.

To do the comparison, we can not use the Linq method Intersect. The reason for this can be seen in the output below. you can not assume that the value will only be a blocked keyword, usually any SQL command has more as required by the command syntax.

Here is how it can be done:
C#
string json = @"{
    ""Id"": null,
    ""FName"": ""create"",
    ""LName"": ""Denny"",
    ""DateofJoining"": null,
    ""Date"": ""2023-08-01T00:00:00"",
    ""CreatedBy"": ""ICC0000389"",
    ""levels"": {
        ""RoleId"": ""0"",
        ""RoleName"": ""select"",
        ""IsActive"": false,
        ""CreatedDate"": null,
        ""CreatedBy"": ""Admin""
    },
    ""functionalities"": [
        {
            ""levelID"": 0,
            ""levelName"": ""create""
        }
    ],
    ""functionalityList"": []
}";

Dictionary<string, object> jsonDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);

Console.WriteLine("Converted JSON to Dictionary:");
foreach (var kvp in jsonDict)
{
    Console.WriteLine($"> {kvp.Key}: {kvp.Value}");
}

HashSet<string> blocked = new HashSet<string>
{
    "create",
    "update",
    "union",
    "select"
};

// get the values that are strings and cast to lowercase
List<string> jsonValues = jsonDict
    .Select(kvp => kvp.Value)
    .OfType<string>()
    .Select(x => x.ToLower())
    .ToList();

Console.WriteLine();
Console.WriteLine("Matches:");
var matches = jsonValues.Where(j => blocked.Any(j.Contains));

foreach (string match in matches)
{
    Console.WriteLine($"> {match}");
}

And here is the output:
Converted JSON to Dictionary:
> Id:
> FName: create
> LName: Denny
> DateofJoining:
> Date: 1/08/2023 12:00:00 AM
> CreatedBy: ICC0000389
> levels: {
  "RoleId": "0",
  "RoleName": "select",
  "IsActive": false,
  "CreatedDate": null,
  "CreatedBy": "Admin"
}
> functionalities: [
  {
    "levelID": 0,
    "levelName": "create"
  }
]
> functionalityList: []

Matches:
> create

in the section labelled Converted JSON to Dictionary, I have output a prefix marker ">" so we can see what each key & value consists of. Note:
> levels: {
  "RoleId": "0",
  "RoleName": "select",
  "IsActive": false,
  "CreatedDate": null,
  "CreatedBy": "Admin"
}

Here we can see that children in the data structure do not automatically deserialize. More work is required. We are not looking for exact matches, so this is okay.

UPDATE

If you want to extract every Property & Values, then you need to manually walk the Json tree structure:
C#
using System;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;

internal class Program
{
    private static void Main(string[] args)
    {
        string json = @"
        {
            ""Id"": null,
            ""FName"": ""create"",
            ""LName"": ""Denny"",
            ""DateofJoining"": null,
            ""Date"": ""2023-08-01T00:00:00"",
            ""CreatedBy"": ""ICC0000389"",
            ""levels"": {
                ""RoleId"": ""0"",
                ""RoleName"": ""select"",
                ""IsActive"": false,
                ""CreatedDate"": null,
                ""CreatedBy"": ""Admin""
            },
            ""functionalities"": [{
                    ""levelID"": 0,
                    ""levelName"": ""create""
                }
            ],
            ""functionalityList"": []
        }";

        Dictionary<string, object> jsonDict = ParseJsonToDictionary(json);

        foreach (KeyValuePair<string, object> kvp in jsonDict)
        {
            Console.WriteLine($"> {kvp.Key}: {kvp.Value}");
        }

        HashSet<string> blocked = new HashSet<string>
        {
            "create",
            "update",
            "union",
            "select"
        };

        // get the values that are strings and cast to lowercase
        List<string> jsonValues = jsonDict
            .Select(kvp => kvp.Value)
            .OfType<string>()
            .Select(x => x.ToLower())
            .ToList();

        Console.WriteLine();
        Console.WriteLine("Matches:");
        
        IEnumerable<string> matches = jsonValues.Where(j => blocked.Any(j.Contains));

        foreach (string match in matches)
        {
            Console.WriteLine($"> {match}");
        }

        Console.WriteLine();
        Console.WriteLine("Matches using intersect:");

        IEnumerable<string> matches2 = jsonValues.Intersect(blocked);

        foreach (string match in matches2)
        {
            Console.WriteLine($"> {match}");
        }

        Console.ReadKey();
    }

    private static Dictionary<string, object> ParseJsonToDictionary(string json)
    {
        Dictionary<string, object> dictionary = new Dictionary<string, object>();
        JObject jObject = JObject.Parse(json);
        ParseJObject(jObject, dictionary);
        return dictionary;
    }

    private static void ParseJObject(JObject jObject, Dictionary<string, object> dictionary)
    {
        foreach (JProperty property in jObject.Properties())
        {
            switch (property.Value.Type)
            {
                case JTokenType.Array:
                    foreach (JToken item in property.Value)
                    {
                        if (item.Type == JTokenType.Object)
                        {
                            ParseJObject(item.Value<JObject>(), dictionary);
                        }
                    }
                    break;

                case JTokenType.Object:
                        ParseJObject(property.Value.Value<JObject>(), dictionary);
                    break;

                default:
                    dictionary[property.Name] = ParseJValue(property.Value);
                    break;
            }
        }
    }

    private static object ParseJValue(JToken jValue)
    {
        switch (jValue.Type)
        {
            case JTokenType.Object:
            {
                Dictionary<string, object> nestedDictionary = new Dictionary<string, object>();
                ParseJObject(jValue as JObject, nestedDictionary);
                return nestedDictionary;
            }
            case JTokenType.Array:
            {
                return jValue.Select(ParseJValue).ToList();
            }
            default:
                return (jValue as JValue)?.Value;
        }
    }
}

Now, I highly recommend not to use the Linq Intersect method as it is an exact match. Reasons given above. But for the sake of this exercise, I have added how to do it in the code just above.

Here is the output:
> Id:
> FName: create
> LName: Denny
> DateofJoining:
> Date: 1/08/2023 12:00:00 AM
> CreatedBy: Admin
> RoleId: 0
> RoleName: select
> IsActive: False
> CreatedDate:
> levelID: 0
> levelName: create

Matches:
> create
> select
> create

Matches using intersect:
> create
> select
 
Share this answer
 
v4
Comments
PIEBALDconsult 18-Aug-23 19:39pm    
You can provide a case-insensitive comparer to the HashSet.
Graeme_Grant 18-Aug-23 20:07pm    
Interesting. I don't normally use a HashSet, so you have taught me something new. :)
PIEBALDconsult 18-Aug-23 20:10pm    
Glad to be of service. You may be using HashSets all the time without knowing. They were added to support Linq.
Dig this:

C#
System.Collections.Generic.HashSet<string> keyword =
  new System.Collections.Generic.HashSet<string>
  (
    System.StringComparer.InvariantCultureIgnoreCase
  )
  {
    "SELECT"
  ,
    "UPDATE"
  ,
    "CREATE"
  ,
    "UNION"
  ,
    "JOIN"
  } ;

System.Collections.Generic.Dictionary<string,string> json =
  new System.Collections.Generic.Dictionary<string,string>
  (
    System.StringComparer.InvariantCultureIgnoreCase
  )
  {
    { "Id"            , null                       }
  ,
    { "FName"         , "create"                   }
  ,
    { "LName"         , "Denny"                    }
  ,
    { "DateofJoining" , null                       }
  ,
    { "Date"          , "2023 - 08 - 01T00: 00:00" }
  ,
    { "CreatedBy"     , "ICC0000389"               }
  } ;

System.Collections.Generic.HashSet<string> matches =
  new System.Collections.Generic.HashSet<string>
  (
    json.Values
  ,
    System.StringComparer.InvariantCultureIgnoreCase
  ) ;

matches.IntersectWith ( keyword ) ;



But I repeat: You probably do not need to do a full intersection; you can stop checking once you find a match.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900