Copy json dictionary without unicode delimiters

I am using a document memory tag to store some recipe information, and there is a “bug” right now with that tag type that requires you to cast the value to a string, and then jsonDecode it to use it as a dictionary.
i.e.

json = system.util.jsonDecode(str(system.tag.readBlocking([tagPath])[0].value))

But somewhere along the way the keys in the dictionaries are made into unicode, instead of strings, so you have the u' appended to the beggining of each key.

i.e.

{u'example':1234, u'example2':[1,2,3,4,5]}

Is there an easy way to convert all of them to regular strings? I know I can do a .replace("u'", "'") on it while its a string, but that is not necessarily a very clean solution.

Any ideas?

1 Like

That ‘u’ isn’t actually there in the string value, it’s only there in the toString representation you see when printing the dictionary.

Gotcha,

I am trying to copy my json to review it in a formatted editor like VSCode, and I just wasnt able to find a way to copy it without those included.

Is there a way to print it in a way that doesnt show the u for the unicode so that I can copy it without them?

EDIT: OR if I am able to print formatted json in the script console, just didnt think I could do that

Actually,

I just needed to grab it prior to encoding it into a dictionary, so in this example, I would copy the print from documentString

tagPath = "[default]Testing/Recipe"
documentTag = system.tag.readBlocking([tagPath])[0].value
print documentTag
documentUnicodeString = str(documentTag)
print documentString #Copy me for a JSON editor!
documentJSON = system.util.jsonDecode(documentString)
print documentJSON

Just print the document without turning it to a dictionary.

edit: yep you got it.

1 Like

What timing,

Thanks for the clarification on the presence of the u kevin!

Continuing on the topic, I just want to get a JSON for tags using in a script (in version 8)

		tags = system.tag.getConfiguration(path,True)
		print tags

for one of my memory tags ‘[default]Tag 0’ from DB. I get the following in log file

[{u'dataType': Float4, u'documentation': u'Boiler Pressure', u'alarms': [{u'setpointA': 75.0, u'label': u'High', u'mode': Above Setpoint, u'name': u'High'}, {u'setpointA': 10.0, u'label': u'Very Low', u'mode': Below Setpoint, u'name': u'Very Low'}, {u'setpointA': 20.0, u'mode': Below Setpoint, u'name': u'Low'}, {u'setpointA': 80.0, u'label': u'Very High', u'mode': Above Setpoint, u'name': u'Very High'}], u'path': [default]Tag 0, u'tagType': AtomicTag, u'name': u'Tag 0', u'engUnit': u'psi', u'valueSource': u'memory', u'value': 80.0}]

I want the output value ‘tags’ in JSON without the unicode characters! I can understand tag properties in unicode in order to facilitate localization in diifferent languages , but why are all keys also converted to unicode? Basically I am trying to generate a JSON array for a given list of tags of my choice from my DB, so that I can export the JSON to another Ignition DB for further processing. How can I do that?

The u’’ syntax is a printing/logging artifact. Strings in java are natively unicode, so that representation is the default conversion in jython. Note that getConfiguration isn’t returning JSON, it is returning a python list of python dictionaries. (Documented to do so, if you didn’t notice.) You would need to use jsonEncode or your own equivalent to yield JSON.

1 Like

While converting dictionary to JSON using json.dumps(), some of the values in key/value pairs are enums such as Float4, the alarm properties etc which give error such as cannot be serialized! I guess we have to individually convert each key/value pair, there is no simple one function that will do the JSON conversion for this use case! Or is there any ? I don’t know where to find jsonEncode documentation in scripting functions!

https://docs.inductiveautomation.com/display/DOC80/system.util.jsonEncode

Thanks for the link. But I get an error ‘RuntimeError: maximum recursion depth exceeded (Java StackOverflowError)’ I think I have given a large dictionary object ! I will try some smaller object.

The function system.tag.exportTags works fine, but alas its only for version 8. Wish there was some thing like this for at least 7.9.

