JSON Parsing Question

Hello everyone,

I have a large JSON-Item and I can parse it when I know in advance how many “child” levels i have. The issue is when I have a JSONItem result and the number of "Child"s are variable. What is the best way to dive down into the children to figure out the .Count for each JSONItem Array? Also how to know when all new levels have been found.

Hopefully this makes sense :slight_smile: Thank you.

I am attaching a large JSONITEM Result.

{"jsonrpc": "2.0", "result": [{"interfaces": {"Management1": {"lastStatusChangeTimestamp": 1413038310.17, "name": "Management1", "duplex": "duplexFull", "autoNegotiate": "success", "burnedInAddress": "08:00:27:6f:72:f8", "mtu": 1500, "hardware": "ethernet", "interfaceStatus": "connected", "bandwidth": 100000000, "forwardingModel": "routed", "lineProtocolStatus": "up", "interfaceCounters": {"outBroadcastPkts": 0, "outUcastPkts": 0, "totalOutErrors": 0, "inMulticastPkts": 0, "counterRefreshTime": 1413043803.92, "inBroadcastPkts": 0, "outputErrorsDetail": {"deferredTransmissions": 0, "txPause": 0, "collisions": 0, "lateCollisions": 0}, "outOctets": 0, "outDiscards": 0, "inOctets": 0, "inUcastPkts": 0, "inputErrorsDetail": {"runtFrames": 0, "rxPause": 0, "fcsErrors": 0, "alignmentErrors": 0, "giantFrames": 0, "symbolErrors": 0}, "linkStatusChanges": 3, "outMulticastPkts": 0, "totalInErrors": 0, "inDiscards": 0}, "interfaceStatistics": {"inBitsRate": 0.0, "outBitsRate": 0.0, "inPktsRate": 0.0, "updateInterval": 300.0, "outPktsRate": 0.0}, "interfaceAddress": [{"secondaryIpsOrderedList": [], "broadcastAddress": "255.255.255.255", "secondaryIps": {}, "primaryIp": {"maskLen": 24, "address": "192.168.1.11"}}], "physicalAddress": "08:00:27:6f:72:f8", "description": ""}, "Ethernet2": {"lastStatusChangeTimestamp": 1413038312.3, "name": "Ethernet2", "duplex": "duplexFull", "autoNegotiate": "unknown", "burnedInAddress": "08:00:27:dd:2b:2e", "mtu": 9214, "hardware": "ethernet", "interfaceStatus": "connected", "bandwidth": 10000000000, "forwardingModel": "bridged", "lineProtocolStatus": "up", "interfaceCounters": {"outBroadcastPkts": 0, "outUcastPkts": 0, "totalOutErrors": 0, "inMulticastPkts": 0, "counterRefreshTime": 1413043803.9, "inBroadcastPkts": 0, "outputErrorsDetail": {"deferredTransmissions": 0, "txPause": 0, "collisions": 0, "lateCollisions": 0}, "outOctets": 364478, "outDiscards": 0, "inOctets": 0, "inUcastPkts": 0, "lastClear": 1413038254.86, "inputErrorsDetail": {"runtFrames": 0, "rxPause": 0, "fcsErrors": 0, "alignmentErrors": 0, "giantFrames": 0, "symbolErrors": 0}, "linkStatusChanges": 1, "outMulticastPkts": 2890, "totalInErrors": 0, "inDiscards": 0}, "interfaceStatistics": {"inBitsRate": 0.0, "outBitsRate": 0.0, "inPktsRate": 0.0, "updateInterval": 300.0, "outPktsRate": 0.0}, "interfaceAddress": [], "physicalAddress": "08:00:27:dd:2b:2e", "description": ""}, "Ethernet3": {"lastStatusChangeTimestamp": 1413038312.3, "name": "Ethernet3", "duplex": "duplexFull", "autoNegotiate": "unknown", "burnedInAddress": "08:00:27:d6:ee:47", "mtu": 9214, "hardware": "ethernet", "interfaceStatus": "connected", "bandwidth": 10000000000, "forwardingModel": "bridged", "lineProtocolStatus": "up", "interfaceCounters": {"outBroadcastPkts": 0, "outUcastPkts": 0, "totalOutErrors": 0, "inMulticastPkts": 0, "counterRefreshTime": 1413043803.91, "inBroadcastPkts": 0, "outputErrorsDetail": {"deferredTransmissions": 0, "txPause": 0, "collisions": 0, "lateCollisions": 0}, "outOctets": 364478, "outDiscards": 0, "inOctets": 0, "inUcastPkts": 0, "inputErrorsDetail": {"runtFrames": 0, "rxPause": 0, "fcsErrors": 0, "alignmentErrors": 0, "giantFrames": 0, "symbolErrors": 0}, "linkStatusChanges": 1, "outMulticastPkts": 2890, "totalInErrors": 0, "inDiscards": 0}, "interfaceStatistics": {"inBitsRate": 0.0, "outBitsRate": 0.0, "inPktsRate": 0.0, "updateInterval": 300.0, "outPktsRate": 0.0}, "interfaceAddress": [], "physicalAddress": "08:00:27:d6:ee:47", "description": ""}, "Ethernet1": {"lastStatusChangeTimestamp": 1413038312.3, "name": "Ethernet1", "duplex": "duplexFull", "autoNegotiate": "unknown", "burnedInAddress": "08:00:27:9f:81:a1", "mtu": 9214, "hardware": "ethernet", "interfaceStatus": "connected", "bandwidth": 10000000000, "forwardingModel": "bridged", "lineProtocolStatus": "up", "interfaceCounters": {"outBroadcastPkts": 0, "outUcastPkts": 0, "totalOutErrors": 0, "inMulticastPkts": 0, "counterRefreshTime": 1413043803.89, "inBroadcastPkts": 0, "outputErrorsDetail": {"deferredTransmissions": 0, "txPause": 0, "collisions": 0, "lateCollisions": 0}, "outOctets": 364478, "outDiscards": 0, "inOctets": 0, "inUcastPkts": 0, "inputErrorsDetail": {"runtFrames": 0, "rxPause": 0, "fcsErrors": 0, "alignmentErrors": 0, "giantFrames": 0, "symbolErrors": 0}, "linkStatusChanges": 1, "outMulticastPkts": 2890, "totalInErrors": 0, "inDiscards": 0}, "interfaceStatistics": {"inBitsRate": 0.0, "outBitsRate": 0.0, "inPktsRate": 0.0, "updateInterval": 300.0, "outPktsRate": 0.0}, "interfaceAddress": [], "physicalAddress": "08:00:27:9f:81:a1", "description": ""}}}], "id": "Arista eAPI Tool"}

