mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-22 19:04:38 +00:00
Compare commits
7 Commits
parameteri
...
json-ops
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
162e4be9f2 | ||
|
|
1ef9d11ca3 | ||
|
|
28f1d587b6 | ||
|
|
096b30f43b | ||
|
|
1d4418a777 | ||
|
|
093cda65fb | ||
|
|
5f4dc2a5fe |
167
core/modules/filters/json-ops.js
Normal file
167
core/modules/filters/json-ops.js
Normal file
@@ -0,0 +1,167 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/json-ops.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operators for JSON operations
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports["jsonget"] = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = options.wiki.getTiddlerDataCached(title);
|
||||
if(data) {
|
||||
var item = getDataItemValueAsStrings(data,operator.operands);
|
||||
if(item !== undefined) {
|
||||
results.push.apply(results,item);
|
||||
}
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports["jsonindexes"] = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = options.wiki.getTiddlerDataCached(title);
|
||||
if(data) {
|
||||
var item = getDataItemKeysAsStrings(data,operator.operands);
|
||||
if(item !== undefined) {
|
||||
results.push.apply(results,item);
|
||||
}
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports["jsontype"] = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = options.wiki.getTiddlerDataCached(title);
|
||||
if(data) {
|
||||
var item = getDataItemType(data,operator.operands);
|
||||
if(item !== undefined) {
|
||||
results.push(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return an array of the string representation of the values at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
function getDataItemValueAsStrings(data,indexes) {
|
||||
// Get the item
|
||||
var item = getDataItem(data,indexes);
|
||||
// Return the item as a string
|
||||
return convertDataItemValueToStrings(item);
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return an array of the string representation of the keys of the item at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
function getDataItemKeysAsStrings(data,indexes) {
|
||||
// Get the item
|
||||
var item = getDataItem(data,indexes);
|
||||
// Return the item keys as a string
|
||||
return convertDataItemKeysToStrings(item);
|
||||
}
|
||||
|
||||
/*
|
||||
Return an array of the string representation of the values of a data item, or "undefined" if the item is undefined
|
||||
*/
|
||||
function convertDataItemValueToStrings(item) {
|
||||
// Return the item as a string
|
||||
if(item === undefined) {
|
||||
return item;
|
||||
}
|
||||
if(typeof item === "object") {
|
||||
if(item === null) {
|
||||
return ["null"];
|
||||
}
|
||||
var results = [];
|
||||
if($tw.utils.isArray(item)) {
|
||||
$tw.utils.each(item,function(value) {
|
||||
results.push.apply(results,convertDataItemValueToStrings(value));
|
||||
});
|
||||
return results;
|
||||
} else {
|
||||
$tw.utils.each(Object.keys(item).sort(),function(key) {
|
||||
results.push.apply(results,convertDataItemValueToStrings(item[key]));
|
||||
});
|
||||
return results;
|
||||
}
|
||||
}
|
||||
return [item.toString()];
|
||||
}
|
||||
|
||||
/*
|
||||
Return an array of the string representation of the keys of a data item, or "undefined" if the item is undefined
|
||||
*/
|
||||
function convertDataItemKeysToStrings(item) {
|
||||
// Return the item as a string
|
||||
if(item === undefined) {
|
||||
return item;
|
||||
} else if(typeof item === "object") {
|
||||
if(item === null) {
|
||||
return [];
|
||||
}
|
||||
var results = [];
|
||||
if($tw.utils.isArray(item)) {
|
||||
for(var i=0; i<item.length; i++) {
|
||||
results.push(i.toString());
|
||||
}
|
||||
return results;
|
||||
} else {
|
||||
$tw.utils.each(Object.keys(item).sort(),function(key) {
|
||||
results.push(key);
|
||||
});
|
||||
return results;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function getDataItemType(data,indexes) {
|
||||
// Get the item
|
||||
var item = getDataItem(data,indexes);
|
||||
// Return the item type
|
||||
if(item === undefined) {
|
||||
return item;
|
||||
} else if(item === null) {
|
||||
return "null";
|
||||
} else if($tw.utils.isArray(item)) {
|
||||
return "array";
|
||||
} else if(typeof item === "object") {
|
||||
return "object";
|
||||
} else {
|
||||
return typeof item;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return the value at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
function getDataItem(data,indexes) {
|
||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||
return data;
|
||||
}
|
||||
// Get the item
|
||||
var item = data;
|
||||
for(var i=0; i<indexes.length; i++) {
|
||||
if(item !== undefined) {
|
||||
item = item[indexes[i]];
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
82
editions/test/tiddlers/tests/test-json-filters.js
Normal file
82
editions/test/tiddlers/tests/test-json-filters.js
Normal file
@@ -0,0 +1,82 @@
|
||||
/*\
|
||||
title: test-json-filters.js
|
||||
type: application/javascript
|
||||
tags: [[$:/tags/test-spec]]
|
||||
|
||||
Tests the JSON filters.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/* jslint node: true, browser: true */
|
||||
/* eslint-env node, browser, jasmine */
|
||||
/* eslint no-mixed-spaces-and-tabs: ["error", "smart-tabs"]*/
|
||||
/* global $tw, require */
|
||||
"use strict";
|
||||
|
||||
describe("json filter tests", function() {
|
||||
|
||||
var wiki = new $tw.Wiki();
|
||||
var tiddlers = [{
|
||||
title: "First",
|
||||
text: '{"a":"one","b":"","c":1.618,"d": {"e": "four","f": ["five","six",true,false,null]}}',
|
||||
type: "application/json"
|
||||
},{
|
||||
title: "Second",
|
||||
text: '["une","deux","trois"]',
|
||||
type: "application/json"
|
||||
}];
|
||||
wiki.addTiddlers(tiddlers);
|
||||
|
||||
it("should support the getindex operator", function() {
|
||||
expect(wiki.filterTiddlers("[[First]getindex[b]]")).toEqual([]);
|
||||
});
|
||||
|
||||
it("should support the jsonget operator", function() {
|
||||
expect(wiki.filterTiddlers("[[First]jsonget[]]")).toEqual(["one","","1.618","four","five","six","true","false","null"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonget[a]]")).toEqual(["one"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonget[b]]")).toEqual([""]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonget[d]]")).toEqual(["four","five","six","true","false","null"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonget[d],[e]]")).toEqual(["four"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonget[d],[f]]")).toEqual(["five","six","true","false","null"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonget[d],[f],[0]]")).toEqual(["five"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonget[d],[f],[1]]")).toEqual(["six"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonget[d],[f],[2]]")).toEqual(["true"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonget[d],[f],[3]]")).toEqual(["false"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonget[d],[f],[4]]")).toEqual(["null"]);
|
||||
});
|
||||
|
||||
it("should support the jsonindexes operator", function() {
|
||||
expect(wiki.filterTiddlers("[[Second]jsonindexes[]]")).toEqual(["0","1","2"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonindexes[]]")).toEqual(["a","b","c","d"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonindexes[a]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonindexes[b]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonindexes[d]]")).toEqual(["e","f"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonindexes[d],[e]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonindexes[d],[f]]")).toEqual(["0","1","2","3","4"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonindexes[d],[f],[0]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonindexes[d],[f],[1]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonindexes[d],[f],[2]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonindexes[d],[f],[3]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[[First]jsonindexes[d],[f],[4]]")).toEqual([]);
|
||||
});
|
||||
|
||||
it("should support the jsontype operator", function() {
|
||||
expect(wiki.filterTiddlers("[[First]jsontype[]]")).toEqual(["object"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsontype[a]]")).toEqual(["string"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsontype[b]]")).toEqual(["string"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsontype[c]]")).toEqual(["number"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsontype[d]]")).toEqual(["object"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsontype[d],[e]]")).toEqual(["string"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsontype[d],[f]]")).toEqual(["array"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsontype[d],[f],[0]]")).toEqual(["string"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsontype[d],[f],[1]]")).toEqual(["string"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsontype[d],[f],[2]]")).toEqual(["boolean"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsontype[d],[f],[3]]")).toEqual(["boolean"]);
|
||||
expect(wiki.filterTiddlers("[[First]jsontype[d],[f],[4]]")).toEqual(["null"]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
87
editions/tw5.com/tiddlers/JSON in TiddlyWiki.tid
Normal file
87
editions/tw5.com/tiddlers/JSON in TiddlyWiki.tid
Normal file
@@ -0,0 +1,87 @@
|
||||
created: 20220406163813574
|
||||
modified: 20220408112300157
|
||||
tags: Features
|
||||
title: JSON in TiddlyWiki
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
!! Introduction
|
||||
|
||||
JSON (~JavaScript Object Notation) is a standardised text representation for data structures that is widely used for the storage and transfer of data.
|
||||
|
||||
JSON is used in several different contexts in TiddlyWiki. For example:
|
||||
|
||||
* Tiddlers are represented as JSON data within TiddlyWiki HTML files
|
||||
* Groups of tiddlers can be [[exported|How to export tiddlers]] and [[imported|Importing Tiddlers]] as JSON files
|
||||
* Plugin tiddlers store their constituent shadow tiddlers as JSON data
|
||||
* The client-server configuration uses JSON messages to communicate between the client and the server
|
||||
* Arbitrary JSON data within DataTiddlers can be processed and manipulated using a set of filter operators and action widgets
|
||||
|
||||
!! About JSON
|
||||
|
||||
The technical description of JSON at the official website https://json.org/ is terse. Here we summarise the main features.
|
||||
|
||||
JSON supports two basic data structures:
|
||||
|
||||
''Arrays'' are lists of items. The items are identified by their numeric index (starting at zero)
|
||||
|
||||
An example of an array is:
|
||||
|
||||
```
|
||||
["one","two","three\"four"]
|
||||
```
|
||||
|
||||
Note the following features of arrays:
|
||||
|
||||
* The array is signified by square brackets surrounding the list of items
|
||||
* Each item is a string in double quotes. Double quotes can be included within the strings by preceding them with a backslash (`\`)
|
||||
* The items are separated by commas
|
||||
|
||||
''Objects'' are collections of name/value pairs. Each item is a value that is identified by a unique name
|
||||
|
||||
An example of an object is:
|
||||
|
||||
```
|
||||
{
|
||||
"first": "This is the first value",
|
||||
"second": "This is the second value",
|
||||
"third": "This is the third value"
|
||||
}
|
||||
```
|
||||
|
||||
Note the following features of objects:
|
||||
|
||||
* The object is signified by curly braces surrounding the list of name/value pairs
|
||||
* Each name/value pair consists of the name in double quotes, a colon, and then the value
|
||||
* The name/value pairs are separated by commas
|
||||
|
||||
The examples above all show string values. JSON actually supports several different types of value. Any of these types can be used as a value:
|
||||
|
||||
* String values, as shown above
|
||||
* Numeric values, represented as signed decimals such as `1`, `3.14`. Exponential notation can also be used e.g. `-1E10`
|
||||
* Boolean values, represented by the keywords `true` and `false`
|
||||
* The special value `null`, which is often used to represent data that is missing or incomplete
|
||||
* Objects and arrays are also values, allowing complex nested structures to be represented
|
||||
|
||||
!! Examples
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
!! Working with Data Tiddlers
|
||||
|
||||
* Reading data from JSON tiddlers
|
||||
* Constructing JSON tiddlers
|
||||
* Modifying JSON tiddlers
|
||||
|
||||
[[jsonstringify Operator]]
|
||||
|
||||
|
||||
[[jsontiddler Macro]]
|
||||
[[jsontiddlers Macro]]
|
||||
|
||||
JSONTiddlerWidget
|
||||
|
||||
[[JSONTiddlers]]
|
||||
|
||||
[[TiddlyWeb JSON tiddler format]]
|
||||
@@ -6,6 +6,33 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
See [[JSON in TiddlyWiki]] for an overview of using JSON in TiddlyWiki.
|
||||
|
||||
!! Introduction
|
||||
|
||||
The following examples assume the following JSON data structure is stored in a data tiddler called "foobar" with the type `application/json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"a": "one",
|
||||
"b": "",
|
||||
"c": "three",
|
||||
"d": {
|
||||
"e": "four",
|
||||
"f": [
|
||||
"five",
|
||||
"six",
|
||||
true,
|
||||
false,
|
||||
null
|
||||
],
|
||||
"g": {
|
||||
"x": "max",
|
||||
"y": "may",
|
||||
"z": "maize"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!! Text References for Accessing JSON Data
|
||||
|
||||
[[Text references|TextReference]] are a simple shortcut syntax to look up the value of a named property. For example, if a [[DictionaryTiddler|DictionaryTiddlers]] called `MonthDays` contains:
|
||||
@@ -23,3 +50,74 @@ The same is true if `MonthDays` is a [[JSONTiddler|JSONTiddlers]] with the follo
|
||||
```
|
||||
{"oct":31,"nov":30,"dec":31}
|
||||
```
|
||||
|
||||
!! Operators for Reading JSON Data
|
||||
|
||||
Values are identified by a sequence of indexes. For example, the value at `[a]` is `one`, and the value at `[d][f][0]` is `five`.
|
||||
|
||||
The new operators use multiple operands to specify the indexes:
|
||||
|
||||
```
|
||||
[[foobar]jsonget[a]] --> "one"
|
||||
[[foobar]jsonget[d],[e]] --> "four"
|
||||
[[foobar]jsonget[d],[f],[0]] --> "five"
|
||||
```
|
||||
|
||||
Indexes can be dynamically composed from variables and transclusions:
|
||||
|
||||
```
|
||||
[[foobar]jsonget<variable>,{!!field},[0]]
|
||||
```
|
||||
|
||||
Boolean values and null are returned as normal strings. The [[jsontype Operator]] returns a string identifying the original type. Thus:
|
||||
|
||||
```
|
||||
[[foobar]jsontype[a]] --> "string"
|
||||
[[foobar]jsontype[d]] --> "object"
|
||||
[[foobar]jsontype[d],[f]] --> "array"
|
||||
[[foobar]jsontype[d],[f],[2]] --> "boolean"
|
||||
```
|
||||
|
||||
Using the [[jsonget Operator]] to retrieve an object or an array returns a list of all the values. For example:
|
||||
|
||||
```
|
||||
[[foobar]jsonget[d],[f]] --> "five","six","true","false","null"
|
||||
[[foobar]jsonget[d],[g]] --> "max", "may", "maize"
|
||||
```
|
||||
|
||||
The [[jsonindexes Operator]] retrieves the corresponding indexes:
|
||||
|
||||
```
|
||||
[[foobar]jsonindexes[d],[f]] --> "0", "1", "2", "3", "4"
|
||||
[[foobar]jsonindexes[d],[g]] --> "x", "y", "z"
|
||||
```
|
||||
|
||||
The behaviour when retrieving an object or array that contains values that are themselves objects or arrays may be confusing: the object is read recursively as a list of values. For example:
|
||||
|
||||
```
|
||||
[[foobar]jsonget[d]] --> "four", "five", "six", "true", "false", "null", "max", "may", "maize"
|
||||
```
|
||||
|
||||
A further subtlety is that the special case of a single blank operand is used to identify the root object. Thus:
|
||||
|
||||
```
|
||||
[[foobar]jsonindexes[]] --> "a", "b", "c", "d"
|
||||
```
|
||||
|
||||
An example of using a list widget to iterate through the properties of an array within a JSON object:
|
||||
|
||||
```
|
||||
<$list filter="[[foobar]jsonindexes[d][f]]">
|
||||
<div>
|
||||
<$text text=<<currentTiddler>>/>: <$text text={{{ [[foobar]jsonget[d][f]<currentTiddler>] }}}/>
|
||||
</div>
|
||||
</$list>
|
||||
|
||||
Prints:
|
||||
|
||||
0: five
|
||||
1: six
|
||||
2: true
|
||||
3: false
|
||||
4: null
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user