Get array from JSON file

I am trying to make a simple system that can retrieve dialogue from a json file, but nothing I can find online seems to work.

The error I currently have, is that the json is retrieved as a string, yet I cannot find a way to retireve it as an array.

A large amount of dialogue will be retrieved eventually, so it needs to put it in an array

The current retrieval method I have is the following:

var FILE_PATH = "res://Assets/Dialogue/test_dialogue.json"

func _ready():
	var json = JSON.new()
	var file = FileAccess.open(FILE_PATH, FileAccess.READ)
	var json_text = JSON.stringify(file.get_as_text())
	file.close()

	var error = json.parse(json_text)
	if error == OK:
		var data_received = json.data
		if typeof(data_received) == TYPE_ARRAY:
			# process code here
			pass

This code retrieves the json, but on typeof(data_recieved) it returns a type of a string.

How do I make it return an array?

My json looks ike this currently:

{
	"dialouge": [
		{
			"type" : "line","text" : "dialogue line 1","char" : "talker","expression" : "1"
		},
		{
			"type" : "line","text" : "dialogue line 2","char" : "talker","expression" : "1"
		},
		{
			"type" : "line","text" : "dialogue line 3","char" : "talker","expression" : "1"
		},
		{
			"type" : "line","text" : "dialogue line 4","char" : "talker","expression" : "1"
		},
		{
			"type" : "line","text" : "dialogue line 5, the very very very long line of dialogue that is soooooooooo long it barely fits on screen","char" : "talker","expression" : "1"
		}
	]
}

HTH,
Cheers !

1 Like

The short version of what @OleNic said: You need to call JSON.parse() on your string.

when?
I already am parsing the json when I check for an error.
And the documentation doesn’t mention any other parses.

Ahhh, too little coffee, sorry.

You aren’t getting TYPE_ARRAY because you aren’t feeding it an array. You’re feeding it an object that contains an array.

Try:

    if error == OK:
        var data_received:  Dictionary = json.data
        var dialogue_array: Array      = data_received["dialogue"]
            for d: Dictionary in dialogue_array:
                print("%s: %s" % [d["char"], d["text"]])
1 Like

Why is the dialogue in a JSON file to begin with? Is it being exported that way from another system, or did you just decide to put it in JSON for some reason?

Is there a reason your prefer an Array to a Dictionary? I ask because JSON is structured to easily be sucked into a Dictionary - even if it becomes a Dictionary of Dictionaries, which is very easy to parse.


My recommendation is to do one of two things:

  1. Don’t use JSON for your dialogue if you want your dialogue loaded into an Array. Store it as something simpler so that you can parse it using the FileAccess object.
  2. If your dialogue needs to be stored with more information, like the speaker and facial expression etc. (as indicated in your example JSON), don’t use an Array - use a Dictionary. It is meant to hold relational data like what you find in a JSON file.

I am using a json file because it makes multi-language support easier if I wanted to implement it.
Along with organized dialog which I don’t need to open Godot for if I wanted to edit it.

but if using a dictionary is more useful then an array for multiple properties, how do I retrieve one from my json?
do i need to convert the string I receive?

There’s a nice little tutorial in the docs about saving/loading data, and how to get data to/from Dictionaries and JSON.

1 Like

The example in the dosc about saving games, only has 1 object it stores in the json, while my dialogue bank has multiple.

As a result, I have updated my code to the following:

func _ready():
	var file = FileAccess.open(FILE_PATH, FileAccess.READ)
	
	var json_string = JSON.stringify(file.get_as_text())
	var json = JSON.new()
	
	var parse_result = json.parse(json_string)
	if not parse_result == OK:
		print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line())
		
	
	var json_data = json.data
	print(json_data.dialouge[0].text)

but it still makes json.data a string
I have tried using

var json_data: Dictionary = json.data

But then it returns an error, saying I am trying to assign a string to a Dictionary

How do I fix this?
And is the way I’m trying to get data from a dictionary correct?

Don’t call .stringify(), just hand the file data directly in to .parse().

EDIT: I’m pretty sure .stringify() is json-escaping your string, which is causing .parse() to de-escape it and you get back… a string.

3 Likes

I wrote a plugin to do this. Taking a look at the code might help you.

From that code I have this function. It literally is what I use to deal with any JSON file.

## Takes serialized data and deserializes it for loading.
func _deserialize_data(data: String) -> Variant:
	var json = JSON.new()
	var error = json.parse(data)
	if error == OK:
		return json.data
	else:
		print("JSON Parse Error: ", json.get_error_message(), " in ", data, " at line ", json.get_error_line())
	return null

As @hexgrid mentioned, stringify() is for encoding your data for saving as a JSON string.

## Takes data and serializes it for saving.
func _serialize_data(data: Variant) -> String:
	return JSON.stringify(data)
2 Likes

Thanks everyone, I managed to get it to work now.
The final result is this:

#	Variable to store the JSON
var json_result

func _ready():
	#	open the file where the JSON is stored
	var FILE_PATH = "res://Assets/Dialogue/test_dialogue.json"
	var file = FileAccess.open(FILE_PATH, FileAccess.READ)	
	var json = JSON.new()
	
	#	retrieve the JSON and parse it
	var parse_result = json.parse(file.get_as_text())
	
	#	error handeling
	if parse_result != OK:
		print("JSON Parse Error: ", json.get_error_message(), " in ", file.get_as_text(), " at line ", json.get_error_line())
	else:
		#	Put the result into a Dictionary
		var json_data: Dictionary = json.data
		
		#	make the result reachable in the rest of the code, and test it
		json_result = json_data
		print(json_result.dialouge[0].text)
1 Like

I recommend changing this line to a const at the top of the file.

const FILE_PATH = "res://Assets/Dialogue/test_dialogue.json"
1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.