Help Searching a JsonSlurper list


(Anthony S.) #1

I’m trying to parse out the following json string:

{"cid":"PWER","data":[{"1440023704000":0}],"sid":"123456","units":"kWm","age":142156},{"cid":"PWER_GAC","data":[{"1440165858000":2202}],"sid":"123456","units":null,"age":2}

Here is the code snip i’m using:

def respData = summaryResp.data.text
log.debug "Summary Reading Result: $summaryResp.data"
log.debug "Summary text: ${respData}"

def list = new JsonSlurper().parseText(respData)
def cids = list.cid
log.debug "Cid List: $cids"
log.debug "List Values: $list"

if(list.cid == "PWER_GAC" && list.age <= 10)
    clampType = "PWER_GAC"
    log.debug "PWER_GAC Data ${list.data}"
    log.debug "PWER_GAC TimeStamp: ${list.data}"
    log.debug "PWER_GAC Reading: ${list.data}"
    
if(list.cid == "PWER" && list.age <= 10)
    clampType = "PWER"
    log.debug "PWER Data ${list.data}"
    log.debug "PWER TimeStamp: ${list.data}"
    log.debug "PWER Reading: ${list.data}"

I need to find the cid value where the age is less than 10 seconds. Then split the value of the data
"data":[{"1440165858000":2202}] field into two strings (First is timestamp and second is the energy reading)

Here is the Logs…

debug PWER Reading: [[1440181448000:1428]]
debug PWER TimeStamp: [[1440023704000:0]]
debug PWER Data [[[1440023704000:0]], [[1440181448000:1428]]]
debug PWER_GAC Reading: [[1440181448000:1428]]
debug PWER_GAC TimeStamp: [[1440023704000:0]]
debug PWER_GAC Data [[[1440023704000:0]], [[1440181448000:1428]]]
debug List Values: [[sid:123456, age:157749, data:[[1440023704000:0]], cid:PWER, units:kWm], [sid:123456, age:5,  data:[[1440181448000:1428]], cid:PWER_GAC, units:null]]
debug Cid List: [PWER, PWER_GAC]
debug Summary text: [{"cid":"PWER","data":[{"1440023704000":0}],"sid":"123456","units":"kWm","age":157749},{"cid":"PWER_GAC","data":[{"1440181448000":1428}],"sid":"123456","units":null,"age":5}]

Read all element of JSon httpPOST
(John S) #2

so list is the array of records
iterate the list, find the record your want. I find when I need to figure out pure Groovy code, playing around in groovyConsole is way easier than using the IDE. If you install groovy on your Mac/PC/Linux box, you usually get (or can also install) the groovyConsole. Anyway, in pure groovy this is a sample solution:

groovy>     def test = '[{"cid":"PWER","data":[{"1440023704000":0}],"sid":"123456","units":"kWm","age":142156},{"cid":"PWER_GAC","data":[{"1440165858000":2202}],"sid":"123456","units":null,"age":2}]' 
groovy>     def list = new groovy.json.JsonSlurper().parseText(test) 
groovy>      
groovy>     def cidval = "" 
groovy>     for (rec in list) { 
groovy>        if ( (rec.age) && ( rec.age < 10) ) { 
groovy>              cidval = rec.cid 
groovy>              break 
groovy>       } 
groovy>     } 
groovy>      
groovy>     println cidval 
groovy>     
 
PWER_GAC

If we convert that into “SmartApp” groovy, we can write it as

def respData = summaryResp.data.text
def list = new JsonSlurper().parseText(respData)
def cidval = "" // or whatever default you want
for (rec in list) {
   // if the record has an age, and the age is less than 10, we're done!
   if ( (rec.age) && ( rec.age < 10) ) {
         cidval = rec.cid
         break
  }
}
// cidval is either "" or the desired value 
log.debug cidval

(Anthony S.) #3

Thanks John.

LOL. I should have known this I have been coding for last few years. I tried to over complicate it and missed the obvious. I will give this a try


(Anthony S.) #4

So now I’m having another issue
I’m trying to split the value returned from the data and It works in groovyConsole:

groovy>     def test = "[[1440304512000:1303]]" 
groovy>      
groovy>     //String[] data = test.replaceAll("\\[|\\{", "").replaceAll("\\]|\\}","").split(":"); 
groovy>     String[] data = test.replaceAll("\\[|\\{|\\]|\\}", "").split(":"); 
groovy>    
groovy>     println "TimeStamp: " + data[0]   
groovy>     println "Reading: " + data[1] 
groovy>      
 
TimeStamp: 1440304512000
Reading: 1303

This Smart App code returns:

def cidVal = ""
def cidData = ""
def cidUnits = ""
    	
def respData = summaryResp.data.text
log.debug "Summary Reading: $respData"
		
def list = new JsonSlurper().parseText(respData)
for (rec in list) {
      // if the record has an age, and the age is less than 10, we're done!
  if ( (rec.age) && ( rec.age < 10) ) {
           cidVal = rec.cid
           log.debug "Cid Value: $cidVal"
           cidData = rec.data
           log.debug "Cid Data: $cidData"
           cidUnits = rec.units
           log.debug "Cid Units: $cidUnits"
                
           break
       }
}
        
    String[] data = rec.data.replaceAll("\\[|\\{|\\]|\\}", "").split(":");
    log.debug "Datas: $data"
    log.debug "TimeStamp: " + data[0]  
    log.debug "Reading: " + data[1]

