none
Looping Json Items RRS feed

  • Question

  • Hi All,

    I have the following Json string

    {
      "FormID": "3604904",
      "UniqueID": "616329415",
      "First Name": {
        "value": "Dave",
        "type": "text"
      },
      "Last Name": {
        "value": "Bassett",
        "type": "text"
      },
      "Signature": {
        "value": "https://",
        "type": "signature"
      },
      "Instance Id": {
        "value": "74625115-e63e-4e68-a4bf-4d8a601377cb",
        "type": "text"
      },
      "record Id": {
        "value": "1dccca2d-159b-4ae9-bf50-76ce639a08bb",
        "type": "text"
      },
      "Form Id": {
        "value": "",
        "type": "text"
      }
    }

    The names (First Name, Last Name etc) may change or not even be there, so can't create the object and do the following JsonConvert.DeserializeObject. 

    What would be the best way to iterate through each item?

    Regards,

    Ben

    Friday, May 22, 2020 6:25 PM

All replies

  • Deserialize to a class which represents the data as a list then use a for-each to iterate.

    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Friday, May 22, 2020 6:50 PM
    Moderator
  • Hi Karen,

    Thanks for your reply.

    You mean something like this?

        public class FormData
        {
            private string formid = String.Empty;
            private string uniqueid = String.Empty;
            private List<FieldData> fielditems = new List<FieldData>();
    
            public string FormID { get => formid; set => formid = value; }
            public string UniqueID { get => uniqueid; set => uniqueid = value; }
            public List<FieldData> Fields { get => fielditems; set => fielditems = value; }
        }
    
        [Serializable]
        public class FieldData
        {
            private string Value = String.Empty;
            private string Type = String.Empty;
    
            public string value { get => Value; set => this.Value = value; }
            public string type { get => Type; set => Type = value; }
        }

    And then something like this?

    var fd = JsonConvert.DeserializeObject<FormData>(m1.ToString());

    If so, I get the form id and unique id values, but none of the others.

    Regards,

    Ben

    Friday, May 22, 2020 6:56 PM
  • If you copy the json then in Visual Studio use the following to create the classes followed by adding [Serializable] as needed.


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Friday, May 22, 2020 7:06 PM
    Moderator
  • Thanks for that, actually never knew that existed :) 

    However, that constructed it incorrectly

    public class Rootobject
        {
            public string FormID { get; set; }
            public string UniqueID { get; set; }
            public FirstName FirstName { get; set; }
            public LastName LastName { get; set; }
            public Signature Signature { get; set; }
            public InstanceId InstanceId { get; set; }
            public RecordId recordId { get; set; }
            public FormId FormId { get; set; }
        }
    
        public class FirstName
        {
            public string value { get; set; }
            public string type { get; set; }
        }
    
        public class LastName
        {
            public string value { get; set; }
            public string type { get; set; }
        }
    
        public class Signature
        {
            public string value { get; set; }
            public string type { get; set; }
        }
    
        public class InstanceId
        {
            public string value { get; set; }
            public string type { get; set; }
        }
    
        public class RecordId
        {
            public string value { get; set; }
            public string type { get; set; }
        }
    
        public class FormId
        {
            public string value { get; set; }
            public string type { get; set; }
        }

    As things like first name, last name etc will change. There may be a field called 'Middle Initial', we just don't know what and how many fields come in.

    Regards,

    Ben

    Friday, May 22, 2020 7:16 PM
  • If there are unknowns then it's not possible to use this then. You need a schema beforehand to code in this fashion

    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Friday, May 22, 2020 8:00 PM
    Moderator
  • I didn't think so. Is there not a way I could iterate through a dynamic object or something like that?

    Regards,

    Ben

    Friday, May 22, 2020 8:14 PM
  • I didn't think so. Is there not a way I could iterate through a dynamic object or something like that?

    Regards,

    Ben

    With dynamic, you still need to know the property names.

    using Newtonsoft.Json;
    .
    .
    .
    dynamic results = JsonConvert.DeserializeObject<dynamic>(YOUR_JSON);


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Friday, May 22, 2020 8:16 PM
    Moderator
  • "As things like first name, last name etc will change"

    APIs cannot change what is being returned. It is immutable upon release. If an API is doing this then the company who produced it is wrong and they should be notified of this behavior. This is a complete and utter violation of the core concept of how APIs work. You can google for the many, many different approaches to versioning that professional APIs use to help ensure this. The API is broken if it is not following this behavior.

    APIs can add new members to an existing type without breaking things. This is allowed and should not break existing clients. That is because clients don't have to read all members, just the ones they care about. You mentioned there could be variants like 'Middle Initial'. That's fine. You don't need a separate type for each one. If you're using JSON.NET then it ignores members that don't exist. So add any "extra" members that may come back in the API call. Your code will need to deal with missing members but JSON won't care in the least.

    public class Rootobject
        {
            public string FormID { get; set; }
            public string UniqueID { get; set; }
            public FirstName FirstName { get; set; }
            public LastName LastName { get; set; }      
            public Signature Signature { get; set; }
            public InstanceId InstanceId { get; set; }
            public RecordId recordId { get; set; }
            public FormId FormId { get; set; }
    
            //Optional stuff
            public ValuePair MiddleInitial { get; set; }
            public double SomeValue { get; set; }
            public int ThisNeverExists { get; set; }
        }
    
        //Generic structure
        public class ValuePair
        {
            public string value { get; set; }
            public string type { get; set; }
        }
    
        public class FirstName
        {
            public string value { get; set; }
            public string type { get; set; }
        }
    
        public class LastName
        {
            public string value { get; set; }
            public string type { get; set; }
        }
    
        public class Signature
        {
            public string value { get; set; }
            public string type { get; set; }
        }
    
        public class InstanceId
        {
            public string value { get; set; }
            public string type { get; set; }
        }
    
        public class RecordId
        {
            public string value { get; set; }
            public string type { get; set; }
        }
    
        public class FormId
        {
            public string value { get; set; }
            public string type { get; set; }
        }

    Then in your code you'll have to handle the fact that this is optional.

    var data = JsonConvert.DeserializeObject<RootObject>(json);
    
    var initial = data.MiddleInitial?.Value ?? "";

    Note that not all JSON parsers work this way so you may need to adjust the serializer settings. Note also that JSON.NET (and others) also support an `Extensions` member. If you mark a member as an extension (it must be a dictionary of string to objects IIRC. Then any JSON that does not match an explicit propery/field is automatically added to this dictionary. This allows your code to get access to everything that was sent even if you don't recognize it.

    public class RootObject
    {
       public FirstName FirstName { get; set; }
     
       [JsonExstensionData]
       public Dictionary<string, object> MissingData {get;set; }
    }
    
    //What was sent we didn't explicitly handle
    foreach (var extras in obj.MissingData)
    {
    };

    The downside to this is that the object may be a JObject (or whatever the serializer uses) to wrap the underlying JSON. So you have to be very aware of whether you're dealing with a primitive or complex object.

    Finally note that JSON.NET has been replaced by System.Text.Json in .NET Framework/Core going forward. It is recommended that you refer to the documentation on when you should consider using the newer parser going forward. Microsoft is switching to this serializer for all the framework code but it is still not quite up to the capabilities of JSON.NET. Still for simple parsing like you've shown it as faster.


    Michael Taylor http://www.michaeltaylorp3.net

    Saturday, May 23, 2020 3:07 PM
    Moderator
  • Hi loftty,

    Another thing to note is that the properties in your json string have spaces, and the corresponding properties in the class are not, which will cause those data cannot be read.

    For this situation, we can use an attribute to connect them.

    Newtonsoft.Json -> [JsonProperty ("First Name")]

    System.Text.Json -> [JsonPropertyName ("First Name")]

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, May 25, 2020 2:01 AM