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