[SOLVED] Loop through an array BUT test value is read as NULL when used in an expression

To briefly summarize, I’m sending an Http request to get bus time arrivals. I am using XSLT to transform the data into the next 1-3 arrival times (it can vary depending on what the http receives).
In the rules, I pass the value, clean up up the string, and split the string so that I now have an array with 1-3 elements containing the next three bustime arrivals (in minutes i.e 13.4). The For loop is so that I can loop through each of the elements and check if any of them are greater than or equal to 9 minutes. As you can see in the logging, openhab seems to read it as a null value, but ONLY when I attempt to use it in an expression ( + - < > …etc).

What am I missing?!

My problem:

06:22:53.579 [ERROR] [.script.engine.ScriptExecutionThread] - Error during the execution of rule 'Calculate CTA': An error occured during the script execution: Could not invoke method: org.eclipse.smarthome.model.script.lib.NumberExtensions.operator_greaterEqualsThan(java.lang.Number,java.lang.Number) on instance: null
Rules : 
import org.openhab.core.types.Command
import org.openhab.core.types.*
import org.openhab.core.items.GenericItem
import org.openhab.core.library.types.DecimalType
import java.util.Set
import java.lang.Math
import org.openhab.core.library.types.DecimalType

rule "Calculate CTA"
when
        Item BusX_Dir received update
then
        val key = "#$#"
        var rt = 99
        var stpid = 9999
        var base = "http://www.somewebsite.com?key="
        var vHTTP = base + key + "&rt=" + rt + "&stpid=" + stpid
        val value = sendHttpGetRequest(vHTTP)
        var vTransform = transform("XSLT","ETA.xsl",value)
        var vTransform1 = vTransform.replace("</:><:>",",")
        var vTransform2 = vTransform1.replace("</:>","")
        var vTransform3 = vTransform2.replace("<:>","")
        val vArray = vTransform3.split(",")
        var vArraySize = vArray.length


        for (Number i: vArray) {
                if(i >= 9) {    // Why is this not going through? Stating a null value, but when removed, it comes out in the log as it should.
                        logInfo("cta","Minutes Until arrival {}", i)
                }
        }
end

SIDENOTE

for (Number i: vArray) {
      logInfo("cta","Minutes Until arrival {}", i)
      }

OUTPUTS:

06:25:56.129 [INFO ] [g.eclipse.smarthome.model.script.cta] - Minutes Until arrival 14.0666

