[Bug] jsonGet's parsing code concatenates list values in jsons

Ok this feels like it should be trivial but i cannot figure out how to do it...
say i've got something like
jsonGet("{item: [1,2,3,4,5]}", 'item')

which outputs [1, 2, 3, 4, 5]. I would like to use index notation to pull out the second element of that array, per Expression Language and Syntax | Ignition User Manual. But
jsonGet("{item: [1,2,3,4,5]}", 'item')[1] gives me an error_TypeConversion for the quality (item.1 doesn't work either)!

XY problem avoidance: i'd like to set an array as a property on a component, and then have another property on that component be that array indexed by a tag -- i.e.

component.customprop=[1, 2, 3, 4, 5]
component.text = toString(component.customprop[{tagPath}])

EDIT: The plot thickens...because { "valueSource": "expr", "expression": "jsonGet(\"{item: [1, 2, 3, 4, 5]}\", \u0027item\u0027)", "dataType": "StringArray", "name": "New Tag", "tagType": "AtomicTag" }

gives me an array of length 1, whos only value is '12345'

Ok, { "valueSource": "expr", "expression": "jsonGet(\u0027{\"item\": [\"1\", \"2\", \"3\", \"4\", \"5\"]}\u0027, \u0027item\u0027)", "dataType": "StringArray", "name": "New Tag", "tagType": "AtomicTag" }

Gives me "1", "2", "3", "4", "5" as a single string value which can't be correct, since it's not even valid json

The actual best way to do what I want to do appears to be runscript which just seems wrong

Why not make your custom prop an actual array ?
Then you can just use {your_prop}[1] to get a specific value.

1 Like

jsonGet("{'item': [1, 2, 3, 4, 5]}", 'item')
returns [1,2,3,4,5]. (Note lack of spaces after commas.)

typeOf(jsonGet("{'item': [1, 2, 3, 4, 5]}", 'item'))
returns "String".

If I create custom property arr =

[
  10,
  11,
  12,
  13,
  14
]

then {view.custom.arr}[2] returns value 12.

It looks to me that the jsonGet function isn't recognising the item list / array.

Update:
This seems overly complicated but...

split(
	replace(
		replace(
			jsonGet("{'item': [11, 12, 13, 14, 15]}", 'item'),
			'[',
			''
		),
		']',
		''
	),
	','	
)[2, 0]
// returns 13

Would the following json work?

        "type": "ia.display.label",
        "meta": {
          "name": "quartile_label"
        },
        "props": {
          "text": "Normal",
          "quartileLabels": [
            "Low",
            "Normal",
            "High",
            "Warning"
          ],
          "backgroundColors": [
            "#B3E5FC",
            "#C8E6C9",
            "#FFE0B2",
            "#FFCDD2"
          ],
          "textColors": [
            "#01579B",
            "#1B5E20",
            "#E65100",
            "#B71C1C"
          ]
        },
        "style": {
          "fontSize": "18px",
          "fontWeight": "bold",
          "padding": "10px 20px",
          "borderRadius": "4px",
          "marginTop": "20px",
          "backgroundColor": "#C8E6C9",
          "color": "#1B5E20"
        },
        "propConfig": {
          "props.text": {
            "binding": {
              "type": "expr",
              "config": {
                "expression": "this.props.quartileLabels[{[default]Expressions/Slider_Quartile}]"
              }
            }
          },
          "style.backgroundColor": {
            "binding": {
              "type": "expr",
              "config": {
                "expression": "this.props.backgroundColors[{[default]Expressions/Slider_Quartile}]"
              }
            }
          },
          "style.color": {
            "binding": {
              "type": "expr",
              "config": {
                "expression": "this.props.textColors[{[default]Expressions/Slider_Quartile}]"
              }
            }
          }
        }
      },```


EDIT, works besides some improper expressions and binding configs, which i've fixed

jsonGet accepts a JSONPath as the second argument:

jsonGet("{item: [1,2,3,4,5]}", 'item[2]') -> 3

No need for anything extra.

I'm actually not sure why using the subscript outside isn't working (it goes through a totally different logic path, but should still work here) but :person_shrugging:

1 Like

Huh, ok, thanks!

The outside subscript not working I'll just class as a subtle bug, then. (From some forum searches it looks like jsonGet's return type has been borked for a while)

The return type of jsonGet depends on its input type.

In this case, you are feeding it a String that happens to be valid JSON syntax. What you get back is a String that also happens to be valid JSON syntax ("[1, 2, 3, 4, 5]").

I guess the expressions can't index into a String?

1 Like

can jsonget be passed a pure dict instead of a string in an expression? i assumed brackets would cause the parser to throw a fit

AFAIK there is no "dictionary" type recognized by the expression language. The closest thing to a JSON type in Ignition is the Document type used by the tag system, which the jsonGet function understands.

i.e. if you were doing this up in Tag land instead of Perspective, and you were passing jsonGet a reference to a Document tag's value via e.g. {MyDocumentTag}, the result of the operation would be a Document that was actually the extracted array, and I do think the expression language can subsequently index into that.

2 Likes

Perhaps you want jsonDecode() instead of jsonGet().

2 Likes

Nice!

jsonDecode("{'item': [10, 20, 30, 40, 50]}")
// returns `{"item": [10, 20, 30, 40, 50]}`

jsonDecode("{'item': [10, 20, 30, 40, 50]}")['item']`
// returns           [10, 20, 30, 40, 50]

jsonDecode("{'item': [10, 20, 30, 40, 50]}")['item'][1]
// returns                20