I am continually frustrated with JSON in TW. If I try hard enough, I can usually get things done, but it’s non-trivial.
You can do it with full paths to your nodes: [<myJSONstring>jsonset[grandpa],[mom],[me],[over21],[yes]]. But you need to set all intermediate nodes before you add a property to them. The above won’t work unless the object your JSON string represents already has a grandpa property, which has a mom property, which has a me property that is an object:
<$let myJSONstring='{"grandpa": {"mom": {"me": {"name": "Scott"}, "bro": {"name": "Michael"}}}}'>
<pre><code><$text text={{{[<myJSONstring>jsonset[grandpa],[mom],[me],[over21],[yes]] +[format:json[4]] }}} /></code></pre>
</$let>
yielding
{
"grandpa": {
"mom": {
"me": {
"name": "Scott",
"over21": "yes"
},
"bro": {
"name": "Michael"
}
}
}
}
But yes, that is awkward as hell.
This is because of what JSON actually is. It is not a data structure; instead it is a string representation of a data structure. That sounds subtle, but the point is important. Although tiddlers are pretty simple data structures (Hash Maps / Dictionaries), most everything else we deal with in TW is a string or a list of strings.
JSON was designed as a transport format: a way to share nested data structures between different systems. But working with JSON in programming languages usually involves parsing JSON into a more sophisticated data structure on receipt, manipulating that structure as needed, and serializing that data structure back into a string before passing it along. In TW, there’s more friction in this than in many languages. But even if there were no friction, the model would still involve converting from a string, making changes, and converting back.
Mostly to sharpen my TW-JSON skills, I tried this, and the results are not too bad:
<$button>Extract
<$action-createtiddler $basetitle="MyExtract" type="application/json" text="{}" >
<$let tid=<<createTiddler-title>> >
<$list filter=[tag[HelloThere]]>
<$action-setfield $tiddler=<<tid>> $field="text" $value={{{
[<tid>get[text]jsonextract[]]
+[jsonset:object{!!title}]
+[jsonset{!!title},[title],{!!title}]
+[jsonset{!!title},[tags],{!!tags}]
+[jsonset{!!title},[caption],{!!caption}]
+[format:json[4]]
}}} />
</$list>
<$action-navigate $to=<<tid>> />
</$let>
</$action-createtiddler>
</$button>
which yields this:
{
"A Gentle Guide to TiddlyWiki": {
"title": "A Gentle Guide to TiddlyWiki",
"tags": "HelloThere",
"caption": ""
},
"Discover TiddlyWiki": {
"title": "Discover TiddlyWiki",
"tags": "HelloThere",
"caption": ""
},
"Some of the things you can do with TiddlyWiki": {
"title": "Some of the things you can do with TiddlyWiki",
"tags": "HelloThere",
"caption": ""
},
"Ten reasons to switch to TiddlyWiki": {
"title": "Ten reasons to switch to TiddlyWiki",
"tags": "HelloThere",
"caption": ""
},
"Examples": {
"title": "Examples",
"tags": "HelloThere Community",
"caption": ""
},
"What happened to the original TiddlyWiki?": {
"title": "What happened to the original TiddlyWiki?",
"tags": "HelloThere",
"caption": ""
},
"Funding TiddlyWiki": {
"title": "Funding TiddlyWiki",
"tags": "About HelloThere",
"caption": ""
},
"Open Collective": {
"title": "Open Collective",
"tags": "About HelloThere",
"caption": ""
}
}
Obviously it would be easy to parameterize the filter used (here [tag[HelloThere]]. I’d have to think about how to do dynamic filters, or possibly use reduce, in order to change the list of fields to include (here title, tags, and caption.) But I’m sure it could be done.
But this is only for a simple, two-level structure. I have some ideas of how to make it simpler to build arbitrary JSON strings from simple parameters. I do it in JS all the time, and so I guess a JS operator might be enough. But I’m trying to figure out how to do it in wikitext.
Extract Tiddlers.tid (676 Bytes)