JSON in one look
JSON (JavaScript Object Notation) is plain text for structured data, and almost every web service sends and takes it. Its pieces map onto xTalk's naturally:
| JSON | Looks like | In xTalk |
|---|---|---|
| object | {"name": "Ada", "born": 1815} | an array with those keys |
| array (a list) | ["tea", "cake"] | an array with keys 1, 2, 3 … |
| string | "Zoë said \"hi\"" | text |
| number | 3.14 | a number |
true, false | true, false | |
null | empty |
The two functions that do the work, JSONImport and JSONExport, come in the JSON library that OXT-Beyond loads as it starts.
Reading JSON: JSONImport
JSONImport turns JSON text into an xTalk value, usually an array, whose elements you reach with keys, as deep as the JSON goes:
put "{'name': 'Zoë', 'tags': ['admin', 'editor'], 'address': {'city': 'Lyon'}, 'score': 3.5, 'active': false, 'manager': null}" into tJSON
replace "'" with quote in tJSON
put JSONImport(tJSON) into tUser
put tUser["name"] && "lives in" && tUser["address"]["city"]
put "tags:" && the number of elements of tUser["tags"] & ", the second is" && tUser["tags"][2]
put "score doubled:" && tUser["score"] * 2
put "active:" && tUser["active"]
put "manager is empty:" && (tUser["manager"] is empty)
Zoë lives in Lyon tags: 2, the second is editor score doubled: 7 active: false manager is empty: true
JSON's strings are in double quotes, which end an xTalk string. To write JSON in a script, this example writes ' for each " and then replaces them: a trick for examples and tests. JSON you work with usually comes from a file or a web service, already as text.
Writing JSON: JSONExport
JSONExport turns an xTalk value into JSON text, escaping quotes and line breaks in strings for you:
put "Ada said" && quote & "hello" & quote & return & "and left" into tNote["text"]
put JSONExport(tNote)
put 1815 + 0 into tPerson["born"]
put JSONExport(tPerson)
put "1815" into tPerson["born"]
put JSONExport(tPerson)
{"text": "Ada said \"hello\"\nand left"}
{"born": 1815}
{"born": "1815"}
The last two lines show a difference that matters to many services. A value that xTalk holds as a number is written as a JSON number; one it holds as text is written as a string, even when the text is digits. A value typed in a script, or read from a field or a file, is text; arithmetic (here + 0) makes it a number.
Writing a JSON list
An xTalk array is always written as a JSON object, even when its keys are 1, 2, 3, so ["tea", "cake"] comes out as {"1": "tea", "2": "cake"}. When a service needs a JSON list, build it from the elements in order, each one exported on its own:
function jsonList pArray
local tItems
repeat with i = 1 to the number of elements of pArray
put JSONExport(pArray[i]) & "," after tItems
end repeat
delete the last char of tItems
return "[" & tItems & "]"
end jsonList
put "tea" into tOrder[1]
put "cake" into tOrder[2]
put "juice" into tOrder[3]
put jsonList(tOrder) into tJSON
put tJSON
put JSONImport(tJSON) into tBack
put tBack[2]
["tea","cake","juice"] cake
When the JSON is wrong
Text that is not valid JSON makes JSONImport throw an error, so wrap it in a try whenever the text comes from outside your program:
command readJSON pText, @rValue
try
put JSONImport(pText) into rValue
catch tError
return "not valid JSON" for error
end try
return empty for value
end readJSON
repeat for each line tText in "[1, 2, 3]" & return & "{broken"
readJSON tText, tValue
if the result is not empty then
put tText & ":" && the result
else
put tText & ": read," && the number of elements of tValue && "elements"
end if
end repeat
[1, 2, 3]: read, 3 elements
{broken: not valid JSON
A settings file
JSON makes a good settings file: readable, and easy to edit by hand if need be. Write it as UTF-8 through binfile: so accented letters survive on every system (Reading and writing files):
put specialFolderPath("temporary") & "/oxt-lesson-settings.json" into tPath
put "dark" into tSettings["theme"]
put 14 + 0 into tSettings["textSize"]
put "Zoë" into tSettings["user"]
put textEncode(JSONExport(tSettings), "UTF-8") into URL ("binfile:" & tPath)
put JSONImport(textDecode(URL ("binfile:" & tPath), "UTF-8")) into tLoaded
put tLoaded["user"] && "likes" && tLoaded["theme"] && "at" && tLoaded["textSize"] && "points"
delete file tPath
Zoë likes dark at 14 points
Try it yourself
A web service sent this list of books: [{"title": "Dune", "pages": 412}, {"title": "Emma", "pages": 474}, {"title": "Momo", "pages": 304}]. Read it, put the titles sorted by pages, longest first, and the total number of pages.
Show a solution
put "[{'title': 'Dune', 'pages': 412}, {'title': 'Emma', 'pages': 474}, {'title': 'Momo', 'pages': 304}]" into tJSON
replace "'" with quote in tJSON
put JSONImport(tJSON) into tBooks
put 0 into tTotal
repeat with i = 1 to the number of elements of tBooks
put tBooks[i]["pages"] & tab & tBooks[i]["title"] & return after tList
add tBooks[i]["pages"] to tTotal
end repeat
set the itemDelimiter to tab
sort lines of tList numeric descending by item 1 of each
repeat for each line tLine in tList
put item 2 of tLine && "(" & item 1 of tLine && "pages)"
end repeat
put "total:" && tTotal
Emma (474 pages) Dune (412 pages) Momo (304 pages) total: 1190
Words in this lesson
Each one finds every lesson that uses it. The Dictionary has the whole story of each, with its syntax and more examples.