Tuesday, April 12, 2005

CSS, the XForms Dependency Engine, and 'Dynamic Infosets'

A discussion is currently running on the W3C mailing-list for CSS (www-style) about whether XPath should feature in CSS [1]. The same thought has probably occurred to just about anyone who has ever had to deal with both XML and CSS -- that the selection mechanism in CSS plays a role uncannily close to that played by XPath. In both systems nodes can be selected using the name of the target element, and in both systems there are mechanisms for narrowing the list of applicable nodes by specifying what value an attribute might have, or indicating that only nodes with a certain relationship to other nodes should be used (for example, the child of another node).

Of course, as Robin Berjon, Bjoern Hoehrmann and others on the discussion have hinted, it's no surprise that the two selection mechanisms play a similar role, since the items across which they are working are the same -- nodes in a DOM. No matter what syntax you come up with for accessing items in that tree, you will still end up expressing the same concepts (although of course CSS is able to address fewer items in the tree than XPath).

But while some sort of convergence of XPath and CSS selectors may seem an obvious thought to many, the CSS 'language' continues to resist being brought up to date, and instead exists in a strange, murky world, of 'quirkarounds' and 'standards-proprietary' syntax. (As people require the ability to address other parts of the source tree, new selection mechanisms have to be added, but in a way that doesn't affect existing rules -- resulting in 'quirky workarounds', and syntax that is not shared by any other standard.)

Before we look at whether XPath fits with CSS, it's worth looking at what exactly it is that CSS does. It may seem obvious -- surely it just provides styling information based on a set of rules? -- but if you break it down a bit you'll find that the general mechanism at play could be used in many other situations. To understand CSS we need to look at its processing model and its addressing model.

The CSS Processing Model

The CSS processing model [2] says that in effect all properties that are supported by the current media type should be added to each element in the DOM tree (see step 4, in the processing model). This means that if our document were to be rendered on a screen, each element in our DOM tree would gain a color property (amongst others), since color is one of the many properties available when the media type is screen.

Let's assume that this property is actually implemented as an attribute on the element itself, and let's also prefix it with a namespace for CSS, so that it doesn't get mixed up with other color attributes that we might have. Our document would look like this (omitting elements outside of body, etc.):

.
.
.
<body css:color="">
<h1 css:color="">Blog</h2>
<p css:color="">
This week's blog.
</p>
</body>
.
.
.

Now, say we had the following stylesheet in the document:

<style type="text/css">
body { color: blue; }
</style>

This style rule says that any element called body (of which there will actually only be one) should have its CSS color property set to blue. After applying this rule, our tree would now look like this:

<body css:color="blue">
<h1 css:color="">Blog</h2>
<p css:color="">
This week's blog.
</p>
</body>

But note also that the color property can be inherited by child elements [3], meaning that if it doesn't have an explicit value it should use the value of its parent element. Since we only have one style rule, then in our example setting the colour on body will also set it for all child nodes since no other rule will override it:

<body css:color="blue">
<h1 css:color="blue">Blog</h2>
<p css:color="blue">
This week's blog.
</p>
</body>

If we put aside that we are dealing with 'styling' for the moment, then what we actually have here is a mechanism by which an attribute on an element can be set to some value. The element that we want to manipulate is selected using some addressing mechanism, and the attribute to be modified is specified with rules. Depending on the attribute to be set, we may also inherit the value if no explicit setting is available.

But we can go further still; not only can we put aside the fact that we are dealing with styling properties (and instead consider the setting of any node in the document), but also we can put aside that we are dealing with an XHTML document in a web-browser, and instead consider the manipulation of any DOM.

In short, the CSS processing model is a specific example of a more general mechanism, a mechanism that for want of a better description we'll call a dynamic infoset [4]. We'll come back to this idea in a moment.

CSS Addressing Model

We've seen how CSS performs its processing, but the other part of the CSS specification is how it expresses these rules in the first place -- the addressing model [5]. As we've seen, CSS uses a simple syntax for selecting the elements to which its processing will apply, but as the discussion on www-style shows, many feel that the time is right for change, and that XPath should also be part of this addressing language.

However, I would like to go further and see CSS broken up even more.

Separate Processing, Addressing and Styling Modules

It would seem pretty straightforward to me to take the first step of breaking the CSS processing and addressing mechanisms away from the actual properties themselves. If the selection mechanism was distinct from the styling properties it would be both easy and manageable to allow different groups to produce different sets of these properties for their different specifications. And before anyone shouts about what a terrible free-for-all that would be, I'm not saying there should be no coordination; but the problem with the current arrangement is that we are like children having to keep asking mummy for sweets from the cupboard -- when we do ask she gives us a stern look, produces a large key from her apron pocket, hands out one or two morsels ... and then slams closed the cupboard door until next we get up the courage to ask for more.

As it happens, despite the imagery, I'm not really saying that this gatekeeper role is desired by the CSS group -- after all, they need to be superhuman to keep up with the demand for new features in such a diverse range of disciplines, from speech, to vector graphics, mathematical mark-up, and of course forms. But desired or not, this gatekeeper role is a direct consequence of the unnecessarily over-centralised nature of the CSS standards.

However, a far more important consequence of separating out the styling properties, is that they can then be used independently of the language used to select the elements to which those properties will apply. To illustrate this point, we'll use another dynamic infoset, the one contained in XForms.

XForms' Dynamic Infoset

XForms already supports a mechanism for setting any node in a DOM of any type. If the XHTML document from our example above were loaded into an XForms instance, then we could re-write our CSS rule like this:

<xf:bind nodeset="//body/@css:color" calculate="'blue'" />

This simply says that for any body element in our document (of which there is only one), set the css:color attribute to blue. To find out exactly what it means for css:color to be set to 'blue' you would need to consult some CSS module -- but that's a benefit, since what it means to have a colour is unrelated to the mechanism used to apply that colour.

The bind statement that we've used here relies on the XForms dependency engine, which is at the core of XForms, and is perhaps one of XForms' most powerful features. If you haven't used it yet, you'll find it saves you a lot of time -- but then you may know by now that I am biased.

Anyway, think of using the engine much like you use a spreadsheet. Say you add a calculation to a cell that sums two other cells:

=A1B1 + A1B2

Once you've entered this, you don't need to worry about performing a recalculation when either A1B1 or A1B2 changes, since the spreadsheet will do that for you. The spreadsheet software has built up a 'dependency graph' -- a list of the relationships between different cells -- and from this list it can tell that if A1B1 changes, the calculation for A1B3 must be re-executed. (Of course, A1B1 may have changed as a result of another cell changing and so on, and so on, but that's after all what computers are for...get them to do the hard work!)

XForms has a similar 'dependency engine' built in, which makes it very easy to build complex data models. For example, in a DOM that contains an invoice, we can indicate that an element should always contain the total of the invoice:

<bind nodeset="sum" calculate="sum(../items/cost)" />

Now if the value of any items changes, the calculation will be re-run, and sum will change, too.

The exciting thing is that by using XPath we break out of the problem that CSS has, where we constantly need new selection mechanisms to get at the different parts of the DOM. And note too that we get for free a syntax for expressing relationships between elements, such as being half the width of your parent:

<xf:bind nodeset="id('a')/div/@css:width" calculate="../../css:width div 2" />

Yet another bonus is that by making use of the standard way of referencing parts of the DOM, we also benefit from emerging standards that provide XPath extension functions. One example is the Dynamic Property Framework [6] which can yield information about the environment in which an application is running. The spec has an example that shows how you might make use of the fact that a device has a low battery level [7], and we could recast the example as follows:

<bind nodeset="id('battery')[dpf:component()/device/battery > 20]/@css:display"
calculate="'none'" />

Conclusion

The existence of a W3C standard for a dependency engine has important implications for the future of CSS and points to the real possibility of creating a 'CSS framework'. This framework would make use of a dynamic infoset standard (with one or more addressing languages), plus the modularised styling properties.

However, I feel that if CSS doesn't adapt to the needs of a new generation of XML languages used to build internet applications, then people will end up just going around it.




[1] XPath and CSS, again, Pascal Schmitt on www-style@w3.org, http://lists.w3.org/Archives/Public/www-style/2005Apr/0105.html

[2] Cascading Style Sheets, level 2
CSS2 Specification
, Section 2.3, The CSS2 processing model, http://www.w3.org/TR/REC-CSS2/intro.html#processing-model

[3] Cascading Style Sheets, level 2
CSS2 Specification
, 14.1 Foreground color: the 'color' property, http://www.w3.org/TR/REC-CSS2/colors.html#colors

[4] This is a term that I used in my paper to the W3C Web Applications conference in April 2004 -- specifically the idea of a 'dynamic infoset'. See http://www.w3.org/2004/04/webapps-cdf-ws/papers/webapps-workshop-standards-based-vm.pdf

[5] Cascading Style Sheets, level 2
CSS2 Specification
, Section 2.3.2 CSS2 addressing model
http://www.w3.org/TR/REC-CSS2/intro.html#q5

[6] Dynamic Properties Framework (DPF), W3C Working Draft, http://www.w3.org/TR/DPF/

[7] Dynamic Properties Framework (DPF), W3C Working Draft, Section B.2 Battery Level http://www.w3.org/TR/DPF/#A2

5 Comments:

Blogger Koranteng said...

Hi Mark,

Thought this would be of interest On XForms, XPath, CSS, Brevity, Syntax And More

Your insightful post sparked a rant on my part... Enjoy.

April 14, 2005 6:32 PM  
Blogger Chris Jay said...

Hi Mark,

You're absolutely right that CSS needs to be split into two parts.

But following the same logic, shouldn't XForms be split in two also (there are other reasons to do binding than to create forms).

See my blog for more details.

February 13, 2007 10:25 AM  
Blogger Mark Birbeck said...

Hi Chris,

I enjoyed your blog post--thanks for the link.

Just a few points on your comment though. My post was saying that in CSS is already split in two, since it already defines a processing model that is separate from its addressing model. I was using this as an argument to say that if CSS supported XPath as one of a number of alternative addressing methods, it would not change the nature of CSS. (When this was written in early 2005, a debate was running about whether CSS should support XPath.)

In passing I also said that it was worth factoring out the dependency-engine from both XForms and CSS into a common component. Work is underway to do exactly that as part of a broader 'factoring' initiative within the W3C, called the Rich Web Application Backplane.

You might also be interested in a session I did on this subject, at a W3C workshop in early 2004, called A Standards-based Virtual Machine:

"Perhaps the two most important modules are the decorator module and the dynamic infoset module. The decorator layer would allow the recursive definition of features required further up the hierarchy, ensuring that the VM remains completely dynamic. The dynamic infoset module allows the value of nodes to be determined on the basis of values and changes to other codes."

Thanks again for your comment, and the link to your interesting post.

Regards,

Mark

February 13, 2007 10:46 AM  
Blogger Chris Jay said...

Mark,

Totally agree.

Both the CSS and XForms specs would be simplified and improved if there was a separate spec for the "dependency engine / dynamic infoset / functional animation language" that they both rely on, probably based on the XForms bind tag.

In fact, it would also improve SVG (no more half-hearted animation tags), HTML (drag and drop, general interactivity) and SMIL (replace pretty much everything).

Chris

February 13, 2007 6:06 PM  
Blogger Fraser Hore said...

I read this post a while ago and liked it very much. I just read an article about the Content Assembly Mechanism (CAM) and it made me think or your post.

http://www.devx.com/xml/Article/41066

What's interesting about CAM is that as the author describes, it is a "system that separates structure from semantics (low coupling) and specifies semantics with rules. He provides the following example of how you would set the datatype for and address:

{

<as:Structure>
<address>
<address_street>%street number and name%</address_street>
. . .
</address>
</as:Structure>

<as:Rules>
<as:constraint action="datatype(//address_street,string)" />
</as:Rules>

}

Notice that the constraint element works much like a bind element in xforms. The action attribute takes a defined set of predicates, such as datatype. Each predicate takes nodeset as an xpath expression and then applies a rule to it. One of the predicates is setValue(). So you could have:

{

<as:constraint action="setValue(//body/@css:color,blue)" />

}

I think you can also have:

{

<as:constraint item=”//body/@css:color”>
<as:action>setValue(blue)</as:action>
</asconstraint>

}

I like the xforms bind element syntax better because I think you could have:

{

<xf:bind nodeset="//body">
<xf:bind nodeset="@css:color" calculate="'blue'" />
<xf:bind nodeset="@css:width" calculate="'10px'" />
</xf:bind>

}

To apply multiple style rules in to a single nodeset would be cumbersome in CAM, as far as I understand. The interesting thing is that it is possible. Or appears to be if I understand it correctly.

Cheers,

Fraser

March 13, 2009 9:22 PM  

Post a Comment

Links to this post:

Create a Link

<< Home