-1

The title is exactly what I meant

All the questions on Stackoverflow asks for whether if the json data is an object or array but what I'm looking for is to see if I can find out if the array is an array of primitive types or objects.

Currently, i already can identify if its an array or not, just that I'm unable to convert if it is not an array of strings.

This code is wrapped in a for loop, where it is (var comArrEl in comArr), where comArr is an array of strings. This array stores something like "gesmes:Envelope:Cube:Cube:@currency="USD"

Basically we're trying to write a universal API wrapper here.

// Identify if its an array or an object
if (token is JArray)
{
    try
    {
        // Parse the comArrEl to an integer for index access
        if (int.TryParse(comArrEl, out int index))
        {
            // Pump in the array
            var dataList = token.ToObject<List<object>>();

            // Is it the last?
            if (comArrEl != last)
            {
                // let's work it out
                // update the token
                if (index >= 0 && index < dataList.Count)
                {
                    token = JToken.Parse(JsonConvert.SerializeObject(dataList[index]));
                }
            }
            // Yes its the last
            else
            {
                var property = dataList[index];

                // Number checks
                // Make sure the datalist element we're targetting contains a proper value.
                if (decimal.TryParse(property, out decimal val))
                {
                    // Update it
                    _currencyPairComponentService.UpdatePairValue(component.Id, val);
                }
            }
        }
        // Incorrect comArrEl.
        else
        {
            return false;
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
}

As you can see, the exception triggers on line 2.

Sample payload to code:

[
    {
        "@currency": "USD",
        "@rate": "1.1354"
    },
    {
        "@currency": "JPY",
        "@rate": "128.31"
    },
    {
        "@currency": "BGN",
        "@rate": "1.9558"
    },
    {
        "@currency": "CZK",
        "@rate": "25.886"
    },
    {
        "@currency": "DKK",
        "@rate": "7.4630"
    },
    {
        "@currency": "GBP",
        "@rate": "0.88885"
    },
    {
        "@currency": "HUF",
        "@rate": "323.49"
    },
    {
        "@currency": "PLN",
        "@rate": "4.2826"
    },
    {
        "@currency": "RON",
        "@rate": "4.6528"
    },
    {
        "@currency": "SEK",
        "@rate": "10.1753"
    },
    {
        "@currency": "CHF",
        "@rate": "1.1328"
    },
    {
        "@currency": "ISK",
        "@rate": "139.40"
    },
    {
        "@currency": "NOK",
        "@rate": "9.6480"
    },
    {
        "@currency": "HRK",
        "@rate": "7.3990"
    },
    {
        "@currency": "RUB",
        "@rate": "75.8385"
    },
    {
        "@currency": "TRY",
        "@rate": "6.0453"
    },
    {
        "@currency": "AUD",
        "@rate": "1.5569"
    },
    {
        "@currency": "BRL",
        "@rate": "4.3692"
    },
    {
        "@currency": "CAD",
        "@rate": "1.5076"
    },
    {
        "@currency": "CNY",
        "@rate": "7.7848"
    },
    {
        "@currency": "HKD",
        "@rate": "8.8695"
    },
    {
        "@currency": "IDR",
        "@rate": "16344.08"
    },
    {
        "@currency": "ILS",
        "@rate": "4.2293"
    },
    {
        "@currency": "INR",
        "@rate": "80.0660"
    },
    {
        "@currency": "KRW",
        "@rate": "1264.39"
    },
    {
        "@currency": "MXN",
        "@rate": "23.2282"
    },
    {
        "@currency": "MYR",
        "@rate": "4.7165"
    },
    {
        "@currency": "NZD",
        "@rate": "1.6398"
    },
    {
        "@currency": "PHP",
        "@rate": "59.878"
    },
    {
        "@currency": "SGD",
        "@rate": "1.5520"
    },
    {
        "@currency": "THB",
        "@rate": "37.190"
    },
    {
        "@currency": "ZAR",
        "@rate": "15.6366"
    }
]
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
Nicholas
  • 1,883
  • 21
  • 39
  • _How do you check if a JSON array is an array of objects._ If you already know how to test whether something is an array and also test whether something is an object, wouldn't iterating through the array and testing each element do the trick? Or am I missing something? – ardila Dec 06 '18 at 10:50
  • @ardila the point is to identify whether if it is an array of objects or not before knowing it because this code is supposed to handle any of the possibilities – Nicholas Dec 06 '18 at 10:53
  • @ardila I don’t want to convert it to a string list and get an exception then convert it to a list of objects, pretty sure there’s a way to check it before opening it – Nicholas Dec 06 '18 at 10:54
  • What do you want to do if there is a mixture of strings and objects? – dbc Dec 06 '18 at 13:23
  • @dbc doesn’t matter, if there’s an object, a string will convert to an object just fine. – Nicholas Dec 06 '18 at 14:12
  • check it out below, didn't want to reveal it but i guess i have to. – Nicholas Dec 06 '18 at 17:37

1 Answers1

0

This method can dynamically iterate a JSON result, be it object or primitive. This method loops through an array called requestComponents , which defines the properties we want to obtain from the JSON payload.

It then breaks down each requestComponent string into an array (i.e. "gesmes:Envelope/Cube/Cube/Cube/0=>@rate") to allow us to go down the object/array. Sometimes its an array, sometimes its an object, we can easily go down that path. A custom "=>" syntax that only works for the last element of the requestComponent array will tell the code to retrieve that property. (sample: 0=>@currency // That will tell us to obtain the object of index 0, the "@currency" property)

Here's the code, do not focus on the inputs, but rather the logic. The main point here is to peek into the upcoming property to see if its an array or etc before processing it. So your target could be

object/array/object/array/array element index

or it could also be

array/object/array/object/property

voila

ResponseType is an Enum, RequestComponents is an object that contains the string to traverse (That's all that matters in that object tbh) and token is basically the json payload.

public bool Update(JToken token, ResponseType resType, IEnumerable<RequestComponent> requestComponents)
{
    // For each component we're checking
    foreach (var component in requestComponents)
    {
        var comArr = component.QueryComponent.Split("/"); // Split the string if its nesting
        var last = comArr.LastOrDefault(); // get the last to identify if its the last

        // Iterate the queryComponent Array
        foreach (var comArrEl in comArr)
        {
            // Null check
            if (comArrEl != null)
            {
                // CHECK CURRENT TYPE
                // Identify if its an array or an object
                if (token is JArray)
                {
                    try
                    {
                        // Is it the last?
                        if (comArrEl != last)
                        {
                            // Parse the comArrEl to an integer for index access
                            if (int.TryParse(comArrEl, out int index))
                            {
                                // Pump in the array, treat it as anonymous.
                                var dataList = token.ToObject<List<JObject>>();

                                // let's work it out
                                // update the token
                                if (index >= 0 && index < dataList.Count)
                                {
                                    // Traverse the array
                                    token = JToken.Parse(JsonConvert.SerializeObject(dataList[index]));
                                }
                            }
                        }
                        // Yes its the last
                        else
                        {
                            // See if theres any property we need to refer to.
                            var comArrElArr = comArrEl.Split("=>");

                            if (int.TryParse(comArrElArr[0], out var index))
                            {
                                // Traverse first
                                var rawData = token.ToObject<List<JToken>>()[index];

                                // if its 1, we assume its just an array of a primitive type
                                if (comArrElArr.Length == 1)
                                {
                                    // Retrieve the value.
                                    var rawVal = rawData.ToString();

                                    // https://stackoverflow.com/questions/23131414/culture-invariant-decimal-tryparse
                                    var style = NumberStyles.Any;
                                    if (ExponentHelper.IsExponentialFormat(rawVal))
                                    {
                                        style = NumberStyles.Float;
                                    }

                                    // If it is an exponent
                                    if (decimal.TryParse(rawVal, style, CultureInfo.InvariantCulture,
                                        out var val))
                                    {
                                        if (val > 0)
                                        {
                                            // Update it
                                            _currencyPairComponentService.UpdatePairValue(component.Id, val);
                                        }
                                    }
                                }
                                // Oh no.. non-primitive...
                                else if (comArrElArr.Length == 2)
                                {
                                    // Object-ify
                                    var rawObj = JObject.Parse(rawData.ToString());

                                    // Obtain the desired value
                                    var rawVal = rawObj[comArrElArr[1]].ToString();

                                    // As usual, update it
                                    // https://stackoverflow.com/questions/23131414/culture-invariant-decimal-tryparse
                                    var style = NumberStyles.Any;
                                    if (ExponentHelper.IsExponentialFormat(rawVal))
                                    {
                                        style = NumberStyles.Float;
                                    }

                                    // If it is an exponent
                                    if (decimal.TryParse(rawVal, style, CultureInfo.InvariantCulture,
                                        out var val))
                                    {
                                        if (val > 0)
                                        {
                                            // Update it
                                            _currencyPairComponentService.UpdatePairValue(component.Id, val);
                                        }
                                    }
                                }
                                else
                                {
                                    // Invalid
                                    return false;
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex);
                    }
                }
                else if (token is JObject)
                {
                    // Pump in the object
                    JObject obj = token.ToObject<JObject>();

                    // Is it the last?
                    if (comArrEl != last)
                    {
                        // let's work it out
                        // update the token
                        token = obj.SelectToken(comArrEl);
                    }
                    // Yes its the last
                    else
                    {
                        // See if theres any property we need to refer to.
                        var comArrElArr = comArrEl.Split("=>");

                        // Traverse first
                        var rawData = (string) obj.SelectToken(comArrElArr[0]);

                        if (rawData != null)
                        {
                            // if its 1, we assume its just an array of a primitive type
                            if (comArrElArr.Length == 1)
                            {
                                // Retrieve the value.
                                var rawVal = rawData.ToString();

                                // https://stackoverflow.com/questions/23131414/culture-invariant-decimal-tryparse
                                var style = NumberStyles.Any;
                                if (ExponentHelper.IsExponentialFormat(rawVal))
                                {
                                    style = NumberStyles.Float;
                                }

                                // If it is an exponent
                                if (decimal.TryParse(rawVal, style, CultureInfo.InvariantCulture,
                                    out var val))
                                {
                                    if (val > 0)
                                    {
                                        // Update it
                                        _currencyPairComponentService.UpdatePairValue(component.Id, val);
                                    }
                                }
                            }
                            // Oh no.. non-primitive...
                            else if (comArrElArr.Length == 2)
                            {
                                // Object-ify
                                var rawObj = JObject.Parse(rawData.ToString());

                                // Obtain the desired value
                                var rawVal = rawObj[comArrElArr[1]].ToString();

                                // As usual, update it
                                // https://stackoverflow.com/questions/23131414/culture-invariant-decimal-tryparse
                                var style = NumberStyles.Any;
                                if (ExponentHelper.IsExponentialFormat(rawVal))
                                {
                                    style = NumberStyles.Float;
                                }

                                // If it is an exponent
                                if (decimal.TryParse(rawVal, style, CultureInfo.InvariantCulture,
                                    out var val))
                                {
                                    if (val > 0)
                                    {
                                        // Update it
                                        _currencyPairComponentService.UpdatePairValue(component.Id, val);
                                    }
                                }
                            }
                            else
                            {
                                // Invalid
                                return false;
                            }
                        }
                    }
                }
                // iterate JValue like a JObject
                else if (token is JValue)
                {
                    // Pump in the object
                    JObject obj = token.ToObject<JObject>();

                    // Is it the last?
                    if (comArrEl != last)
                    {
                        // let's work it out
                        // update the token
                        token = obj.SelectToken(comArrEl);
                    }
                    // Yes its the last
                    else
                    {
                        var rawData = (string) obj.SelectToken(component.QueryComponent);

                        if (rawData != null)
                        {
                            // https://stackoverflow.com/questions/23131414/culture-invariant-decimal-tryparse
                            var style = NumberStyles.Any;
                            if (ExponentHelper.IsExponentialFormat(rawData))
                            {
                                style = NumberStyles.Float;
                            }

                            // If it is an exponent
                            if (decimal.TryParse(rawData, style, CultureInfo.InvariantCulture,
                                out decimal val))
                            {
                                if (val > 0)
                                {
                                    // Update it
                                    _currencyPairComponentService.UpdatePairValue(component.Id, val);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                // Something bad happened
                return false;
            }
        }
    }

    return false;
}

What type of data input works?

well, the 'token' property can be this

{
  "?xml": {
    "@version": "1.0",
    "@encoding": "UTF-8"
  },
  "gesmes:Envelope": {
    "@xmlns:gesmes": "http://www.gesmes.org/xml/2002-08-01",
    "@xmlns": "http://www.ecb.int/vocabulary/2002-08-01/eurofxref",
    "gesmes:subject": "Reference rates",
    "gesmes:Sender": {
      "gesmes:name": "European Central Bank"
    },
    "Cube": {
      "Cube": {
        "@time": "2018-12-06",
        "Cube": [
          {
            "@currency": "USD",
            "@rate": "1.1351"
          },
          {
            "@currency": "JPY",
            "@rate": "128.04"
          },
          {
            "@currency": "BGN",
            "@rate": "1.9558"
          },
          {
            "@currency": "CZK",
            "@rate": "25.890"
          },
          {
            "@currency": "DKK",
            "@rate": "7.4635"
          },
          {
            "@currency": "GBP",
            "@rate": "0.88930"
          },
          {
            "@currency": "HUF",
            "@rate": "323.75"
          },
          {
            "@currency": "PLN",
            "@rate": "4.2881"
          },
          {
            "@currency": "RON",
            "@rate": "4.6548"
          },
          {
            "@currency": "SEK",
            "@rate": "10.2355"
          },
          {
            "@currency": "CHF",
            "@rate": "1.1304"
          },
          {
            "@currency": "ISK",
            "@rate": "138.40"
          },
          {
            "@currency": "NOK",
            "@rate": "9.7028"
          },
          {
            "@currency": "HRK",
            "@rate": "7.3965"
          },
          {
            "@currency": "RUB",
            "@rate": "75.9421"
          },
          {
            "@currency": "TRY",
            "@rate": "6.0947"
          },
          {
            "@currency": "AUD",
            "@rate": "1.5745"
          },
          {
            "@currency": "BRL",
            "@rate": "4.4370"
          },
          {
            "@currency": "CAD",
            "@rate": "1.5229"
          },
          {
            "@currency": "CNY",
            "@rate": "7.8239"
          },
          {
            "@currency": "HKD",
            "@rate": "8.8669"
          },
          {
            "@currency": "IDR",
            "@rate": "16481.65"
          },
          {
            "@currency": "ILS",
            "@rate": "4.2367"
          },
          {
            "@currency": "INR",
            "@rate": "80.4950"
          },
          {
            "@currency": "KRW",
            "@rate": "1273.03"
          },
          {
            "@currency": "MXN",
            "@rate": "23.3643"
          },
          {
            "@currency": "MYR",
            "@rate": "4.7271"
          },
          {
            "@currency": "NZD",
            "@rate": "1.6517"
          },
          {
            "@currency": "PHP",
            "@rate": "60.012"
          },
          {
            "@currency": "SGD",
            "@rate": "1.5560"
          },
          {
            "@currency": "THB",
            "@rate": "37.282"
          },
          {
            "@currency": "ZAR",
            "@rate": "15.9797"
          }
        ]
      }
    }
  }
}

Update method: need a sample input for line 6?

This will obtain the @rate property.

gesmes:Envelope/Cube/Cube/Cube/0=>@rate

Easier sample:

[
  97.935,
  1745.41815607,
  97.936,
  315.65150703,
  -6.58,
  -0.063,
  97.93,
  664801.20661302,
  105.67,
  96.23
]

Line 6 would be just "0"

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
Nicholas
  • 1,883
  • 21
  • 39