[SOLVED] JSON vs. REGEX

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)

Thanks a lot for your patience.
Including the ´´´ at the end?

No, that’s an artefact from the browser, I’ll remove it

it works!
Thanks a lot!

Coolio, please mark the thread as solved
The issue was the value “null” in the json. Javascript was also treating it as null value
You can now create as many JS transforms you require to extract data from this json.
BUT there are other users that have volvos on the forum that who may have come up with better solutions.
Good luck

Hi,

Again, thanks for your help.
I know about the other Volvo users, but did not get a response yet about a request sharing their items and such.
And I am a little impatient after getting my new volvo :wink:

Please mark the thread as solved, Thanks

Hi. I know you got your issue resolved, but I wanted to share a few tips on using regular expressions that make them a bit less cumbersome.

  1. In my experience regular expression engines generally only match a single line by default but then you can pass a flag to use a multi-line match. I haven’t looked at the openhab one, but it would be good to confirm whether or not you need to pass a flag by checking the docs.

  2. The use of “." as you have it can cause some unexpected results because the "” repeat operator is as greedy as possible, meaning it matches as many characters as it can while still completing the match of possible. So, if there happened to be another instance of “heading” later in the file, one of your “." instances would likely match a whole bunch of lines up until right before the second “heading”. The way to avoid the greedy behavior is to use a “?” after a repeat operator ("?" or “+”). Something like "\s.?,” would match the very first comma if possible while still getting a match of the whole expression, otherwise it would match more if a later “heading” causes a match but the first one didn’t for some reason.

  3. If possible, it’s good to use repeat operators to simplify the equation. Instead of having “\s.,\s.,\s.," in your expression, which could break if the json changes format in some way or places heading first instead of later in the list, I would include this: (\s”\w+"\s*:\s*"?."?\s,\s*)*

In that example, each \s* matches from 0 to many space characters. This is more robust because the number of spaces can change without affecting the results of your regular expression. The () group the whole thing together and the star after the closing paren repeats the group from 0 to many times, so that takes care of the situation where heading becomes the first attribute in the set. The "? That appears twice in the latter part of the expression optionally matches a quote but doesn’t have to. After a normal character (not a repeat operator like above) the “?” is a 0 or 1 time match operator. Note that the whole expression I entered may need additional \ characters inserted when using it in a specific situation like openhab.

  1. Regex tools are your friend. It sounds like you used these already, but if not I often search Google for “online Regex” and there are various tools you can use that allow you to enter a Regex and a target string and see how it matches or why it doesn’t. Regexes can get a bit hairy and computers are much better at parsing Regex than humans are.

I know you got your problem solved, but I figured this would help in your future use of regular expressions as well as be helpful for anybody else who happens to come along and view this thread later.

Thank you - it’s a while ago but I still struggle with one or the other REGEX handling.
My main issue is, that the results in OH’s REGEX do not reflect the results from online testers.
That’s the most frustrating part and costs a lot of time.
However, I will think about your suggestions above and see if I can get the right impulse from it.

My Problem looks so easy and all my tests on the online tester regex101 did work well.
But it’s not in OH:
Input:

InputCH1=OFF
InputCH2=ON
InputCH3=ON
InputVCH1=ON
InputVCH2=DEACTIVATED
InputVCH3=DEACTIVATED
OutputCH1=OFF
OutputCH2=OFF
OutputWired=OFF
AlarmPowerFail=OFF
AlarmLowBattery=OFF
AlarmFault=OFF
AlarmFire=OFF
AlarmTechnical=OFF
AlarmBurglary=OFF
AlarmEntry=OFF
AlarmPanic=OFF

In most cases the entire string is returned (including newline and all the rest after the match)
I tried:

REGEX(AlarmBurglary=(.*)\n)
REGEX(AlarmBurglary=(.*)[\\s].*)
REGEX(.*AlarmBurglary=(.*)\n.*)
REGEX(.*InputCH1=(.*).*)
REGEX(.*AlarmBurglary=(.?)\n.*)
REGEX(AlarmBurglary=([A-Z]{2,3})\n.*)

I also check the docs and they mention specifically regex101.

EDIT:
Why is OH working so differently than the regex on REGEX101?
I understand that specific characters need to be escaped (in the “STRING”) like mentioned in the docs, but with these results I don’t get it.

All of these work fine on regex101 returning only “ON”
REGEX(.*InputCH2=(.*))
returns in OH: ON including the rest of the string InputCH3…
same result with
REGEX(.*InputCH2=(.*).*)

REGEX(.*InputCH2=(..))
returns nothing (empty string), where I expected the next 2 characters after the “=”
Again: on regex101 it works fine.

I got a solution:

REGEX(.*InputCH3=(.*)\\n.*\\n.*
Means:
For each new line after the interestin part of the string there needs to be a \n.*
:smiley: