Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How about event-driven templates à la XSLT? #1

Open
xcazin opened this issue May 16, 2020 · 4 comments
Open

How about event-driven templates à la XSLT? #1

xcazin opened this issue May 16, 2020 · 4 comments

Comments

@xcazin
Copy link

xcazin commented May 16, 2020

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.

@flibbles
Copy link
Owner

flibbles commented May 16, 2020

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 xsl:apply-template using a simple design paradigm.

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 <xsl: apply-template> when using XSLT, I've already descended into insanity, and my memory of the events will be hazy at best.

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?

@xcazin
Copy link
Author

xcazin commented May 17, 2020

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 🤕

@flibbles
Copy link
Owner

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.

@xcazin
Copy link
Author

xcazin commented Jun 17, 2020

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 :-(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants