[ZPT] Stylesheet Language

Evan Simpson evan@4-am.com
Fri, 17 May 2002 16:12:10 -0500


Shane Hathaway wrote:
> Maybe we can discuss the requirements first?  It sounds like what we 
> want is server-side, stylesheet-like tag processing.  That's what XSLT 
> is good for, though a lot of us believe XSLT is too complicated to fit 
> the same uses ZPT has.

What we want, in the design of both TAL and TSSL, is subtly different 
than what XSLT provides.  It is also vastly simpler, but let that pass. 
XSLT transforms one DOM into another, often using the source DOM as a 
sort of datasource.  TAL and TSSL, like CSS, apply formatting changes to 
a document in a simple, linear fashion.  Many of the reasons why CSS and 
XSL are expected to co-exist probably apply.

TSSL, specifically, is intended to allow TAL-like capabilities to be 
factored out of the document body.  This is desirable when the TAL 
equivalent is redundant, intrusive, or requires document restructuring. 
   For example, making the same change to the "src" attribute of every 
image in a document is highly redundant with TAL.  Presentation logic 
can easily become intrusive, requiring a document editor to be aware of 
it in order to preserve its semantics.  The limitations of TAL often 
require us to restructure a document in order to control the order of 
operations.

> OTOH, perhaps your example is a lot like CSS.  In that case, CSS has 
> come to resemble Perl. :-)

There are two syntactic pieces to TSSL: the tag selectors and the 
statements.  In my example, I have adhered exactly to CSS2 selector 
syntax (the bits outside the braces}, and I am strongly in favor of 
keeping it.  The syntax is concise and fairly simple. The only bit I 
used that someone familiar with CSS wouldn't recognize is the at-rule 
"@begin".  I introduced this to allow operations at the beginning of the 
document, which CSS2 selectors have no way to (or need to) address.

The syntax for rule statements is less obvious.  I assume that we will 
want to perform at least the range of operations that TAL allows, so a 
start would be to translate 'talattr="tales"' directly into 'talattr: 
tales;'.  We would be immediately freed from TAL's XML-inspired 
attribute restrictions, so that TSSL statements need not be unique 
within a block, nor have an order of operations apart from syntactic 
sequence.

TAL's design constraints had three other major effects, however, and 
each is worth revisiting.  First, the unique attribute constraint 
required tal:define and tal:attributes to be multi-part statements, with 
semi-colons as part separators, while in CSS semi-colons are statement 
terminators.  Second, the fact that attributes are already quoted led to 
the development of a string expression syntax that did not require 
further quoting, and to raw path expressions as the default.  Third, 
attribute syntax also led to TALES' colon-separated expression syntax.

By making 'define' and 'attributes' single-part statements, we avoid the 
semi-colon problem since 'tal:define="x a;y b"' can simply be translated 
to 'define:x a; define:y b;'.  CSS already has a quoted string syntax, 
and I'm happy to translate 'string:Foo $bar' into '"Foo $bar"'.  CSS 
also has a functional notation, the most common use of which is 
'url(http://whatever)'.  Again, simply translating 'python:x + 1' into 
'python(x + 1)' seems fine to me.  As for path expressions, I recommend 
leaving them as the default since '<identifier>/<rest of path>' is not 
hard to parse in a CSS-like environment.  Paths with spaces can be 
written as 'path(here/name with spaces.gif)'.

So far, so good.  I took things a step further in my example, since I 
very much prefer 'x = y;' over 'define: x y;'.  We left the '=' out of 
tal:define largely because it seemed awkward to have two or more of them 
in a row, as in 'tal:define="x=a;y=b"'.  By analogy with the CSS2 
selector syntax, I used '[src] = value;' instead of 'attribute:src 
value;'.  Neither of these extensions is really necessary, and they do 
violate the CSS model.  I still like them, though :-)

Finally, I added a number of at-rules in order to address missing 
functionality.  At-rules are a standard mechanism for extension in CSS, 
and processors are directed to ignore at-rules that they don't 
understand.  The at-rule '@tal;' allows us to specify how TSSL interacts 
with TAL.  The at-rule '@if <expr> <statement>;' allows the sorely 
missed ability to make individual statements (or groups, using {}) to be 
conditional.  Awkward TAL constructions like 'tal:replace="structure 
python:test(items, default, '<b>None</b>')"' can be written as '@if 
not(items) replace:structure "<b>None</b>";', which has the additional 
virtues of short-circuit evaluation and efficiency (no Python 
expression).  The following statement would be very painful to write 
without @if: '@if items | nothing { @if python(len(items)>1) 
replace:"Many"; @else replace: "One"; } @else replace:"None";'.

Whaddya think? Rationale enough?

Cheers,

Evan @ 4-am