First, it is easier to read code, particularly longer chunks of code, if you use the forum’s code formatting. There are several ways but the easiest is to put three backticks (i.e. `) on the line before and the line after.

```
your code
```

When you parse XML and do the XSLT transforms you get a String. You can’t just treat a String like a Number, you actually have to parse the String into a Number.

Unfortunately, the Rules DSL treats these sorts of errors as a NullPointerException rather than something more informative.

One challenge with the Rules DSL though is that it is pretty lax when it comes to data type where it can manage to figure out what to do. This is why your log statement works. Both a Number and a String can be printed like that so it happily ignores the incorrect Number i: vArray which should be String i: vArray. However, it doesn’t make sense to use the >= operator on a String so it fails.

What you need to do is convert the String to a Number before the if statement.

import java.math.BigDecimal

...
    for(String i: vArray){
        val num = new BigDecimal(i)
        if(num >= 9) {
            logInfo(...
    }
1 Like

@rlkoshak

Thanks for the tip! I’ve edited my original post so that is is easier to read.

That did it! I knew it was being read as a string, I honestly that the act of writing
for(Number i : vArray) did the conversion from string to number.

Running the code it seems to be doing well except… for one small thing. It doesn’t seem to loop through all the iterations.

for (String i : vArray) {                                                                                            
                val num = new BigDecimal(i)                                                                                 
                logInfo("cta","Bus @ {}", i)      // Just to make sure it is going through each element                                                                           
                if(num >= 9) {                                                                                              
                        logInfo("cta","This bus is more than 9 minutes.  {}", num)                                          
                }                                                                                                           
        } 

The result:

15:19:51.935 [INFO ] [marthome.event.ItemStateChangedEvent] - WesternWarren_South changed from <:>8.15</:><:>22.15</:>      
 to <:>8.15</:><:>21.15</:>               // So here I see the value updating. 2 elements.                                                                                   
                                                                                                                            
15:19:52.238 [INFO ] [g.eclipse.smarthome.model.script.cta] - Bus @ 8.133333333333333                                       
15:19:52.257 [ERROR] [.script.engine.ScriptExecutionThread] - Error during the execution of rule 'Calculate CTA': null   //  It looks like it loops through the first element but not the second one. I've also gotten 3 elements where the 2nd element met the requirement for the second log, it shows up but then on the third element, I get the NULL execution rule. 

This might be caused by the number being extracted in the XSLT not being a valid number (e.g. leading or trailing white-space).

It doesn’t appear that way but it is all I can think of right now that would cause problems.

Try moving the logInfo to the top of the for loop so it logs i before it tries to convert it to a BigDecimal to see if the error is being generated during that line. Also, try wrapping the value printed in some way to see if there are leading or trailing white space.

logInfo("cta", "Bus @ [" + i + "]")

Interesting,

I ran your suggesting and this is what comes up. 4 elements, last one errors out.

It looks like it there is a white space at the end of the last element. Is there a trim function available? Or is it possible to modify my xslt template to eliminate white spaces on the output?
LOG:

16:36:48.694 [INFO ] [marthome.event.ItemStateChangedEvent] - WesternWarren_South changed from <:>6.216666666666667</:><:>16
.216666666666665</:><:>21.216666666666665</:>                                                                               
 to <:>6.2</:><:>15.2</:><:>21.2</:><:>28.2</:>                                                                             
                                                                                                                            
16:36:48.994 [INFO ] [g.eclipse.smarthome.model.script.cta] - Value before convert [6.2]                                    
16:36:49.013 [INFO ] [g.eclipse.smarthome.model.script.cta] - Value after convert [6.2]                                     
16:36:49.028 [INFO ] [g.eclipse.smarthome.model.script.cta] - Value before convert [15.2]                                   
16:36:49.039 [INFO ] [g.eclipse.smarthome.model.script.cta] - Value after convert [15.2]                                    
16:36:49.049 [INFO ] [g.eclipse.smarthome.model.script.cta] - This bus is more than 9 minutes.  15.2                        
16:36:49.060 [INFO ] [g.eclipse.smarthome.model.script.cta] - Value before convert [21.2]                                   
16:36:49.069 [INFO ] [g.eclipse.smarthome.model.script.cta] - Value after convert [21.2]                                    
16:36:49.077 [INFO ] [g.eclipse.smarthome.model.script.cta] - This bus is more than 9 minutes.  21.2                        
16:36:49.091 [INFO ] [g.eclipse.smarthome.model.script.cta] - Value before convert [28.2                                    
]   //  <------  white space??                                                                                                
16:36:49.097 [ERROR] [.script.engine.ScriptExecutionThread] - Error during the execution of rule 'Calculate CTA': null    

Rules:

for (String i: vArray) {                                                                                            
                logInfo("cta","Value before convert [" + i + "]")                                                           
                                                                                                                            
                val num = new BigDecimal(i)                                                                                 
                                                                                                                            
                logInfo("cta","Value after convert [" + num + "]")                                                          
                                                                                                                            
                if(num >= 9) {                                                                                              
                        logInfo("cta","This bus is more than 9 minutes.  {}", num)                                          
                }                                                                                                           
        }                               

Yep.

i.trim

@rlkoshak

That did it!!! Thank you!!!

Below is my final solution. I am able to loop through each element in the array and check each value against a condition.

for (String i: vArray) {                   // vArray contains a list of ETA's in a String                                                                         
                var x = i.trim               // removes white spaces from the string element                                                                               
                logInfo("cta","Value before convert [" + x + "]")    // checks value before converting                                                       
                                                                                                                            
                val num = new BigDecimal(x)  //Converts string value into an integer                                                                               
                                                                                                                            
                logInfo("cta","Value after convert [" + num + "]") //checks integer value before condition                                                         
                                                                                                                            
                if(num >= 9) {                          // Checks if value in element is true                                            
                        logInfo("cta","This bus is more than 9 minutes.  {}", num)                                          
                }                                                                                                           
        }