Walking a tree structure is easily accomplished using recursion. The real question is, what do you need to do with the results?

I am putting my results into a dictionary. The recursion is where I am stuck a bit. Any help on the recursion code would be very much appreciated. Thanks Tim!!

What information are you putting in the dictionary? I presume you want to get at the 4 interfaces and store information for each one. How do you want to handle the nested children? Do you want to flatten the structure? Do you intend to get a dictionary of dictionaries, each of which represents an interface and contains the key/value pairs of all the leaf nodes?

I want to preserve the structure and pull each “Key” with associated value. I guess in a sense it will be flattened from the directory perspective, but I struggle on how to check for the levels of children for recursive searching dynamically. Thanks again Tim!!

I just don’t have a great way to dynamically test for additional children especially when they are a combination of Arrays and Objects in my JSON output. Some JSON outputs I have 6-7 child deep in some case. I am trying but still can’t find the right combination of JSONItem code.

Any help would be very much appreciated.

Have you looked at the example (Examples\Communication\Internet\JSON Example). The Method SHowJSONObject is a good place to start.

HTH

Wayne

To walk the JSONItem, try something like this (untested):

Function JSONToDictionary(data As JSONItem) As Dictionary
  dim r as new Dictionary
  
  dim names() as string = data.Names
  for each name as string in names
    
    dim value as Variant = data.Value( name )
    if value IsA JSONItem then
      
      dim j as JSONItem = JSONItem( value )
      if j.IsArray then
        r.Value( name ) = JSONToArray( j )
      else
        r.Value( name ) = JSONToDictionary( j )
      end if
      
    else
      
      r.Value( name ) = value
      
    end if
    
  next
  
  return r
End Function

Function JSONToArray(data As JSONItem) As Variant()
  dim r() as Variant
  
  dim ub as integer = data.Count - 1
  for i as integer = 0 to ub
    dim value as Variant = data( i )
    
    if value IsA JSONItem then
      
      dim j as JSONItem = JSONItem( value )
      if j.IsArray then
        r.Append JSONToArray( j )
      else
        r.Append JSONToDictionary( j )
      end if
      
    else
      
      r.Append value
      
    end if
    
  next i
  
  return r
  
End Function

To start, you just have to determine if your initial JSONItem is an array or object, and call the right function.

That’s close. The problem is that names() doesn’t return a name for an array, so your code will skip them. I finally worked this out, which flattens the structure. Your JSONtoArray is probably a better idea.

Sub getvalues(d as dictionary, json as JSONItem)
  dim name as string
  dim value as variant
  dim i as integer
  
  for i = 0 to json.count-1
    name = json.name(i)
    if name = "" then
      // array, recurse on child
      getvalues(d, json.child(i))
    else
      value = json.lookup(name, "")
      if value isa JSONItem then
        // recurse on value
        getvalues(d, value)
      else
        // leaf node, save it in the dictionary
        d.value(name) = value
      end
    end
  next
  
End Sub

The initial call is from a button action event:

  dim json, result as JSONItem
  dim interfaces, d as dictionary
  dim i as integer
  dim s as string
  
  json = new JSONItem
  json.load(jsontext)
  
  result = json.child("result").child(0).value("interfaces")
  
  interfaces= new dictionary
  for i = 0 to result.count-1
    d = new dictionary
    s = result.name(i)
    getvalues(d, result.value(s))
    interfaces.value(s) = d
  next

jsontext is your json copied into a constant. You can see that I’m making assumptions about how to get to the starting point of the recursion. I must admit that I’m new to JSONitem, and it seems pretty quirky to me right now.

I think you missed my comment below the code, Tim. :slight_smile:

[quote=134994:@Wayne Golding]Have you looked at the example (Examples\Communication\Internet\JSON Example). The Method SHowJSONObject is a good place to start.

HTH

Wayne[/quote]
I did thanks Wayne! I have also been using JSON for a while, but I never had to dynamically walk the children before.

Thanks!!

Tim/Kem both guys thank you very much for snippets! i will dive into them now.

Thank you!

Tim/Kem,

i am working on your code snippet now into my app. If i wanted to recurse at a higher point – say the “result” child I assume (i havent tested quite yet) that I can use:
result = json.child(“result”)

intead of:
result = json.child(“result”).child(0).value(“interfaces”)

Yes, Tim I am with you as the implementation of JSONitem has me a bit of keel :wink:

Thank you again guys.

That should work using Kem’s code.

Kem thank you as your code was exactly what I needed !! I am performing a JSONITEM.IsArray and then deciding whether to choose the JSONtoArray or JSONtoDictionary as the starting point. Thank you once again!!!

I walk with my kid regularly, although I have to say he is more dynamic than me :wink:

Kind of makes one wish there was something like XQL for JSON :slight_smile:

what is XQL?

Xml Query Language so you can actual write “queries” against an XML document and return at a without having to walk through all its children like this :slight_smile:

Think “sql for XML” kind of

Very handy stuff

http://documentation.xojo.com/index.php/XMLNode.XQL

I think I was good at JSON/XML :slight_smile: :slight_smile: THANKS NORMAN! :slight_smile: :slight_smile: