Search code examples
c#json.netdeserializationcisco

JSON.NET field names with numbers?


I am building an interface to Cisco's ClearAccess application for my employer and I ran into something I found strange and wondered if anyone has suggestions on how to deal with it.

The JSON objects coming back from a simple invocation of "get me all what the customer has on their network" returns a great deal of information which can be easily de-serialized into some plan old objects until I found something like this in the mix:

"Settings.Hosts.35.Active":"false", "Settings.Hosts.17.Active":"false",

Essentially I have a big object that contains elements that follow the naming convention of "Settings.Hosts.xx.Active", "Settings.Hosts.xx.MACAddress", etc.

The documentation is sketchy at best from Cisco (even the object definitions are lacking) so I am left wondering if there's a maximum Host.xx I can safely rely upon or if there's a way I can bend JSON.NET to my will that will force these numbered elements into a collection of (conceptually) "Settings.Host" { "MACAddress": "xx:xx:xx:xx:xx", "Active": "false" }

I've considered using a custom parser (JsonProperty decoration), but I've been rather unsuccessful in finding examples of this to copy.


Solution

  • If you deserialize the JSON string to a JObject, you could manipulate the object to rebuild it.

    e.g.,

    // suppose your string deserialized into this structure
    var obj = new JObject(
        new JProperty("Settings.Hosts.35.Active", false),
        new JProperty("Settings.Hosts.35.MACAddress", "xx:xx:xx:xx:xx"),
        new JProperty("Settings.Hosts.37.Active", false)
    );
    
    var re = new Regex(@"^Settings\.Hosts\.(\d+)\.(\w+)$");
    var newObj = new JObject(
        new JProperty("Settings.Hosts",
            new JObject(
                from prop in obj.Cast<JProperty>()
                let m = re.Match(prop.Name)
                where m.Success
                let id = m.Groups[1].Value
                let propertyName = m.Groups[2].Value
                group new JProperty(propertyName, prop.Value) by id into g
                select new JProperty(g.Key, new JObject(g))
            )
        )
    );
    

    Ideally the code would be in a JsonConverter. This would yield the following JSON strings.

    // before
    {
      "Settings.Hosts.35.Active": false,
      "Settings.Hosts.35.MACAddress": "xx:xx:xx:xx:xx",
      "Settings.Hosts.37.Active": false
    }
    
    // after
    {
      "Settings.Hosts": {
        "35": {
          "Active": false,
          "MACAddress": "xx:xx:xx:xx:xx"
        },
        "37": {
          "Active": false
        }
      }
    }