Nicole Phillips
Nicole Phillips

Reputation: 763

Read JSON file into a Jarray and access data dynamically

I am trying to read in a json file which is very complex into a JArray that can be accessed dynamically in a foreach statement. However I am getting an error which is stating 'Current JsonReader item is not an Array' I am able to access the keys and values if I use a JObject but that is not what I need I need to be able to go through the records and search by names or IDs, etc. I am a bit new at newtwonsoft and JSON.net so any help would be appreciated!

JArray o1 = JArray.Parse(File.ReadAllText(@"myfilepath"));

dynamic records = o1;

foreach (dynamic record in records)
{
       Console.WriteLine(record.Id + " (" + record.Name + ")");
}

My json file looks like this, there are multiple records however I have shortened it. I need to access and search by Id or Name however I am having issues accessing.

String json = @"{
  "RecordSetBundles" : [ {
    "Records" : [ {
      "attributes" : {
        "type" : "nihrm__Location__c",
        "url" : "/services/data/v38.0/sobjects/nihrm__Location__c/a0di0000001nI3oAAE"
      },
      "CurrencyIsoCode" : "USD",
      "Id" : "a0di0000001nI3oAAE",
      "Name" : "The City Hotel",
      "nihrm__Abbreviation__c" : "TCH",
      "nihrm__AddressLine1__c" : "1 Main Street",
      "nihrm__AlternateNameES__c" : "El Ciudad Hotel",
      "nihrm__AvailabilityScreenView__c" : "Combined",
      "nihrm__Geolocation__c" : null,
      "nihrm__HideBookingsFromPortal__c" : false,
      "nihrm__IsActive__c" : true,
      "nihrm__IsPlannerPortalEnabled__c" : false,
      "nihrm__isRemoveCancelledEventsFromBEOs__c" : false,
      "nihrm__ManagementAffliation__c" : "NI International",
      "nihrm__NearestAirportCode__c" : "MHT",
      "nihrm__Phone__c" : "(207) 555-5555",
      "nihrm__PostalCode__c" : "04103",
      "nihrm__PropertyCode__c" : "TCH",
      "nihrm__RegionName__c" : "Northeast",
      "nihrm__RestrictBookingMoveWithPickup__c" : true,
      "nihrm__RohAllowedStatuses__c" : "Prospect;Tentative;Definite",
      "nihrm__StateProvince__c" : "ME",
      "nihrm__SystemOfMeasurement__c" : "Standard",
      "nihrm__TimeZone__c" : "GMT-05:00 Eastern Daylight Time (America/New_York)",
      "nihrm__UpdateBookingEventAverageChecks__c" : false,
      "nihrm__UseAlternateLanguage__c" : false,
      "nihrm__Website__c" : "www.thecityhotelweb.com"
    } ],
    "ObjectType" : "nihrm__Location__c",
    "DeleteFirst" : false
  },

Here is a link to the entire json: https://codeshare.io/rGL6K5

Upvotes: 1

Views: 5401

Answers (3)

Equalsk
Equalsk

Reputation: 8194

The other answers show strong typed classes. If you can do this and you're sure the structure won't change I'd recommend doing it that way. It'll make everything else much easier.

If you want to do it with a dynamic object, then you can get what you want this way.

// GET JSON DATA INTO DYNAMIC OBJECT
var data  = JsonConvert.DeserializeObject<dynamic>(File.ReadAllText(@"myfilepath"));

// GET TOP LEVEL "RecordSetBundles" OBJECT
var bundles = data.RecordSetBundles;

// LOOP THROUGH EACH BUNDLE OF RECORDS
foreach (var bundle in bundles)
{
    // GET THE RECORDS IN THIS BUNDLE
    var records = bundle.Records;

    // LOOP THROUGH THE RECORDS
    foreach (var record in records)
    {
        // WRITE TO CONSOLE
        Console.WriteLine(record.Id.ToString() + " (" + record.Name.ToString() + ")");
    }
}

Produces this output:

a0di0000001nI3oAAE (The City Hotel)
a0xi0000000jOQCAA2 (Rounds of 8)
a0xi0000001aUbfAAE (Additional Services)
a0xi0000004ZnehAAC (Citywide)
a0xi0000001YXcCAAW (Cocktail Rounds)

etc etc

Upvotes: 1

Tinwor
Tinwor

Reputation: 7973

This error Current JsonReader item is not an Array is self explanatory: the object parsed is not an array.However without see the Json we can only suppose that this Json is an object and if you want use a dynamic object change the code as follow:

dynamic myJson = JsonConvert.DeserializeObject(File.ReadAllText(@"myfilepath"));
var currency = myJson.RecordSetBundles[0].Records[0].CurrencyIsoCode
//Access to other property in your dynamic object

EDIT

Your JSON object seems quite complex and access via dynamic can be complex I suggest you to use JsonConvert.DeserializeObject<T>(string).
From the json that yoou have posted the class looks like this:

public class Attributes
{
    public string type { get; set; }
    public string url { get; set; }
}

public class Record
{
    public Attributes attributes { get; set; }
    public string CurrencyIsoCode { get; set; }
    public string Id { get; set; }
    public string Name { get; set; }
    public string nihrm__Abbreviation__c { get; set; }
    public string nihrm__AddressLine1__c { get; set; }
    public string nihrm__AlternateNameES__c { get; set; }
    public string nihrm__AvailabilityScreenView__c { get; set; }
    public object nihrm__Geolocation__c { get; set; }
    public bool nihrm__HideBookingsFromPortal__c { get; set; }
    public bool nihrm__IsActive__c { get; set; }
    public bool nihrm__IsPlannerPortalEnabled__c { get; set; }
    public bool nihrm__isRemoveCancelledEventsFromBEOs__c { get; set; }
    public string nihrm__ManagementAffliation__c { get; set; }
    public string nihrm__NearestAirportCode__c { get; set; }
    public string nihrm__Phone__c { get; set; }
    public string nihrm__PostalCode__c { get; set; }
    public string nihrm__PropertyCode__c { get; set; }
    public string nihrm__RegionName__c { get; set; }
    public bool nihrm__RestrictBookingMoveWithPickup__c { get; set; }
    public string nihrm__RohAllowedStatuses__c { get; set; }
    public string nihrm__StateProvince__c { get; set; }
    public string nihrm__SystemOfMeasurement__c { get; set; }
    public string nihrm__TimeZone__c { get; set; }
    public bool nihrm__UpdateBookingEventAverageChecks__c { get; set; }
    public bool nihrm__UseAlternateLanguage__c { get; set; }
    public string nihrm__Website__c { get; set; }
}

public class RecordSetBundle
{
    public List<Record> Records { get; set; }
    public string ObjectType { get; set; }
    public bool DeleteFirst { get; set; }
}

public class RootObject
{
    public List<RecordSetBundle> RecordSetBundles { get; set; }
}

To deserialize it using Newtonsoft:

var myObject = JsonConvert.DeserializeObject<RootObject>(myJsonStrin);

Upvotes: 1

Ross Miller
Ross Miller

Reputation: 646

Do you know if the properties of your JSon object will be the same each time the request is made? Not the values, just the names? If so, create a concrete type and use JSonObjectSerializer to deserialize into an object. If should be able to create a dictionary collection on that object that deserialized your JSon data into Key Value pairs. Then you can iterate like any other collection via the Keys collection.

You don't really need to use dynamic objects unless you really don't know what you are dealing with on the input. Ascertain if your incoming data has consistent property names each time the request is made.

An example could be

var myData = JsonSerializer.Deserialize<myDataType>(incomingTextData);

myDataType would have a collection that can handle your array.

Upvotes: 1

Related Questions