[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