Log Output:

groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.replaceAll() is applicable for argument types: (java.lang.String, java.lang.String) values: [\[|\{, ] @ line 243

(John S) #5

I think you want

def data = cidData.replaceAll("\\[|\\{|\\]|\\}", "").split(":");

It’s still not going to work as you expect. The error message ( No signature of method: java.util.ArrayList.replaceAll() ) is because you’ve still got an array, not a string, in that field. When the json parser parses the original string, it parses all of it, all the way down. So the data field is an array:

"data":[{"1440165858000":2202}]

with one element (data[0]) which is itself a json object

{"1440165858000":2202}

That object has a single key of “1440165858000” and that key’s value is 2202

So if you want to fetch all the details of that, you would have to iterate over the keys/values - you end up with this:

def list = new JsonSlurper().parseText(test) 

def cidval = "" 
def ciddata = [{}]

for (rec in list) { 
    if ( (rec.age) && ( rec.age < 10) ) { 
        cidval = rec.cid 
        ciddata = rec.data
        break 
     } 
}
 
// look at all of them
for (report in ciddata) {
    for ( item in report) {
        log.debug "Timestamp: " + item.key
        log.debug "Value: " + item.value
    }
}
  
// since we know there is only one, just use it
def timestamp
def reading
for (item in ciddata[0]) {
     timestamp =  item.key
    reading = item.value
}

// you have the values now
log.debug "Timestamp: " + timestamp
log.debug "Value: " + reading

(Anthony S.) #6

Thanks for all of your help. I was able to make it work with your examples. It’s very much appreciated


(John S) #7

Glad to help! I live in json (so it seems) and have to do this kinda stuff in java/javascript/c#/groovy/omgwhatlanguagenext all the time, so I’m used to making the same kinds of mistakes. json->text->json or worse json (in lang X) -> text (over teh internets) -> json (in lang Y) is just a mess, usually.


#8

Hello John,

I know this is an older post but hopefully you can help me out.

I am trying to do something similar but I cannot figure it out to get the data out of the string.

I am trying to get the values for :mVolts, mCurrent, mKW,and mKWh. They are separated by mId.

Here is my code:

def tlist = ‘[ {“SystemData”: [{“tsKwh”: 0,“tsKvarh”: 0,“pCntIp0”: 111,“pCntIp1”: 106,“twPulse”: 0,“tgPulse”: 0,“vAlarm”: 0}]},{“MeterData”: [{“mId”: 1,“mExist”: 1,“mVolts”: 118.53,“mCurrent”: 13.14,“mKW”: 0.85,“mKWh”: 780.44,“mAlrm”: 0},{“mId”: 2,“mExist”: 1,“mVolts”: 668.53,“mCurrent”: 13.14,“mKW”: 0.85,“mKWh”: 780.44,“mAlrm”: 0}]}]’
def list = new groovy.json.JsonSlurper().parseText(tlist)

def mId1

for ( rec in list){

 if ((rec.SystemData.MeterData.mId) && (rec.SystemData.MeterData.mId =1) )   {
    mone=rec.SystemData.MeterData.mId.mVolts
     break
     }
     }      

println mId1

Here is the error I am getting in Groovy console:

Exception thrown

java.lang.NullPointerException: Cannot get property ‘MeterData’ on null object

at ConsoleScript203.run(ConsoleScript203:8)

(Anthony S.) #9

Is tlist the actual JSON data you are trying to parse?


#10

Yes that is correct.


(Anthony S.) #11

JSON isn’t encapsulated in [ ]


(Anthony S.) #12

I almost have the structure for you


(Anthony S.) #13

String tlist = "[{"SystemData": [{"tsKwh": 0,"tsKvarh": 0,"pCntIp0": 111,"pCntIp1": 106,"twPulse": 0,"tgPulse": 0,"vAlarm": 0}]},{"MeterData": [{"mId": 1,"mExist": 1,"mVolts": 118.53, "mCurrent": 13.14,"mKW": 0.85, "mKWh": 780.44, "mAlrm": 0}, {"mId": 2,"mExist": 1,"mVolts": 668.53,"mCurrent": 13.14,"mKW": 0.85,"mKWh": 780.44,"mAlrm": 0}]}]"

def mId1 = null
println "data[0]: ${data[0]}"
println "data[1]: ${data[1]}"
//println "${data[0].SystemData}
//mId1 = rec.SystemData.MeterData.mId.mVolts
println "mId1: $mId1"

Output:
data[0]: [SystemData:[[pCntIp0:111, pCntIp1:106, tgPulse:0, tsKvarh:0, tsKwh:0, twPulse:0, vAlarm:0]]]
data[1]: [MeterData:[[mAlrm:0, mCurrent:13.14, mExist:1, mId:1, mKW:0.85, mKWh:780.44, mVolts:118.53]
[mAlrm:0, mCurrent:13.14, mExist:1, mId:2, mKW:0.85, mKWh:780.44, mVolts:668.53]]]
mId1: null

So the data structure is very odd


#14

@tonesto7 you are right it is a weird format for a JSON string. I went a different direction, not using jsonslurper.

Basically I just looked at the array and pointed at each value using getAt(0).


(Anthony S.) #15

Glad you sorted it out