[SOLVED] JSON vs. REGEX

I have a json response which looks like:

{
    "tid": "volvo",
    "lat": xxx,
    "_type": "location",
    "t": "p",
    "_vehicle": {
        "ERS": {
            "engineStartWarning": "None",
            "timestamp": "2018-05-11T05:22:53+00:00",
            "status": "off",
            "engineStartWarningTimestamp": "2018-05-11T05:22:53+00:00"
        },
        "VIN": "xxx",
        "assistanceCallSupported": true,
        "averageFuelConsumption": 82.0,
        "averageFuelConsumptionTimestamp": "2018-05-11T05:24:26+00:00",
        "averageSpeed": 74,
        "averageSpeedTimestamp": "2018-05-11T05:24:26+00:00",
        "bCallAssistanceNumber": "xxx",
        "brakeFluid": "Normal",
        "brakeFluidTimestamp": "2018-05-11T05:24:26+00:00",
        "bulbFailures": [],
        "bulbFailuresTimestamp": "2018-05-11T05:24:26+00:00",
        "calculatedPosition": {
            "longitude": null,
            "speed": null,
            "timestamp": null,
            "heading": null,
            "latitude": null
        },

I would like to extract “heading”

With JSONPATH I used:
val String head = transform("JSONPATH", "$._vehicle.calculatedPosition.heading", json)

However, this returns " null"
I would prefer “null”

I also tried with REGEX:
val String head = transform(“REGEX”, ““calculatedPosition”: {\s.,\s.,\s.,\s.“heading”: (.*),”, json)

Which works in an online REGEX tester, but not in OH:
Configuration model 'car.rules' has errors, therefore ignoring it: [63,55]: Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ )

Any suggestion to solve this the best way?
I could use " null" in rules - but that’s kind of “dirty”

var String head = transform("JSONPATH", "$._vehicle.calculatedPosition.heading", json)
head = head.trim()

You can try:

val String head = transform("JSONPATH", "$._vehicle.calculatedPosition.heading", json).trim()

But I am not sure that will work

thanks for your lightning fast response :slight_smile:
I will give it a try.

I actually found another issue.

If the JSON online tester returns >null< openhab stores the entire json string instead of >null<
Is this a known issue or my problem only?

No it’s not a know error, it’s by design
You will probably be better of with a JS transform

Hmmm, ok, thanks.
How would this look like vs the JSONPATH stuff?

Create a file called volvoheading.js in your transform folder
with the following content:

(function(volvo) {
var data = JSON.parse(volvo);
var heading = data._vehicle.calculatedPosition.heading;
return heading.trim();
})(input)

But the value returned is a STRING of value “null” which OH could interpret as NULL. Maybe.
So you could change the value of null in the script to 999, or whatever…

if (heading == "null") {
    return = 999;
}

Your code now becomes:

val Number head = transform(“JS”, "volvoheading.js", json)
1 Like

Thank you so much.

The part of if (heading == "null") { I tried with JSONPATH already, but in that case it did not help.

I will be able to manage this now with JS.
Thanks again!

That’s better:

(function(volvo) {
var data = JSON.parse(volvo);
var heading = data._vehicle.calculatedPosition.heading.trim();
if (heading == "null") {
    return "999";
}
return heading;
})(input)

Is it maybe:

if (heading == “null”) {
heading = 999;
}

like:

(function(volvo) {
var data = JSON.parse(volvo);
var heading = data._vehicle.calculatedPosition.heading.trim();
if (heading == "null") {
    heading = 999;
}
return heading;
})(input)

because I still get :
[ERROR] [ore.transform.actions.Transformation] - Error executing the transformation ‘JS’: An error occurred while executing script.

Don’t you need to use === instead of == when comparing to “null” in java?

Yes that was a bad typo.
I wanted to avoid type conflict
return 999;
Or
heading = “999”;

In this case it the string “null” that we are checking not the null value.

I see that now, my bad!

doesn’t help.
I stll get the entire json response back :frowning:

The regex is embeded in a string thus all stated characters in the error message have to be escaped.
UPDATED:This works for me.

val String head = transform("REGEX", ".*\"heading\".*:\\s(.*),", json)

As for the JSONPATH

rule "Test JSONPATH"
    when
        Item Test_1 received command
    then
        logInfo("JSON Test","Start")
        var json ="{ \"tid\": \"volvo\", \"lat\": xxx, \"_type\": \"location\", \"t\": \"p\", \"_vehicle\": { \"ERS\": { \"engineStartWarning\": \"None\", \"timestamp\": \"2018-05-11T05:22:53+00:00\", \"status\": \"off\", \"engineStartWarningTimestamp\": \"2018-05-11T05:22:53+00:00\" }, \"VIN\": \"xxx\", \"assistanceCallSupported\": true, \"averageFuelConsumption\": 82.0, \"averageFuelConsumptionTimestamp\": \"2018-05-11T05:24:26+00:00\", \"averageSpeed\": 74, \"averageSpeedTimestamp\": \"2018-05-11T05:24:26+00:00\", \"bCallAssistanceNumber\": \"xxx\", \"brakeFluid\": \"Normal\", \"brakeFluidTimestamp\": \"2018-05-11T05:24:26+00:00\", \"bulbFailures\": [], \"bulbFailuresTimestamp\": \"2018-05-11T05:24:26+00:00\", \"calculatedPosition\": { \"longitude\": null, \"speed\": null, \"timestamp\": null, \"heading\": null, \"latitude\": null },}}"
        val result = transform("JSONPATH","$._vehicle.calculatedPosition.heading" ,json)
        logInfo("JSON Test","Result:" + result )
end

Gives me following log:

[INFO ] [pse.smarthome.model.script.JSON Test] - Result:NULL

The postet JSONSTRING is missing two termination brackets }}. but then it returns what you wanted, imho.

You get the whole string back when there is no match in the string for your query.

Thanks - I will play around with your suggestions.

About the two brackets:
I have cut off most of the stuff below to keep it short.
so the original json string was much longer.

I guess the main issue are the newlines in the json string.

Escaping the \s to \s like
val String head1 = transform("REGEX", "\"calculatedPosition\": {\\s.*,\\s.*,\\s.*,\\s.*\"heading\": (.*),", json)

brings:

  `Error during the execution of rule 'request car information': Illegal repetition near index 12 ^"calculatedPosition ": {\s.*,\s.*,\s.*,\s.*"heading": (.*),$`

Isn’t there an option to look for the next “heading” after calculatedPosition regardless of the number of newlines?

I’ll try it in the morning

This is tested and it works

(function(volvo) {
var data = JSON.parse(volvo);
var heading = data._vehicle.calculatedPosition.heading;
if (heading === null) {
    heading = 999;
}
return heading;
})(input)