Table of Contents
JSON Data Definition Demo
Here are some external files with recipes as JSON data:
- recipe_butter_cookie - pure JSON file.
- recipe_sweet_sauces - DokuWiki page with two JSON data objects inside <json> tags.
JSON from single source
Inline
<json path=inline display=all> { "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } } </json>
null
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
- element: json, path: inline, inline data
External JSON file
In this case we have pure JSON external file recipe_butter_cookie. 'src' may be internal or external DokuWiki link.
<json path=external_json src=recipe_butter_cookie display=all></json>
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
- element: json, path: external_json, external data (from path: )
- internal file: json:recipe_butter_cookie, JSON file
External JSON file from internet
Load JSON file from internet into our database (this may not work - depends on server settings):
<json path=external_json_internet src=https://duckduckgo.com/country.json display=all></json>
{ "country": "SI" }
{ "country": "SI" }
- element: json, path: external_json_internet, external data (from path: )
- external file: https://duckduckgo.com/country.json, JSON file
External Dokuwiki page
Load JSON data from external DokuWiki page (recipe_sweet_sauces) with multiple <json> elements inside.
<json path=page_external src=recipe_sweet_sauces display=all></json>
[ { "name": "Caramel sauce", "type": "sweet sauce", "Ingredients": { "sugar": "200 g", "water": "2 spoons", "cream": "250 ml" } }, { "name": "Ganache", "type": "sweet sauce", "Ingredients": { "chocolate": "250 g", "cream": "250 ml" } } ]
[ { "name": "Caramel sauce", "type": "sweet sauce", "Ingredients": { "sugar": "200 g", "water": "2 spoons", "cream": "250 ml" } }, { "name": "Ganache", "type": "sweet sauce", "Ingredients": { "chocolate": "250 g", "cream": "250 ml" } } ]
- element: json, path: page_external, external data (from path: )
- internal file: json:recipe_sweet_sauces
- element: json, id: caramel, path: [], inline data
- element: json, id: ganache, path: [], inline data
External Dokuwiki page - specific element
Specific <json> element inside the page can be addressed with #
symbol. It corresponds to the id attribute of the remote <json> element.
<json path=page_ext_one_element src=recipe_sweet_sauces#ganache display=all></json>
{ "name": "Ganache", "type": "sweet sauce", "Ingredients": { "chocolate": "250 g", "cream": "250 ml" } }
{ "name": "Ganache", "type": "sweet sauce", "Ingredients": { "chocolate": "250 g", "cream": "250 ml" } }
- element: json, path: page_ext_one_element, external data (from path: )
- internal file: json:recipe_sweet_sauces#ganache
- element: json, id: ganache, path: [], inline data
External file from query string
'src_ext' attribute contains a name of the argument. Argument must be passed with the Query string added to the link to this page.
<json path=query_string src_ext=json_recipe display=all></json>
{ "name": "Ganache", "type": "sweet sauce", "Ingredients": { "chocolate": "250 g", "cream": "250 ml" } }
{ "name": "Ganache", "type": "sweet sauce", "Ingredients": { "chocolate": "250 g", "cream": "250 ml" } }
- element: json, path: query_string, external data (from path: )
- internal file: json:recipe_sweet_sauces#ganache
- element: json, id: ganache, path: [], inline data
Recipe in query_string is currently for Ganache.
If 'query_string.name' is not defined and there is tag with Errors, click on it. It says, that 'query srting for json_recipe not defined'. This page should be loaded from link, which includes query string, like this:
[[json_definition_demo?json_recipe=recipe_butter_cookie|JSON Data Definition Demo - Butter Cookie]]
Click this: JSON Data Definition Demo - Butter Cookie
Now the page should reload with data as defined in the link. No Errors should show. Any link can be used in the Query string. Key must be prepended with 'json_'. Multiple key=value combinations may be in the Query string, separated by &
.
It is possible to address specific <json> element in query string. However, #
has special meaning in URL and this sign can not be used as value of the argument. %23
must be used instead. For example, reload this page with data from <json id=ganache> element from 'recipe_sweet_sauces' and jump to this chapter (see title of current chapter):
[[json_definition_demo?json_recipe=recipe_sweet_sauces%23ganache#external_file_from_query_string|JSON Data Definition Demo - Ganache]]
Click this: JSON Data Definition Demo - Ganache
Errors
If there are errors, they are displayed in 'Errors' tab. For example, missing external file or wrong attributes and JSON syntax:
<json path=error src=recipe_nonexisted display=all></json> <json xyz></json> <json>abc</json>
null
null
- element: json, path: error, external data (from path: )
- internal file: json:recipe_nonexisted, ERROR: file not found
- element: json, path: , ERROR: attributes syntax at 4
- element: json, path: , ERROR: internal JSON Syntax error, inline data
Combine JSON data from multiple sources
In the background, there is a JSON array, which is empty on the beginning, when DokuWiki page starts loading. Then each <json> element on the page loads some data. If data are loaded to the same 'path', then they are combined, replaced or added somehow. Below are the rules with examples.
Replace or add to existing data
<json path=replace src=recipe_butter_cookie display=all></json> <json path=replace display=all> { "name": "Butter cookie enhanced", "Ingredients": { "sugar": "350 g", "chocolate chips": "100 g" } } </json>
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
- element: json, path: replace, external data (from path: )
- internal file: json:recipe_butter_cookie, JSON file
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
{ "name": "Butter cookie enhanced", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "350 g", "butter": "250 g", "chocolate chips": "100 g" } }
- element: json, path: replace, inline data
As you can see, data from the second <json> are added to the data from the first <json>. If necessary, data from the second <json> replace data from the first. (“sugar” in the example changes from “300 g” to “350 g”)
The same is achieved with the combined <json> element belov:
<json path=replace2 src=recipe_butter_cookie display=all> { "name": "Butter cookie enhanced", "Ingredients": { "sugar": "350 g", "chocolate chips": "100 g" } } </json>
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
{ "name": "Butter cookie enhanced", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "350 g", "butter": "250 g", "chocolate chips": "100 g" } }
- element: json, path: replace2, inline data, external data (from path: )
- internal file: json:recipe_butter_cookie, JSON file
Load data to the specific path
With the 'path' attribute you can specify a path, where to load new data.
<json path=path src=recipe_butter_cookie display=all></json> <json path=path.Ingredients display=all> { "sugar": "350 g", "chocolate chips": "100 g" } </json>
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
- element: json, path: path, external data (from path: )
- internal file: json:recipe_butter_cookie, JSON file
{ "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" }
{ "eggs": "3", "flour": "500 g", "sugar": "350 g", "butter": "250 g", "chocolate chips": "100 g" }
- element: json, path: path.Ingredients, inline data
Load specific part of data
With the 'src_path' attribute you can specify a path on data referenced by 'src'. Only that part of data will be loaded.
<json path=partly display=all> { "name": "My cookie" } </json> <json path=partly."my ingredients" src=recipe_butter_cookie src_path=Ingredients display=all></json> <json path=partly display=combined*></json>
null
{ "name": "My cookie" }
- element: json, path: partly, inline data
{ "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" }
{ "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" }
- element: json, path: partly.my ingredients, external data (from path: Ingredients)
- internal file: json:recipe_butter_cookie, JSON file
Delete existing data
Use -
in the beginning of the 'path' attribute do clear previous data and then load new. -
operator simply remove previous data on the path. For example, you can only remove a part of previously defined data with it.
<json path=del src=recipe_butter_cookie display=all></json> <json path=-del.Ingredients.butter display=all></json> <json path=del.Ingredients display=all> { "margarine": "250 g" } </json> <json path=del display=combined*></json>
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
- element: json, path: del, external data (from path: )
- internal file: json:recipe_butter_cookie, JSON file
null
null
- element: json, path: -del.Ingredients.butter
{ "eggs": "3", "flour": "500 g", "sugar": "300 g" }
{ "eggs": "3", "flour": "500 g", "sugar": "300 g", "margarine": "250 g" }
- element: json, path: del.Ingredients, inline data
Another example:
<json path=del2 src=recipe_butter_cookie display=all></json> <json path=-del2.Ingredients display=all> { "eggs": "3", "flour": "500 g", "sugar": "300 g", "margarine": "250 g" } </json> <json path=del2 display=combined*></json>
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
- element: json, path: del2, external data (from path: )
- internal file: json:recipe_butter_cookie, JSON file
null
{ "eggs": "3", "flour": "500 g", "sugar": "300 g", "margarine": "250 g" }
- element: json, path: -del2.Ingredients, inline data
Stack data
If you want to push data into the next free element of the array, you can use []
operator on the end of the 'path' attribute.
<json path=stack[] src=recipe_butter_cookie display=all></json> <json path=stack[] src=recipe_sweet_sauces#caramel display=all></json> <json path=stack[] src=recipe_sweet_sauces#ganache display=all></json>
[ { "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } } ]
[ { "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } } ]
- element: json, path: stack[], external data (from path: )
- internal file: json:recipe_butter_cookie, JSON file
[ { "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }, { "name": "Caramel sauce", "type": "sweet sauce", "Ingredients": { "sugar": "200 g", "water": "2 spoons", "cream": "250 ml" } } ]
[ { "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }, { "name": "Caramel sauce", "type": "sweet sauce", "Ingredients": { "sugar": "200 g", "water": "2 spoons", "cream": "250 ml" } } ]
- element: json, path: stack[], external data (from path: )
- internal file: json:recipe_sweet_sauces#caramel
- element: json, id: caramel, path: [], inline data
[ { "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }, { "name": "Caramel sauce", "type": "sweet sauce", "Ingredients": { "sugar": "200 g", "water": "2 spoons", "cream": "250 ml" } }, { "name": "Ganache", "type": "sweet sauce", "Ingredients": { "chocolate": "250 g", "cream": "250 ml" } } ]
[ { "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }, { "name": "Caramel sauce", "type": "sweet sauce", "Ingredients": { "sugar": "200 g", "water": "2 spoons", "cream": "250 ml" } }, { "name": "Ganache", "type": "sweet sauce", "Ingredients": { "chocolate": "250 g", "cream": "250 ml" } } ]
- element: json, path: stack[], external data (from path: )
- internal file: json:recipe_sweet_sauces#ganache
- element: json, id: ganache, path: [], inline data
Wildcard characters can also be used for the file name:
<json path=stack2[] src=recipe_* display=all></json>
[ { "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }, [ { "name": "Caramel sauce", "type": "sweet sauce", "Ingredients": { "sugar": "200 g", "water": "2 spoons", "cream": "250 ml" } }, { "name": "Ganache", "type": "sweet sauce", "Ingredients": { "chocolate": "250 g", "cream": "250 ml" } } ] ]
[ { "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }, [ { "name": "Caramel sauce", "type": "sweet sauce", "Ingredients": { "sugar": "200 g", "water": "2 spoons", "cream": "250 ml" } }, { "name": "Ganache", "type": "sweet sauce", "Ingredients": { "chocolate": "250 g", "cream": "250 ml" } } ] ]
- element: json, path: stack2[], external data (from path: )
- internal file: json:recipe_butter_cookie, JSON file
- internal file: json:recipe_sweet_sauces
- element: json, id: caramel, path: [], inline data
- element: json, id: ganache, path: [], inline data
However, data inside two files with recipes does not have the same format, so combined data is probably not what we want.
Load data recursively
Make again 'Butter Cookie Enhanced', which is based on 'Butter Cookie':
<json id=recursive path=recursive src=recipe_butter_cookie display=all> { "name": "Butter cookie enhanced", "Ingredients": { "sugar": "350 g", "chocolate chips": "100 g" } } </json>
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
{ "name": "Butter cookie enhanced", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "350 g", "butter": "250 g", "chocolate chips": "100 g" } }
- element: json, id: recursive_2, path: recursive, inline data, external data (from path: )
- internal file: json:recipe_butter_cookie, JSON file
Then we make a “Butter cookie super enhanced”, which is based on 'Butter Cookie Enhanced', which is based on 'Butter Cookie':
<json path=recursive2 src=json_definition_demo#recursive display=all> { "name": "Butter cookie super enhanced", "Ingredients": { "caramel": "50 g" } } </json>
{ "name": "Butter cookie enhanced", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "350 g", "butter": "250 g", "chocolate chips": "100 g" } }
{ "name": "Butter cookie super enhanced", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "350 g", "butter": "250 g", "chocolate chips": "100 g", "caramel": "50 g" } }
- element: json, path: recursive2, inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive
- element: json, id: recursive, path: recursive, inline data, external data (from path: )
- internal file: json:recipe_butter_cookie, JSON file
It works perfectly. Recursion depth is controlled by configuration setting 'src_recursive'. By default it is limited to 30 levels and it prevents page crash, if someone makes something stupid, like cyclic reference:
<json id=recursive3 path=recursive3[] src=json_definition_demo#recursive3 display=all> { "name": "Butter cookie super enhanced", "Ingredients": { "caramel": "50 g" } } </json>
[ { "name": "Butter cookie super enhanced", "Ingredients": { "caramel": "50 g" } } ]
[ { "name": "Butter cookie super enhanced", "Ingredients": { "caramel": "50 g" } }, { "name": "Butter cookie super enhanced", "Ingredients": { "caramel": "50 g" } } ]
- element: json, id: recursive3_2, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data (from path: )
- internal file: json:json_definition_demo#recursive3
- element: json, id: recursive3, path: recursive3[], inline data, external data
- internal file: json:json_definition_demo, ERROR: recursion limit reached
Build inline JSON from existing data
Inside inline json we can use %$ path [( row_filter )]( filter )%
syntax, which will be replaced by data from existing JSON database. First we define database for 'cars' and 'salesmen'. Then use those data for building 'sale' database, as shown below:
<json path=sale>{ "Renault": { "cars": %$cars[(0 == renault)]%, "salesman": %$salesmen.james_s% }, "other": { "cars": %$cars[(2 == black or 2 == red or 2 == white)]%, "salesman": %$salesmen.george_w% } }</json> %$sale#code#%
- element: json, path: cars, inline data
- element: json, path: salesmen, inline data
- element: json, path: sale, inline data
{ "Renault": { "cars": [ [ "Renault", 2017, "yellow" ], [ "Renault", 2018, "green" ] ], "salesman": { "name": "James", "surname": "Smith" } }, "other": { "cars": [ [ "BMW", 2016, "black" ], [ "Tesla", 2018, "white" ] ], "salesman": { "name": "George", "surname": "Wright", "middle name": "T." } } }
Reuse existing data with 'src' attribute
'src' attribute is not only used for file path, it can also contain JSON data. For example, existing data from JSON database can be “cloned” with 'src' attribute. Only specific parts can then be changed with inline JSON.
<json path=reuse src=%$inline% display=all> { "name": "Cloned butter cookie", } </json>
{ "name": "Butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
{ "name": "Cloned butter cookie", "type": "cookie", "Ingredients": { "eggs": "3", "flour": "500 g", "sugar": "300 g", "butter": "250 g" } }
- element: json, path: reuse, inline data, external data (from path: )
- JSON code from 'src' attribute