766 lines
22 KiB
HTML
766 lines
22 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8"/>
|
|
<title>
|
|
[json decode] And [json encode]: JSON Data in Pd
|
|
</title>
|
|
<style>
|
|
/* Page tweaks */
|
|
.preview-page {
|
|
margin-top: 64px;
|
|
margin-bottom: 21px;
|
|
}
|
|
/* User-content tweaks */
|
|
.timeline-comment-wrapper > .timeline-comment:after,
|
|
.timeline-comment-wrapper > .timeline-comment:before {
|
|
content: none;
|
|
}
|
|
/* User-content overrides */
|
|
.discussion-timeline.wide {
|
|
width: 920px;
|
|
}
|
|
</style>
|
|
<link href="style.css" rel="stylesheet"/>
|
|
</head>
|
|
<body>
|
|
<div class="page">
|
|
<div class="preview-page" data-autorefresh-url="" id="preview-page">
|
|
<main id="js-repo-pjax-container">
|
|
<div class="clearfix new-discussion-timeline container-xl px-3 px-md-4 px-lg-5">
|
|
<div class="repository-content">
|
|
<div class="clearfix">
|
|
<div class="Layout Layout--flowRow-until-md Layout--sidebarPosition-end Layout--sidebarPosition-flowRow-end">
|
|
<div class="Layout-main">
|
|
<div class="Box md Box--responsive" id="readme">
|
|
<div class="Box-header d-flex border-bottom-0 flex-items-center flex-justify-between color-bg-default rounded-top-2">
|
|
<div class="d-flex flex-items-center">
|
|
<h2 class="Box-title">
|
|
[json decode] And [json encode]: JSON Data in Pd
|
|
</h2>
|
|
</div>
|
|
</div>
|
|
<div class="Box-body px-5 pb-5">
|
|
<article class="markdown-body entry-content container-lg" id="grip-content">
|
|
<p>
|
|
Pd does not have boolean values, and no notion of a NULL object, only lists, symbols (=strings) and floats (=numbers).
|
|
</p>
|
|
<p>
|
|
To use the definitions from
|
|
<a href="http://json.org/" rel="nofollow">
|
|
json.org
|
|
</a>
|
|
this leads to the following mapping of JSON data to Pd:
|
|
</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>
|
|
JSON type
|
|
</th>
|
|
<th>
|
|
Pd type
|
|
</th>
|
|
<th>
|
|
JSON example
|
|
</th>
|
|
<th>
|
|
Pd example
|
|
</th>
|
|
</tr>
|
|
<tr>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>
|
|
string
|
|
</td>
|
|
<td>
|
|
symbol
|
|
</td>
|
|
<td>
|
|
"my string, containing a comma"
|
|
</td>
|
|
<td>
|
|
symbol my string\, containing a comma
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
number
|
|
</td>
|
|
<td>
|
|
float
|
|
</td>
|
|
<td>
|
|
1.01
|
|
</td>
|
|
<td>
|
|
1.01
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
object
|
|
</td>
|
|
<td>
|
|
see below
|
|
</td>
|
|
<td>
|
|
{"key": "value"}
|
|
</td>
|
|
<td>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
array
|
|
</td>
|
|
<td>
|
|
see below
|
|
</td>
|
|
<td>
|
|
[{"key": "value"}, {"other key": "other value"}]
|
|
</td>
|
|
<td>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
boolean
|
|
</td>
|
|
<td>
|
|
float
|
|
</td>
|
|
<td>
|
|
true
|
|
</td>
|
|
<td>
|
|
1
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
boolean
|
|
</td>
|
|
<td>
|
|
float
|
|
</td>
|
|
<td>
|
|
false
|
|
</td>
|
|
<td>
|
|
0
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
null
|
|
</td>
|
|
<td>
|
|
symbol
|
|
</td>
|
|
<td>
|
|
null
|
|
</td>
|
|
<td>
|
|
symbol
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>
|
|
As you can infer from the table, values of
|
|
<code>
|
|
true
|
|
</code>
|
|
,
|
|
<code>
|
|
false
|
|
</code>
|
|
, or
|
|
<code>
|
|
null
|
|
</code>
|
|
cannot be constructed by
|
|
<code>
|
|
[json-encode]
|
|
</code>
|
|
, but can be read by the objects. A value of null yields a Pd value of an empty symbol.
|
|
</p>
|
|
<h2>
|
|
<a aria-hidden="true" class="anchor" href="#json-decode" id="user-content-json-decode">
|
|
<span aria-hidden="true" class="octicon octicon-link">
|
|
</span>
|
|
</a>
|
|
<code>
|
|
[json-decode]
|
|
</code>
|
|
</h2>
|
|
<p>
|
|
Feeding a symbol or list to
|
|
<code>
|
|
[json-decode]
|
|
</code>
|
|
will parse the values and generate an output. If you use a list, then all elements of the list will be converted to symbols and concatenated using a space as separator, so
|
|
<code>
|
|
symbol my value
|
|
</code>
|
|
will generate the same output as
|
|
<code>
|
|
list my value
|
|
</code>
|
|
.
|
|
</p>
|
|
<p>
|
|
You must feed exactly one valid JSON object or array of objects as a symbol or list message to
|
|
<code>
|
|
[json-decode]
|
|
</code>
|
|
. Any other correct JSON data cannot be interpreted by the
|
|
<code>
|
|
[json-decode]
|
|
</code>
|
|
.
|
|
</p>
|
|
<h3>
|
|
<a aria-hidden="true" class="anchor" href="#output-of-a-json-object" id="user-content-output-of-a-json-object">
|
|
<span aria-hidden="true" class="octicon octicon-link">
|
|
</span>
|
|
</a>
|
|
Output of a JSON object
|
|
</h3>
|
|
<p>
|
|
JSON objects are interpreted by
|
|
<code>
|
|
[json-decode]
|
|
</code>
|
|
as key value stores. Each key/value pair outputs a list on the middle outlet, where the key is always converted to a symbol, while the value is converted according to the table above. Arrays and objects are converted to their string representation again and then output as a symbol.
|
|
</p>
|
|
<p>
|
|
After all key/value are sent to the middle outlet, a
|
|
<code>
|
|
bang
|
|
</code>
|
|
is emitted from the left outlet.
|
|
</p>
|
|
<p>
|
|
<strong>
|
|
Example:
|
|
</strong>
|
|
</p>
|
|
<p>
|
|
JSON string:
|
|
</p>
|
|
<pre><code>{
|
|
"id": 1,
|
|
"active": true,
|
|
"obsolete": false,
|
|
"name": "PuREST JSON",
|
|
"objects": ["json-decode", "json-encode", "urlparams", "rest", "oauth"],
|
|
"author": {"name": "me", "age": "none of your business"}
|
|
}
|
|
</code></pre>
|
|
<p>
|
|
Output:
|
|
</p>
|
|
<ol>
|
|
<li>
|
|
middle:
|
|
<code>
|
|
list id 1
|
|
</code>
|
|
</li>
|
|
<li>
|
|
middle:
|
|
<code>
|
|
list active 1
|
|
</code>
|
|
</li>
|
|
<li>
|
|
middle:
|
|
<code>
|
|
list obsolete 0
|
|
</code>
|
|
</li>
|
|
<li>
|
|
middle:
|
|
<code>
|
|
list name PuREST JSON
|
|
</code>
|
|
</li>
|
|
<li>
|
|
middle:
|
|
<code>
|
|
list objects ["json-decode"\, "json-encode"\, "urlparams"\, "rest"\, "oauth"]
|
|
</code>
|
|
</li>
|
|
<li>
|
|
middle:
|
|
<code>
|
|
list author {"name": "me"\, "age": "none of your business"}
|
|
</code>
|
|
</li>
|
|
<li>
|
|
left:
|
|
<code>
|
|
bang
|
|
</code>
|
|
</li>
|
|
</ol>
|
|
<h3>
|
|
<a aria-hidden="true" class="anchor" href="#output-of-an-array-of-json-objects" id="user-content-output-of-an-array-of-json-objects">
|
|
<span aria-hidden="true" class="octicon octicon-link">
|
|
</span>
|
|
</a>
|
|
Output of an Array of JSON objects
|
|
</h3>
|
|
<p>
|
|
An array generates the same output as a series of JSON objects, including
|
|
<code>
|
|
bang
|
|
</code>
|
|
messages on the left outlet.
|
|
</p>
|
|
<p>
|
|
<strong>
|
|
Example:
|
|
</strong>
|
|
</p>
|
|
<p>
|
|
JSON string:
|
|
</p>
|
|
<pre><code>[
|
|
{"key": "value", "id": 1},
|
|
{"id": 2},
|
|
{"id": 3}
|
|
]
|
|
</code></pre>
|
|
<p>
|
|
Output:
|
|
</p>
|
|
<ol>
|
|
<li>
|
|
middle:
|
|
<code>
|
|
list key value
|
|
</code>
|
|
</li>
|
|
<li>
|
|
middle:
|
|
<code>
|
|
list id 1
|
|
</code>
|
|
</li>
|
|
<li>
|
|
left:
|
|
<code>
|
|
bang
|
|
</code>
|
|
</li>
|
|
<li>
|
|
middle:
|
|
<code>
|
|
list id 2
|
|
</code>
|
|
</li>
|
|
<li>
|
|
left:
|
|
<code>
|
|
bang
|
|
</code>
|
|
</li>
|
|
<li>
|
|
middle:
|
|
<code>
|
|
list id 3
|
|
</code>
|
|
</li>
|
|
<li>
|
|
left:
|
|
<code>
|
|
bang
|
|
</code>
|
|
</li>
|
|
</ol>
|
|
<h3>
|
|
<a aria-hidden="true" class="anchor" href="#error-handling" id="user-content-error-handling">
|
|
<span aria-hidden="true" class="octicon octicon-link">
|
|
</span>
|
|
</a>
|
|
Error handling
|
|
</h3>
|
|
<p>
|
|
If the string fed into
|
|
<code>
|
|
[json-decode]
|
|
</code>
|
|
cannot be converted into a valid JSON object, then Pd will write an error to the console, and the right outlet will output a bang. Use that for error handling.
|
|
</p>
|
|
<h3>
|
|
<a aria-hidden="true" class="anchor" href="#some-hints-for-data-processing" id="user-content-some-hints-for-data-processing">
|
|
<span aria-hidden="true" class="octicon octicon-link">
|
|
</span>
|
|
</a>
|
|
Some hints for data processing
|
|
</h3>
|
|
<ul>
|
|
<li>
|
|
Use
|
|
<code>
|
|
list trim
|
|
</code>
|
|
from list-abs for trimming the list selector off the output and then use
|
|
<code>
|
|
[route]
|
|
</code>
|
|
for the data. If you want to create new lists, feed them into
|
|
<code>
|
|
[pack]
|
|
</code>
|
|
.
|
|
</li>
|
|
<li>
|
|
If you process an array of same object types, use the approach above and store the values in a FIFO buffer, e. g.
|
|
<code>
|
|
[fifop]
|
|
</code>
|
|
from zexy or
|
|
<code>
|
|
[list-fifo]
|
|
</code>
|
|
from list-abs.
|
|
</li>
|
|
<li>
|
|
Do not expect JSON data to be ordered:
|
|
<code>
|
|
{"id": 1, "name: "my name"}
|
|
</code>
|
|
and
|
|
<code>
|
|
{"name": "my name", "id": 1}
|
|
</code>
|
|
are in fact the same object. Use an empty first inlet of
|
|
<code>
|
|
[pack]
|
|
</code>
|
|
and the
|
|
<code>
|
|
bang
|
|
</code>
|
|
from the left outlet to create your own lists.
|
|
</li>
|
|
</ul>
|
|
<h2>
|
|
<a aria-hidden="true" class="anchor" href="#json-encode" id="user-content-json-encode">
|
|
<span aria-hidden="true" class="octicon octicon-link">
|
|
</span>
|
|
</a>
|
|
<code>
|
|
[json-encode]
|
|
</code>
|
|
</h2>
|
|
<h3>
|
|
<a aria-hidden="true" class="anchor" href="#reading-and-writing-json-files" id="user-content-reading-and-writing-json-files">
|
|
<span aria-hidden="true" class="octicon octicon-link">
|
|
</span>
|
|
</a>
|
|
Reading and Writing JSON files
|
|
</h3>
|
|
<p>
|
|
<code>
|
|
[json-encode]
|
|
</code>
|
|
can hold one JSON object at a time in its memory. Therefore, if you read JSON data from a file using the
|
|
<code>
|
|
[read(
|
|
</code>
|
|
message, the message needs exactly one additional parameter, the path to the file to read.
|
|
</p>
|
|
<p>
|
|
The file must contain exactly one JSON object. If you want to read an array, you must wrap the array in an object.
|
|
</p>
|
|
<p>
|
|
<strong>
|
|
Example:
|
|
</strong>
|
|
</p>
|
|
<p>
|
|
<code>
|
|
[{"key": "value"}, {"another key": "another value"}]
|
|
</code>
|
|
cannot be read, but
|
|
<code>
|
|
{"wrapping": [{"key": "value"}, {"another key": "another value"}]}
|
|
</code>
|
|
can.
|
|
</p>
|
|
<p>
|
|
To write data to a file, use the
|
|
<code>
|
|
[write(
|
|
</code>
|
|
message. This message needs exactly one additional parameter, the path to the file to write the JSON object as string. It will overwrite existing content without asking for confirmation.
|
|
</p>
|
|
<h3>
|
|
<a aria-hidden="true" class="anchor" href="#storing-data-with-add-and-array" id="user-content-storing-data-with-add-and-array">
|
|
<span aria-hidden="true" class="octicon octicon-link">
|
|
</span>
|
|
</a>
|
|
Storing Data with
|
|
<code>
|
|
[add(
|
|
</code>
|
|
And
|
|
<code>
|
|
[array(
|
|
</code>
|
|
</h3>
|
|
<p>
|
|
There are two messages for adding values to the JSON object stored in
|
|
<code>
|
|
[json-encode]
|
|
</code>
|
|
,
|
|
<code>
|
|
[add(
|
|
</code>
|
|
and
|
|
<code>
|
|
[array(
|
|
</code>
|
|
. Both need at least two additional values. The first parameter must be a symbol and represents the key. As Pd currently has no way to escape whitespace, there is no simple way to generate keys with space in it, a workaround is possible using
|
|
<code>
|
|
[makefilename]
|
|
</code>
|
|
from
|
|
<a href="http://puredata.info/downloads/zexy" rel="nofollow">
|
|
zexy
|
|
</a>
|
|
.
|
|
</p>
|
|
<p>
|
|
If the message has exactly two additional parameters, and the second parameter is a float, then the value will be stored as a number. Otherwise all additional parameters will be concatenated with a space.
|
|
</p>
|
|
<p>
|
|
If the additional parameters can be converted to a JSON object, then the resulting string will be converted thusly, otherwise, a string is stored.
|
|
</p>
|
|
<p>
|
|
Adding a value with an already stored key will result in overwriting the existing value.
|
|
</p>
|
|
<p>
|
|
<strong>
|
|
Example:
|
|
</strong>
|
|
</p>
|
|
<ul>
|
|
<li>
|
|
<code>
|
|
[add key 1(
|
|
</code>
|
|
will store
|
|
<code>
|
|
{"key":1}
|
|
</code>
|
|
.
|
|
</li>
|
|
<li>
|
|
<code>
|
|
[add key first second third(
|
|
</code>
|
|
will store
|
|
<code>
|
|
{"key":"first second third"}
|
|
</code>
|
|
.
|
|
</li>
|
|
<li>
|
|
<code>
|
|
[add key {"first":"second third"}(
|
|
</code>
|
|
will store
|
|
<code>
|
|
{"key":{first: "second third"}}
|
|
</code>
|
|
.
|
|
</li>
|
|
</ul>
|
|
<p>
|
|
<code>
|
|
[array(
|
|
</code>
|
|
will add data to an array with the name of the key. The members of the array will be sorted in the specified order. If a value with the same key exists, but was stored with
|
|
<code>
|
|
[add(
|
|
</code>
|
|
, the value will be discarded. A new
|
|
<code>
|
|
[add(
|
|
</code>
|
|
message with the same key will discard the stored array.
|
|
</p>
|
|
<p>
|
|
<strong>
|
|
Example:
|
|
</strong>
|
|
</p>
|
|
<ol>
|
|
<li>
|
|
<code>
|
|
[add id 1(
|
|
</code>
|
|
=>
|
|
<code>
|
|
{"id": 1}
|
|
</code>
|
|
.
|
|
</li>
|
|
<li>
|
|
<code>
|
|
[array id 2(
|
|
</code>
|
|
=>
|
|
<code>
|
|
{"id": [2]}
|
|
</code>
|
|
.
|
|
</li>
|
|
<li>
|
|
<code>
|
|
[array id 3(
|
|
</code>
|
|
=>
|
|
<code>
|
|
{"id": [2, 3]}
|
|
</code>
|
|
.
|
|
</li>
|
|
<li>
|
|
<code>
|
|
[add id 4(
|
|
</code>
|
|
=>
|
|
<code>
|
|
{"id": 4}
|
|
</code>
|
|
.
|
|
</li>
|
|
</ol>
|
|
<h3>
|
|
<a aria-hidden="true" class="anchor" href="#outputting-and-clearing-data" id="user-content-outputting-and-clearing-data">
|
|
<span aria-hidden="true" class="octicon octicon-link">
|
|
</span>
|
|
</a>
|
|
Outputting And Clearing Data
|
|
</h3>
|
|
<p>
|
|
Issuing a
|
|
<code>
|
|
[bang(
|
|
</code>
|
|
message to
|
|
<code>
|
|
[json-encode]
|
|
</code>
|
|
will output the JSON object as a string on its only outlet. If no data is stored, an empty symbol is sent.
|
|
</p>
|
|
<p>
|
|
You can clear the stored object with the
|
|
<code>
|
|
[clear(
|
|
</code>
|
|
method.
|
|
</p>
|
|
</article>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
function showCanonicalImages() {
|
|
var images = document.getElementsByTagName('img');
|
|
if (!images) {
|
|
return;
|
|
}
|
|
for (var index = 0; index < images.length; index++) {
|
|
var image = images[index];
|
|
if (image.getAttribute('data-canonical-src') && image.src !== image.getAttribute('data-canonical-src')) {
|
|
image.src = image.getAttribute('data-canonical-src');
|
|
}
|
|
}
|
|
}
|
|
|
|
function scrollToHash() {
|
|
if (location.hash && !document.querySelector(':target')) {
|
|
var element = document.getElementById('user-content-' + location.hash.slice(1));
|
|
if (element) {
|
|
element.scrollIntoView();
|
|
}
|
|
}
|
|
}
|
|
|
|
function autorefreshContent(eventSourceUrl) {
|
|
var initialTitle = document.title;
|
|
var contentElement = document.getElementById('grip-content');
|
|
var source = new EventSource(eventSourceUrl);
|
|
var isRendering = false;
|
|
|
|
source.onmessage = function(ev) {
|
|
var msg = JSON.parse(ev.data);
|
|
if (msg.updating) {
|
|
isRendering = true;
|
|
document.title = '(Rendering) ' + document.title;
|
|
} else {
|
|
isRendering = false;
|
|
document.title = initialTitle;
|
|
contentElement.innerHTML = msg.content;
|
|
showCanonicalImages();
|
|
}
|
|
}
|
|
|
|
source.onerror = function(e) {
|
|
if (e.readyState === EventSource.CLOSED && isRendering) {
|
|
isRendering = false;
|
|
document.title = initialTitle;
|
|
}
|
|
}
|
|
}
|
|
|
|
window.onhashchange = function() {
|
|
scrollToHash();
|
|
}
|
|
|
|
window.onload = function() {
|
|
scrollToHash();
|
|
}
|
|
|
|
showCanonicalImages();
|
|
|
|
var autorefreshUrl = document.getElementById('preview-page').getAttribute('data-autorefresh-url');
|
|
if (autorefreshUrl) {
|
|
autorefreshContent(autorefreshUrl);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |