(I'm going to insert examples, but I want to finish the explanation first, to make sure I understand it, -- Dan)


IKAT is an algorithm for unifying a tree of data generated by an application with a template file.

The template file has something rather like a series of examples, rather than a set of formal rules. At various points the template processing can divert to another part of the template with a "closer" copy of what you want to render, to return when it is done.

For example, consider a template containing a red border around a strawberry, and a green border around an apple, as examples. The data model contains a red apple. The border is red, so it initially follows the red strawberry part of the template. When it starts to render the fruit, though, it spots that the apple inside the green apple part of the template is a better match, and goes to render the apple there. When finished rendering the fruit it returns to the red strawberry template to finish the red border.

The template is processed, then, in fits and starts. It proceeds linearly in a normal kind of way till it jumps (temporarily) to a completely different part of the template, and then carries on where it left off. The linear processing is called "base-state" the process of jumping is called "extended-state". There is also a glue state, which I find a little confusing (more to come!).


The data which comes out the code is in the form of components. There are different classes of components. One important component is a container. It simply contains sub-components. Other components, sitting at the leaf, can be more exotic. They can contain strings, or any kind of data you desire, really. Their purpose is to be rendered, when IKAT sees fit. For example, there's a kind of component which contains a string, which is probably a string you want rendered. More of which later. So these components are assembled into a tree. At the root is the root container, and at the leaf are the leaf components, and in between are various containers.

Simple Template Driving#

Initially, a template rendering is proceeding linearly (in "base state") through the template file. The only thing which can affect this stately progress is the presence of rsf:id tags. These tags have one of three forms. In the simplest form, it contains neither a colon nor an equals. In this state the current container (initially the root container) is searched for any sub-components which match the id exaclty. If so, control is handed to the component, which does as it will with the tag and all its contents. For example, the string component replaces the contents of the tag with the string it contains. If the rsf:id contains an equals sign it does something similar, but with some special semantics. Exactly what is special is determined by what preceeds the equals. At the only moment, the only special thing is scr. In this case a rendering is undertaken without reference to any component at all, named by the suffix after the scr. For example, it could be used to implement some function you want to apply to all contents (say converting to upper case, or rewriting URLs), and which doesn't depend on the model you produced.

Rendering Containers#

All this is pretty linear stuff. Pages aren't that simple. You need some things conditionally, and some things to occur many times. In traditional template languages you embed the conditionals and loops in the code. IKAT doesn't do that. RSF id's which implement this non-linear driving have colons within them. When the template engine encounters a tag with a colon in, it first assembles all tags with rsf:id attributes inside the current container (initially the root, which contains the whole document, we'll see how that changes later) that match that prefix. So if the rsf:id encountered is beans:1, then beans:2, beans:fred, beans:food, are found, inside that container.

