Stanza
Stanza

Reputation: 565

Identifying that a property's value is an array

I have a JSON file:

{  
   "abn":"63119059513",
   "acn":"119059513",
   "business_structure":"Private Company",
   "ngr_number":"1231231",
   "cbh_number":"1231231",
   "main_name":"Brickworks Building Products Pty Ltd",
   "trading_name":"Brickworks",
   "other_trading_names":"Austral Bricks",
   "directors":[  
      {  
         "ID":"12114",
         "ae_forms_filled_in_ID":"22739",
         "name":"John Smith",
         "dob":"1983-10-29",
         "address_line_1":"123 Fake Street",
         "address_line_2":"",
         "address_line_city":"Fakeland",
         "address_line_postcode":"2000",
         "address_line_state":"New South Wales",
         "address_line_country":"Australia",
         "order_extract_id":null,
         "director_found":null,
         "drivers_lic":"",
         "home_mortgage":"",
         "phone":"",
         "mobile":"",
         "director_email":"",
         "director_title":"Mr",
         "director_position":"Director",
         "dir_pdf_url":null
      }
   ],

}

I want to determine if the value of any property has a structure of an array. The best I can come up with so far is:

StreamReader streamrr = new StreamReader("C:\\temp\\agfarm_example_udate.json", Encoding.UTF8);

string JSON = streamrr.ReadToEnd();

JObject CWFile = JObject.Parse(JSON);
foreach (JProperty property in CWFile.Properties())
{
    // Do something

    if (property.Value.ToString().Contains("["))
    {
        // Do something with the array
        JArray items = (JArray)CWFile[property.Name];

        foreach (JObject o in items.Children<JObject>())
        {
            foreach (JProperty p in o.Properties())
            {
               // Do something
            }
        }
    }
}

To determine whether or not a property value has an array, I used the condition:

if (property.Value.ToString().Contains("["))

I'm just wondering if there is a better way of doing this check?

Upvotes: 11

Views: 22728

Answers (2)

dbc
dbc

Reputation: 116991

One way to do this is to check the JToken.Type property. Arrays are of type JTokenType.Array:

if (property.Value.Type == JTokenType.Array)
{
    var items = (JArray)property.Value;

    // Proceed as before.
}

Or, you can just try to cast to JArray:

if (property.Value is JArray)
{
    var items = (JArray)property.Value;

    // Proceed as before.
}

Both are preferable to checking property.Value.ToString().Contains("[") since a nested property might have an array value, thus causing a bracket to appear somewhere in the ToString() return.

If you want to recursively find every property with an array value, you can introduce an extension method:

public static class JsonExtensions
{
    public static IEnumerable<JToken> WalkTokens(this JToken node)
    {
        if (node == null)
            yield break;
        yield return node;
        foreach (var child in node.Children())
            foreach (var childNode in child.WalkTokens())
                yield return childNode;
    }
}

And then do:

var CWFile = JToken.Parse(JSON)
var arrayProperties = CWFile.WalkTokens().OfType<JProperty>().Where(prop => prop.Value.Type == JTokenType.Array);

Upvotes: 17

erevos
erevos

Reputation: 11

    public void Traverse(string name, JToken j)
    {
        foreach (JToken token in j.AsJEnumerable())
            if (token.Type == JTokenType.Object)
            {
                foreach (var pair in token as JObject)                        
                {
                    string name_ = pair.Key;
                    JToken child = pair.Value;
                    Traverse(name, child);
                }
            }
            else if (token.Type == JTokenType.Array) //an array property found 
            {
                foreach (var child in token.Children())
                    Traverse(((JProperty)j).Name, child);
            }
            else if (token.Type == JTokenType.Property)
            {
                var property = token as JProperty; //current level property
                Traverse(name, (JContainer)token);
            }
            else //current level property name & value
            {
                var nm = "";
                var t = "";
                if (j is JProperty)
                {
                    nm = ((JProperty)j).Name;
                    t = Convert.ToString(((JProperty)j).Value);
                }
                t = Convert.ToString(token);
            }
    }

Call:

JSON = JObject.Parse(...);
Traverse("", JSON);

To parse and already parsed text for the same reason is not very wise :

if (property.Value.ToString().Contains("["))

Json structure is simple : objects, arrays, properties, values

http://www.json.org/

So array is a wellknown object for json and we are looking for it :

if (token.Type == JTokenType.Array) //an array property

Upvotes: 0

Related Questions