Open xcazin opened 4 years ago
When I first started this, it was to marry XSLT with Tiddlywiki, but I abandoned that, because between <$xpath> and all of tiddlywiki's powers, there wasn't much more needed for xslt. I think you can implement something like
I'll describe how I'd implement it, and you let me know whether it works for you, doesn't work, or how tw5-xml should better address it. I'll count on your input, because for me, if I get around to using
Let's say we've got a D&D schema which has a block like this:
<character>
<name>Higgins</name>
<class>Rogue</class>
...
</character>
This block can show up all over your schema, either under <players>
, or <NPCs>
, or even under <character>
as a character's cohort or familiar.
Now I'm rendering this xml document in a tiddler.
! <$xpath value-of="@title" />
!!! Players
<$xpath for-each="/DnD/players">
<$xpath for-each="character">
<!-- Render my character -->
</$xpath>
</$xpath>
!!! Places
<$xpath for-each="/DnD/location">
!!!! People leaving in <$xpath value-of="@name" />
<$xpath for-each="character">
<!-- Render my character... again -->
</$xpath>
</$xpath>
It's wasteful, so I'd make a template tiddler for character:
title: Template/Character
!!!! <$xpath value-of="name" />
* Class: <$xpath value-of="class" />
* Lvl: <$xpath value-of="class/@level" />
...
Then,
<$xpath for-each "NPC/character" template="Templates/Character" />
We're partway there, but what if we have other schema blocks, like <$monster>
, or <$items>
. I don't want:
<$xpath for-each "NPC/character" template="Templates/Character" />
<$xpath for-each "NPC/monster" template="Templates/Monster" />
<$xpath for-each "NPC/items" template="Templates/Items" />
...all over my code. So I define a tag and a field. Here is my new Templates/Character:
title: Templates/Character
tag: [[XSLT Template]]
match: character
!!!! <$xpath value-of="name" />
* Class: <$xpath value-of="class" />
* Lvl: <$xpath value-of="class/@level" />
...
Then I define a global macro:
title: Macros/apply-templates
tags: $:/tags/Macro
\define apply-templates(tag: "XSLT Template")
<$list variable="template" filter="[tag<__tag__>]">
<$set name="match" tiddler=<<template>> field="match">
<$xpath for-each=<<match>> >
<$transclude tiddler=<<template>> mode="block" />
</$xpath>
</$set>
</$list>
\end
Now let's look at my main tiddler again:
! <$xpath value-of="@title" />
!!! Players
<$xpath for-each="/DnD/players">
<<apply-templates>>
</$xpath>
!!! Places
<$xpath for-each="/DnD/location">
!!!! People leaving in <$xpath value-of="@name" />
<<apply-templates>>
</$xpath>
Voila! apply-templates is emulated through tags. I can add new templates using the [[XSLT Template]] tag, or another one, and manage other blocks of schema.
I've attached an XML tiddlybundle which includes the sample tiddlers I made to make sure this works. Just drag it onto the tw5-xml demo site, and you'll see. I added another template and an example XML just to show it off. (Github wouldn't let me upload an XML for some reason. So you need to change its extension to XML before you can drag it) dungeonsAndTemplates.txt
Does this work for you? tw5-xml could be expanded to include the macro perhaps, but there are so many subtle ways to implement this design pattern that I felt it was better to leave it up to the user. Your thoughts?
Hi @flibbles, thank you! I tested your solution: it does work wonderfully and I think you should include it as an example of advanced use of the widget.
Still, with <<apply-templates>>
the sequence of template application is driven by the TW5 tag processing sequence rather than the sequence of elements in the XML file. That's when I meant to process an Open Office document with tw5-xml, that I realised that documents obviously needed to be processed in order, by contrast with data files. That's probably the only real difference between XML documents and XML data 🤕
Are you saying the problem with it is with a situation like this?
<character>
<item />
<skill />
<item />
<item />
<skill />
</character>
You can't process those internal elements in the order they appear. You can only process all the items first, then skills, or vice versa? Is that what you're saying?
Also, in the future, I recommend you feel free to create a new comment after you've finished testing. I was not notified when you edited your existing comment, which is why I've ignored you all month.
Are you saying the problem with it is with a situation like this?
<character> <item /> <skill /> <item /> <item /> <skill /> </character>
You can't process those internal elements in the order they appear. You can only process all the items first, then skills, or vice versa? Is that what you're saying?
Exactly that. It is more obvious with a typical XML document (as opposed to XML data):
<text>
<section>
<heading>My First Chapter</heading>
<para>Paragraph 1</para>
<para>Paragraph 2</para>
</section>
<section>
<heading>My Second Chapter</heading>
<para>Paragraph one</para>
<para>Paragraph two</para>
</section>
</text>
If one says:
<$xpath for-each="/text/">
<<apply-templates>>
</$xpath>
(S)he can't make the macro apply to the sections in the expected order, and then to the paras in the expected order.
Also, in the future, I recommend you feel free to create a new comment after you've finished testing. I was not notified when you edited your existing comment, which is why I've ignored you all month.
Oops, apologies! I didn't think of that :-(
Hi Flibbles,
As you know, I'm a big fan of this plugin already. The one thing that I'm missing as of 1.0.1 is the ability for the
<$xpath>
widget to choose a template based on the current path, as would XSLT do with<xsl:apply-templates>
.It is currently quite difficult to process an XML chunk whose schema allows several distinct subpaths at a given XML node: revealing nested
<$xpath>
s based on a subpath value doesn't seem impossible with the help of a few variables and some TW5 core widgets, but it would be suboptimal to say the least.I suggest that in a future version, a mecanism is added to allow the registration of templates based on an xpath string (like
<xsl:template>
in XSLT), so that<$xpath>
can choose one of these templates based on the current node it is in.Thanks again! Xavier.