Actually this typically comes from giving the jsonEncode function a dictionary that includes a class instance of something that serializses in a non-json structure. For instance if one of your values is a BasicQualifiedValue then it will return this. I’m not exactly sure what your dictionary looks like prior to encoding, but you could potentially iterate through it and convert any BasicQualifiedValues to regular values

As given before, the dictionary is basically a tag properties dictionary generated by function system.tag.getConfiguration(basePath, recursive) in version 8. I think, things like Float4, Above setpoint, Below Setpoint etc are enums which are I think not parsable to JSON. It will be nice if I can get the properties of selected tags as JSON somehow, just like the system.tag.exportTags function in version 8, exports JSON for a given folder to a file. Sample JSON:

[
{
"valueSource": "memory",
"dataType": "Float4",
"documentation": "Hotwell Level",
"alarms": [
{
"mode": "AboveValue",
"setpointA": 75.0,
"name": "High",
"label": "High"
},
{
"mode": "BelowValue",
"setpointA": 10.0,
"name": "Very Low",
"label": "Very Low"
},
{
"mode": "BelowValue",
"setpointA": 20.0,
"name": "Low",
"label": "Low"
},
{
"mode": "AboveValue",
"setpointA": 80.0,
"name": "Very High",
"label": "Very High"
}
],

Try replacing the memory tag value at the end of the JSON before converting it, I am able to parse json with floats and what not in it.

In your case before the encode hardcode it with something like tags[0][‘value’] = 80 And see if that works.

As well the ‘path’ variable may be a BasicTagPath and not a string so you could try overwriting that as a string as well.

If those two solve it, it would be pretty easy to write a recursive script that goes through all of it to find oddly typed values like that and convert them

The problem is solved by simply casting these enums to string in python. It is producing the python dictionary which is parsable to JSON properly now! It was a simple problem!

Hi @PRAMANJ , @kgamble

Can you help to solve this for me?
I need to write back the dictionary value to tag.

userName = self.session.props.auth.user.userName

rawTagdata = system.tag.readBlocking(["[default]NOCTANKMONITOR/PersonalTrend"])
system.perspective.print (rawTagdata)

personalTrendTags = rawTagdata[0].value.toDict()

personalAxes = self.view.custom.axes
personalColors = self.view.custom.colors
personalPens = self.view.custom.pens
personalTags = self.view.custom.tags

personalTrendTags[userName] = {"axes":personalAxes, "colors":personalColors , "pens":personalPens, "tags":personalTags}
system.perspective.print (personalTrendTags)

newTagdata = []
newTagdata.append(personalTrendTags)
system.perspective.print (newTagdata)

encodedTag = system.util.jsonEncode(newTagdata)
system.tag.writeBlocking(["[default]NOCTANKMONITOR/PersonalTrend"], [encodedTag])

I’m getting same error as “RuntimeError: maximum recursion depth exceeded (Java StackOverflowError)” at system.util.jsonEncode script.

If you look through the output printed by the third print statement, you will notice that there are alot of objectWrappers for each of the color properties:

... 
<ObjectWrapper>: {u'color': u'rgba(151,242,24,1)', u'pen': None},
<ObjectWrapper>: {u'color': u'rgba(242,24,215,1)', u'pen': None},
<ObjectWrapper>: {u'color': u'rgba(24,242,205,1)', u'pen': None},
...

The system.util.jsonEncode() function is not a fan of wrappers I have found, same happens when you pass a BasicQualifiedValue

Unfortunately these wrappers seem to be present on each of the objects within array properties. So to use them you will just need to cast them as dictionaries (and a list in the case of the tags)

Replace lines 8-11 with the following

personalAxes = [dict(axis) for axis in self.view.custom.axes]
personalColors = [dict(color) for color in self.view.custom.colors]
personalPens = [dict(pen) for pen in self.view.custom.pens]
personalTags = list(self.view.custom.tags)

Note:
I am not sure if this is considered a bug or not, because I can see almost no end user scenario where the preferred behavior would be to copy the wrapper and not a dictionary? However there may be some functional limitations here that I am unaware of causing this to be a necessity

@kgamble Thanks a lot! I got your point. :+1:

1 Like