It is possible (though, not necessary, we'll see how IKAT can be contrary in a moment), that it proceeds like this. The rsf:id is found in the current container, and is itself a container. this container becomes the current container, and the contents are parsed just as we have been, but with a different current container, further down the model.

For example, consider a model which has a subcontainer with label "myfood:" inside myfood: is "name", which is a string component saying "Cauliflower", and also "number" which is a string component saying "a million".

Inside the tag in the template with the rsf:id tag "food:" is one with a tag "name". According to the simple linear substitution applied above, name is exctracted from our current container "food:". If we weren't inside the "food:" tag, the algorithm couldn't have found it, because the current container would have been the root container, and "name" is inside the "food:" container.

Repeating yourself#

But what if your root container contains many components called "food:"? This is not only allowed, it's encouraged! For every "food:" in your container, the template is repeated again and agin, along with glue (XXX explain glue). So if you want a list of many entries, or a table, simply store many of them in your container, they will be printed one after the other. In fact, everything with the same prefix is rendered, in order, whatever the suffix. Repeating ignores suffixes, they're used in something explained later. If we have a "food:c" conatining the "name" Cauliflower, and a "food:a" containing "name" Apple inside our root container, then the first is printed, and then the second, based on the first template in the template file matching "food:whatever".

When that's done, we jump to just past the last instance of "food:*" in the current tag, and then continue. Note that this means that all the "food:*" tags should be together, and not have any other 'colon' rsf:id tags in between at the same level.

Going Absent, with Leave#

Whenever IKAT comes across a tag with a colon in it, however, it can, instead choose not to render the contents of that tag (or the tag itself) at all! Instead, it may render a part of the template it considers more appropriate to the container. In fact, IKAT can choose to render any tag anywhere in the template, as long as it has an ID with the same prefix. Exactly how it chooses we describe in a moment.

For example, say there's a tag with an rsf:id equal to "food:". Our current container contains a component with tag "food:cheese", so its prefix matches. If that's the only "food:*" tag in the template, then it will be used to render the cheese. However, somewhere else in the document we may have a tag with an rsf:id of "food:cheese". All other things being equal (often they're not, see later), IKAT will assume that this tag and its contents are better at rendering our component than the generic "food:" tag at the current place. It uses this "food:cheese" tag and its contents, and then goes back to where it left off after the tag that was rejected. So if IKAT finds a better fit for the component to be rendered, then it uses that instead.

This is the core operation of IKAT that makes it distinct from other engines, and the most complex point. When it encounters a tag with a coloned rsf:id it may decide to go elsewhere in the template to render it, based on the contents of any corresponding entry in the model, and return to the template when it is done.

Fitness (matching of children)#

(XXX correct in light of Rule priority. Remove references to cheese, etc)

How do we tell which is a fitter tag to render a sub-component? The most important criterion is to consider future matching lower down the tree. Say we have a component called "food:cheese" and we can find a tag called "food:", and we're wondering how to render it (to use this tag in-front of us, or a better one elsewhere). Now say our "food:" contains a component called "picture". We want to make sure that the template we use to render food has a way of doing something with a "picture": we want to make sure as much of our model as possible makes it out onto the screen. Say there's another tag with rsf:id called "food:", far away. As the suffix matches our component, all other things being equal, we would use that. But say that "food:cheese" doesn't refer to "picture", but the "food:" tag does. Then we use the latter, despite the suffix match of the former. The children of the component we are about to render are the most important criterion in determining which to render. A container will have extra children, typically, to indicate extra functionality (say another button, or more information). We must make sure that extra functionality is rendered!

The children are considered in this manner.

Most important is that none of the children refered within the container is absent from the template, considering only prefixes. For example, if the container to be rendered contains a "picture:*" child, and there is no "picture:*" referenced in that part of the template, then that template is heavily penalised. All the template-parts which "tie" in matching the most of the children are then forwarded to the next round. For example, if the container to be rendered has a "picture" child, and this part of the template doesn't mention "picture", then another is chosen, which does. This ensures that as much of the model is displayed as possible in the template chosen.

Secondly the remaining templates are considered in terms of those children where the previous matches were only by the prefix part, and those which were complete matches. A template which referred a "picture:staff" when there was a "picture:product" in the component is bad in this regard, whereas one which referred to a "picture:product" directly would be better. Those templates which are the best at this stage go through to another round. It is assumed that matching suffixes represent "better" matches in terms of the appeal of the visual layout.

Thirdly, if there are extra tags in the template that are not referred to in the container (ie the other way around to the previous two rules), these templates are penalised. For example, if a template refers to "picture", and the container has no picture, are penalised here. Those which are best go on. This is to ensure that those simple templates designed to cater for simple cases are chosen over their more baroque cousins, in cases where that functionality is genuinely missing from the container.

At this point we have finished considering the children of the container to be rendered.

Fitness (other concerns)#

(XXX todo Tue)

(XXX glue)

Add new attachment

Only authorized users are allowed to upload new attachments.
« This page (revision-) was last changed on 01-Aug-2007 12:35 by UnknownAuthor