1====== JSON Data Definition Demo ======
2
3
4Here are some external files with recipes as JSON data:
5  * [[recipe_butter_cookie]] - pure JSON file.
6  * [[recipe_sweet_sauces]] - DokuWiki page with two JSON data objects inside %%<json>%% tags.
7
8
9===== JSON from single source =====
10
11==== Inline ====
12<code>
13<json path=inline display=all>
14{
15  "name": "Butter cookie",
16  "type": "cookie",
17  "Ingredients": {
18    "eggs": "3",
19    "flour": "500 g",
20    "sugar": "300 g",
21    "butter": "250 g"
22  }
23}
24</json>
25</code>
26
27<json path=inline display=all>
28{
29  "name": "Butter cookie",
30  "type": "cookie",
31  "Ingredients": {
32    "eggs": "3",
33    "flour": "500 g",
34    "sugar": "300 g",
35    "butter": "250 g"
36  }
37}
38</json>
39
40
41==== External JSON file ====
42In this case we have pure JSON external file [[recipe_butter_cookie]]. 'src' may be internal or external [[wiki:syntax#links|DokuWiki link]].
43<code>
44<json path=external_json src=recipe_butter_cookie display=all></json>
45</code>
46<json path=external_json src=recipe_butter_cookie display=all></json>
47
48
49==== External JSON file from internet ====
50Load JSON file from internet into our database (this may not work - depends on server settings):
51<code>
52<json path=external_json_internet src=https://duckduckgo.com/country.json display=all></json>
53</code>
54<json path=external_json_internet src=https://duckduckgo.com/country.json display=all></json>
55
56
57==== External Dokuwiki page ====
58Load JSON data from external DokuWiki page ([[recipe_sweet_sauces]]) with multiple %%<json>%% elements inside.
59<code>
60<json path=page_external src=recipe_sweet_sauces display=all></json>
61</code>
62<json path=page_external src=recipe_sweet_sauces display=all></json>
63
64
65==== External Dokuwiki page - specific element ====
66Specific %%<json>%% element inside the page can be addressed with ''#'' symbol. It corresponds to the id attribute of the remote %%<json>%% element.
67<code>
68<json path=page_ext_one_element src=recipe_sweet_sauces#ganache display=all></json>
69</code>
70<json path=page_ext_one_element src=recipe_sweet_sauces#ganache display=all></json>
71
72
73==== External file from query string ====
74'src_ext' attribute contains a name of the argument. Argument must be passed with the [[wp>Query string]] added to the link to this page.
75
76<code>
77<json path=query_string src_ext=json_recipe display=all></json>
78</code>
79<json path=query_string src_ext=json_recipe display=all></json>
80
81Recipe in query_string is currently for %$query_string.name%.
82
83If '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:
84<code>
85[[json_definition_demo?json_recipe=recipe_butter_cookie|JSON Data Definition Demo - Butter Cookie]]
86</code>
87
88Click this: [[json_definition_demo?json_recipe=recipe_butter_cookie#external_file_from_query_string|JSON Data Definition Demo - Butter Cookie]]
89
90Now 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 ''&''.
91
92It is possible to address specific %%<json>%% element in query string. However, ''#'' has special meaning in [[wp>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):
93<code>
94[[json_definition_demo?json_recipe=recipe_sweet_sauces%23ganache#external_file_from_query_string|JSON Data Definition Demo - Ganache]]
95</code>
96
97Click this: [[json_definition_demo?json_recipe=recipe_sweet_sauces%23ganache#external_file_from_query_string|JSON Data Definition Demo - Ganache]]
98
99
100==== Errors ====
101If there are errors, they are displayed in 'Errors' tab. For example, missing external file or wrong attributes and JSON syntax:
102<code>
103<json path=error src=recipe_nonexisted display=all></json>
104<json xyz></json>
105<json>abc</json>
106</code>
107<json path=error src=recipe_nonexisted display=all></json>
108<json xyz></json>
109<json>abc</json>
110
111
112===== Combine JSON data from multiple sources =====
113In 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.
114
115==== Replace or add to existing data ====
116<code>
117<json path=replace src=recipe_butter_cookie display=all></json>
118<json path=replace display=all>
119{
120  "name": "Butter cookie enhanced",
121  "Ingredients": {
122    "sugar": "350 g",
123    "chocolate chips": "100 g"
124  }
125}
126</json>
127</code>
128
129<json path=replace src=recipe_butter_cookie display=all></json>
130<json path=replace display=all>
131{
132  "name": "Butter cookie enhanced",
133  "Ingredients": {
134    "sugar": "350 g",
135    "chocolate chips": "100 g"
136  }
137}
138</json>
139
140As 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")
141
142The same is achieved with the combined %%<json>%% element belov:
143<code>
144<json path=replace2 src=recipe_butter_cookie display=all>
145{
146  "name": "Butter cookie enhanced",
147  "Ingredients": {
148    "sugar": "350 g",
149    "chocolate chips": "100 g"
150  }
151}
152</json>
153</code>
154<json path=replace2 src=recipe_butter_cookie display=all>
155{
156  "name": "Butter cookie enhanced",
157  "Ingredients": {
158    "sugar": "350 g",
159    "chocolate chips": "100 g"
160  }
161}
162</json>
163
164
165==== Load data to the specific path ====
166With the 'path' attribute you can specify a path, where to load new data.
167<code>
168<json path=path src=recipe_butter_cookie display=all></json>
169<json path=path.Ingredients display=all>
170{
171  "sugar": "350 g",
172  "chocolate chips": "100 g"
173}
174</json>
175</code>
176
177<json path=path src=recipe_butter_cookie display=all></json>
178<json path=path.Ingredients display=all>
179{
180  "sugar": "350 g",
181  "chocolate chips": "100 g"
182}
183</json>
184
185
186==== Load specific part of data ====
187With the 'src_path' attribute you can specify a path on data referenced by 'src'. Only that part of data will be loaded.
188<code>
189<json path=partly display=all>
190{
191  "name": "My cookie"
192}
193</json>
194<json path=partly."my ingredients" src=recipe_butter_cookie src_path=Ingredients display=all></json>
195<json path=partly display=combined*></json>
196</code>
197
198<json path=partly display=all>
199{
200  "name": "My cookie"
201}
202</json>
203<json path=partly."my ingredients" src=recipe_butter_cookie src_path=Ingredients display=all></json>
204<json path=partly display=combined*></json>
205
206
207==== Delete existing data ====
208Use ''-'' 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.
209
210<code>
211<json path=del src=recipe_butter_cookie display=all></json>
212<json path=-del.Ingredients.butter display=all></json>
213<json path=del.Ingredients display=all>
214{
215  "margarine": "250 g"
216}
217</json>
218<json path=del display=combined*></json>
219</code>
220
221<json path=del src=recipe_butter_cookie display=all></json>
222<json path=-del.Ingredients.butter display=all></json>
223<json path=del.Ingredients display=all>
224{
225  "margarine": "250 g"
226}
227</json>
228<json path=del display=combined*></json>
229
230Another example:
231
232<code>
233<json path=del2 src=recipe_butter_cookie display=all></json>
234<json path=-del2.Ingredients display=all>
235{
236  "eggs": "3",
237  "flour": "500 g",
238  "sugar": "300 g",
239  "margarine": "250 g"
240}
241</json>
242<json path=del2 display=combined*></json>
243</code>
244
245<json path=del2 src=recipe_butter_cookie display=all></json>
246<json path=-del2.Ingredients display=all>
247{
248  "eggs": "3",
249  "flour": "500 g",
250  "sugar": "300 g",
251  "margarine": "250 g"
252}
253</json>
254<json path=del2 display=combined*></json>
255
256
257==== Stack data ====
258If you want to push data into the next free element of the array, you can use ''[]'' operator on the end of the 'path' attribute.
259<code>
260<json path=stack[] src=recipe_butter_cookie display=all></json>
261<json path=stack[] src=recipe_sweet_sauces#caramel display=all></json>
262<json path=stack[] src=recipe_sweet_sauces#ganache display=all></json>
263</code>
264
265<json path=stack[] src=recipe_butter_cookie display=all></json>
266<json path=stack[] src=recipe_sweet_sauces#caramel display=all></json>
267<json path=stack[] src=recipe_sweet_sauces#ganache display=all></json>
268
269[[https://cowburn.info/2010/04/30/glob-patterns/|Wildcard]] characters can also be used for the file name:
270<code>
271<json path=stack2[] src=recipe_* display=all></json>
272</code>
273
274<json path=stack2[] src=recipe_* display=all></json>
275
276However, data inside two files with recipes does not have the same format, so combined data is probably not what we want.
277
278
279==== Load data recursively ====
280Make again 'Butter Cookie Enhanced', which is based on 'Butter Cookie':
281<code>
282<json id=recursive path=recursive src=recipe_butter_cookie display=all>
283{
284  "name": "Butter cookie enhanced",
285  "Ingredients": {
286    "sugar": "350 g",
287    "chocolate chips": "100 g"
288  }
289}
290</json>
291</code>
292<json id=recursive_2 path=recursive src=recipe_butter_cookie display=all>
293{
294  "name": "Butter cookie enhanced",
295  "Ingredients": {
296    "sugar": "350 g",
297    "chocolate chips": "100 g"
298  }
299}
300</json>
301
302Then we make a "Butter cookie super enhanced", which is based on 'Butter Cookie Enhanced', which is based on 'Butter Cookie':
303<code>
304<json path=recursive2 src=json_definition_demo#recursive display=all>
305{
306  "name": "Butter cookie super enhanced",
307  "Ingredients": {
308    "caramel": "50 g"
309  }
310}
311</json>
312</code>
313<json path=recursive2 src=json_definition_demo#recursive display=all>
314{
315  "name": "Butter cookie super enhanced",
316  "Ingredients": {
317    "caramel": "50 g"
318  }
319}
320</json>
321
322It 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:
323
324<code>
325<json id=recursive3 path=recursive3[] src=json_definition_demo#recursive3 display=all>
326{
327  "name": "Butter cookie super enhanced",
328  "Ingredients": {
329    "caramel": "50 g"
330  }
331}
332</json>
333</code>
334<json id=recursive3_2 path=recursive3[] src=json_definition_demo#recursive3 display=all>
335{
336  "name": "Butter cookie super enhanced",
337  "Ingredients": {
338    "caramel": "50 g"
339  }
340}
341</json>
342
343
344===== Build inline JSON from existing data =====
345Inside 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:
346
347<code>
348<json path=sale>{
349    "Renault": {
350        "cars": %$cars[(0 == renault)]%,
351        "salesman": %$salesmen.james_s%
352    },
353    "other": {
354        "cars": %$cars[(2 == black or 2 == red or 2 == white)]%,
355        "salesman": %$salesmen.george_w%
356    }
357}</json>
358%$sale#code#%
359</code>
360
361<json path=cars>[
362    ["BMW",     2016, "black"],
363    ["Renault", 2017, "yellow"],
364    ["Renault", 2018, "green"],
365    ["Tesla",   2018, "white"]
366]</json>
367
368<json path=salesmen>{
369    "james_s": {"name": "James", "surname": "Smith"},
370    "george_w": {"name": "George", "surname": "Wright", "middle name": "T."}
371}</json>
372
373<json path=sale>{
374    "Renault": {
375        "cars": %$cars[(0 == renault)]%,
376        "salesman": %$salesmen.james_s%
377    },
378    "other": {
379        "cars": %$cars[(2 == black or 2 == red or 2 == white)]%,
380        "salesman": %$salesmen.george_w%
381    }
382}</json>
383%$sale#code#%
384
385
386===== Reuse existing data with 'src' attribute =====
387'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.
388<code>
389<json path=reuse src=%$inline% display=all>
390{
391  "name": "Cloned butter cookie",
392}
393</json>
394</code>
395
396<json path=reuse src=%$inline% display=all>
397{
398  "name": "Cloned butter cookie"
399}
400</json>
401