# Using Document Tags to Store JSON

**URL:** <https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412>\
**Category:** Ignition\
**Created:** [March 12, 2021, 4:23pm UTC](https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412 "2021-03-12T16:23:59Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![mcarritt1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mcarritt1/32/4262_2.png) [@mcarritt1](https://forum.inductiveautomation.com/u/mcarritt1)\
**Post date:** [March 12, 2021, 4:23pm UTC](https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412/1 "2021-03-12T16:23:59Z")

</div>

Hi I’m trying to utilize document tags to store some data, and having a hard time with it.

Heres what I’m doing:  
Create an empty document tag.  
in scripting, create a dictionary, that will be a list of dictionaries.  
write that structure to the tag  
then I want to append additional entries to the list, which I get an error.

```auto
#get the tag value
tagData = system.tag.readBlocking([myDocTag])[0].value
#create an instance of data i want to store
instance = {'stuff':'stuff info'}
#if the tag is empty, create the data structure
if tagData is None:
	data = {'toplevel' : [instance]}
#the structure should exist, so just add to it
else:
	tagData = dict(tagData)
	tagData['toplevel'].append(instance) #I get an error here  
#can't convert to com.inductiveautomation.ignition.common.document.DocumentElement

data = system.util.jsonEncode(tagData)
system.tag.writeBlocking([myDocTag], [data])

```

Is there something I’m missing?

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [March 12, 2021, 4:40pm UTC](https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412/2 "2021-03-12T16:40:55Z")

</div>

Well I think your first mistake is assuming the value you get from reading a document tag is a python dictionary.

You can convert it to a dictionary with something like this:

```auto
qv = system.tag.read("DocTest")
dict = system.util.jsonDecode(str(qv.value))

```

The next issue is that dictionaries don’t have an `append` method…

---

<div class="post-metadata">

**Author:** ![WillMT10](https://avatars.discourse-cdn.com/v4/letter/w/7feea3/32.png) [@WillMT10](https://forum.inductiveautomation.com/u/WillMT10)\
**Post date:** [March 12, 2021, 4:55pm UTC](https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412/3 "2021-03-12T16:55:01Z")

</div>

You can also use `.toDict()`:

```auto
qv = system.tag.read("DocTest")
doctest_dict = qv.value.toDict()

```

Also, just a quick warning. If you store java.util.Date type values to these tags, they get converted to a string and you will need to loop through the dict to parse them back to a Date object if you want to use them as a Date object again (`system.date.parse(val_to_parse, "E MMM dd HH:mm:ss z yyyy")`).

---

<div class="post-metadata">

**Author:** ![mcarritt1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mcarritt1/32/4262_2.png) [@mcarritt1](https://forum.inductiveautomation.com/u/mcarritt1)\
**Post date:** [March 12, 2021, 4:56pm UTC](https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412/4 "2021-03-12T16:56:10Z")

</div>

Hrm, I do convert the value i get from a tag using  
(after the else:)  
tagData = dict(tagData)

I’ll try to use json decode like your example though.

I’m not trying to append to dict, i’m trying to append to a list thats the value of a key in dictionary. like this:

```auto
test = {'top': []}
test['top'].append(1)
test['top'].append(2)
test['top'].append(3)
print test
>>> {'top': [1, 2, 3]}

```

---

<div class="post-metadata">

**Author:** ![mcarritt1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mcarritt1/32/4262_2.png) [@mcarritt1](https://forum.inductiveautomation.com/u/mcarritt1)\
**Post date:** [March 14, 2021, 4:46pm UTC](https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412/5 "2021-03-14T16:46:43Z")

</div>

well after getting the tag value, I didnt realize I needed to force it to a string first. Thanks that helped!

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [March 14, 2021, 5:09pm UTC](https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412/6 "2021-03-14T17:09:09Z")

</div>

@WillMT10’s `toDict()` method is a little cleaner than forcing it to string and parsing it.

---

<div class="post-metadata">

**Author:** ![mcarritt1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mcarritt1/32/4262_2.png) [@mcarritt1](https://forum.inductiveautomation.com/u/mcarritt1)\
**Post date:** [March 14, 2021, 5:22pm UTC](https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412/7 "2021-03-14T17:22:40Z")

</div>

so is  
`system.tag.readBlocking([myDocTag])[0].value.toDict()`  
different than  
`dict(system.tag.readBlocking([myDocTag])[0].value)` ?

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [March 14, 2021, 5:25pm UTC](https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412/8 "2021-03-14T17:25:07Z")

</div>

Yes, because `toDict()` is something we implemented on the Python-friendly document type you get from reading that tag’s value. I don’t know how `dict()` will behave when receiving that object.

---

<div class="post-metadata">

**Author:** ![mcarritt1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mcarritt1/32/4262_2.png) [@mcarritt1](https://forum.inductiveautomation.com/u/mcarritt1)\
**Post date:** [March 14, 2021, 5:26pm UTC](https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412/9 "2021-03-14T17:26:49Z")

</div>

oh ok that makes sense. sweet well i’ll try that, thanks!

---

<div class="post-metadata">

**Author:** ![ryanjmclaughlin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ryanjmclaughlin/32/4318_2.png) [@ryanjmclaughlin](https://forum.inductiveautomation.com/u/ryanjmclaughlin)\
**Post date:** [March 15, 2021, 12:22pm UTC](https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412/10 "2021-03-15T12:22:57Z")

</div>

> [@Kevin.Herron](#):
>
> `toDict()` is something we implemented on the Python-friendly document type

Is this something recent, or did I completely miss it somewhere? Up til now I was importing and using the functions in TypeUtilities.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [March 15, 2021, 1:04pm UTC](https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412/11 "2021-03-15T13:04:35Z")

</div>

I didn’t know it was there either… but it looks like it has been since 2018.

---

<div class="post-metadata">

**Author:** ![tyler.bennett](https://avatars.discourse-cdn.com/v4/letter/t/f04885/32.png) [@tyler.bennett](https://forum.inductiveautomation.com/u/tyler.bennett)\
**Post date:** [June 27, 2025, 12:24am UTC](https://forum.inductiveautomation.com/t/using-document-tags-to-store-json/44412/12 "2025-06-27T00:24:05Z")

</div>

A word of caution based on my observations...

JSON at its top level is always a dictionary of key/value pairs but the Ignition document tag seems to accept objects with lists at the top level.

The object returned by reading the value of a document tag will have a [PyDocumentObjectAdapter](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.48/com/inductiveautomation/ignition/common/script/adapters/PyDocumentObjectAdapter.html) object for levels of the object that are dictionary (dict) equivalents.

The object returned by reading the value of a document tag will have a will have an `array.array` object for levels of the document that are list equivalents.

Calling `.toDict()` on a [PyDocumentObjectAdapter](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.48/com/inductiveautomation/ignition/common/script/adapters/PyDocumentObjectAdapter.html) object will return the object convert to a py `dict` object with deeper level `PyDocumentObjectAdapter` objects also converted to py `dict` objects and with deeper level `array.array` objects converted to py `list` objects.

Calling `.tolist()` on an `array.array` object will return will return the object convert to a py `list` object but **DOES NOT** convert deeper level `PyDocumentObjectAdapter` and `array.array` objects. You cannot assume some lower level isn't still a `PyDocumentObjectAdapter` object or `array.array` object. In that case you may need to recursively process the whole object

```python
def sanitize(obj):
	if hasattr(obj, "append"): # list like object
		if hasattr(obj, "tolist"): # array.array object 
			obj = obj.tolist()
		for i in range(len(obj)):
			obj[i] = sanitize(obj[i])
		return obj
	elif hasattr(obj, "items"): # dict like object
		if hasattr(obj, "toDict"): # PyDocumentObjectAdapter object
			obj = obj.toDict()
			# We should not need to process the deeper levels
# else:
# for k, v in obj.iteritems():
# obj[k] = sanitize(v)
		return obj
	else:
		return obj

obj_in =[{"a": [1,2], "b": 3, "c": {"x":4}}, {"y":5}, 100]
system.tag.writeBlocking([tagPath], [obj_in])
obj_out = system.tag.readBlocking([tagPath])[0].value
results = sanitize(obj_in)
print results
results.append(300)
results[0]["a"].append(3)
results[0]["c"]["y"] = 5
print results

```

Therefore it would seem good practice to always have the top level of the object be a dictionary so you can just call `.toDict()` on the whole thing.
