XBL Task Force Issue: Includes attribute syntax

This version:
Version 0.2: 2005/01/03
Previous versions:
Version 0.1: 2004/12/08

Abstract

This document is a working document within the XBL task force which discusses one of the outstanding issues in depth: what syntax to use of the 'includes' attribute on <content> elements. This document describes the issues, lists the various proposals under consideration, and discusses pros and cons for the various proposals relative to particular examples. The overall goal with the document is to help the XBL task force make decisions at a particular moment in time. Once the XBL task force has discussed and made decisions about the given issue, this document may become obsolete and may not get updated to reflect the decisions that were made.

Table of contents


1 Introduction

Request for public feedback

The XBL task force has not yet decided the syntax to use for includes attribute.

Two syntax approaches are being considered:

  1. A drastically small subset of XPath such as only allowing:
  2. A drastically small subset of CSS Selector syntax such as only allowing:
    • *
    • name
    • name:nth-of-type(n) [from CSS3]
    • #id

2 Background

2.1 How Mozilla XBL does it

The 'includes' attribute on <children> in Mozilla XBL uses XPath 1.0 syntax in the spec, but was actually implemented as only a list of tag names. In the four years since the specification was submitted to the W3C as a Note, the need for more power in the attribute has not been strong enough to cause anyone to change the implementation, even when other parts of Mozilla's XBL implementation were changed.

2.2 How RCC did it

The 'select' attribute on <refContent> in RCC used the following subset of XPath 1.0:

3 Possible Requirements

While there is a consensus about the general capabilities of the 'includes' attribute, detailed analysis of the issue has generated questions about certain detailed feature requirements. Are the following candidate requirements facilities that must be supported (MUST), are highly desirable to support (SHOULD), are optional to support (MAY), or should not be supported (NOT):

  1. Namespaced tagname selection. Is it a requirement that the 'includes' attribute support the ability to select namespaced tagnames? The W3C Selectors proposal relies on CSS selectors; however, the current CSS Recommendation (CSS2) does not support namespaces. The W3C Selectors specification does add namespace support, and is currently a Candidate Recommendation. (There is a good chance it will reach Recommendation faster than sXBL.) If W3C Selectors namespace syntax is used, then to select the <foo:bar> element using CSS selectors, the 'includes' attribute would have to use a vertical bar, as in includes="foo|bar". Prefixes would be defined using the normal xmlns method. The compromise proposal suggests restricting the 'includes' attribute to unqualified tagnames. In a namespace-aware DOM, this would mean that tagname matching would ignore namespaces, for example foo would match an element whose local name was foo whether the element was in the http://example.com/ namespace, no namespace, or any other namespace.
  2. Selecting child elements by ordinal number. The XPath Subset proposal argues that a key feature is the ability to point to a particular child element by ordinal number. This feature is available both in XPath (using [n]) and in W3C Selectors (using :nth-child(n)).
  3. Selecting child elements by ID matching. The XPath Subset proposal does not include ID matching, whereas the W3C Selector proposal does. (The XPath proposals could be extended to allow ID matching.) This is a more minor feature issue, but nevertheless is ID matching a requirement?
  4. Long-term extensibility to allow arbitrary node selection. The subset proposals only allow selection of all nodes or particular child elements. Is it a requirement that there is a future growth path that allows for richer selector facilities such as selecting a particular text node or an element node which isn't necessarily a direct child of the bound element? Note that the 4.3 Use XPath Subset (Any descendants of bound element) proposal would provide arbitrary node selection immediately.
  5. Long-term extensibility towards arbitrary XPath expressions. One of the arguments for using XPath expressions is that it is a requirement to have a growth path so that future scenarios will be able to use the full power of XPath expressions with the 'include' attribute. For example, some future compound document format might use sXBL in conjunction with XForms, which already requires XPath support, so in this scenario why not allow arbitrary XPath with sXBL? Is such future extensibility to full XPath a requirement?
  6. Long-term extensibility towards arbitrary selectors. One of the arguments for using W3C Selectors is that it is a requirement to have a growth path so that future scenarios will be able to use the full power of W3C Selectors expressions with the 'include' attribute. For example, some future compound document format might use sXBL in conjunction with CSS, which already requires W3C Selectors support, so in this scenario why not allow arbitrary Selectors with sXBL? Is such future extensibility to full W3C Selectors a requirement?
  7. Highly optimised matching. W3C Selectors have been optimised for speed, only introducing features that can be evaluated using minimal context. However, XPath can require that the entire document tree be examined to evaluate an expression. Is it a requirement that the includes attribute be fast to evaluate?

4 Proposals

4.1 Proposal: Use W3C Selectors or a subset thereof

4.1.1 Proposal

One proposal is to use W3C Selectors, the selector language that originated from CSS in 1996. The normative reference would be one of the following:

In a first version, the exact syntax UAs would be required to support could be limited, for example only allowing one simple selector (no combinators), only allowing (namespaced) tag names and pseudo-classes (not the .class syntax or the #id syntax), and only allowing certain pseudo-classes (such as :nth-child(n)).

Namespace prefixes from the current scope (as defined by xmlns attributes) would be used for namespaces prefixes in the selectors.

Examples

One feature that could offer XBL component developers important flexibility is the "*[attr=val]" option. With this feature, it is possible for a component to use script to set the 'includes' attribute to point to a particular child element without having to analyse the bound element's children. For example, suppose the custom element is allowed to look like this:

<myNS:SkinnableWidget>
  <myNS:DropShadowSkin state="normal">...</myNS:DropShadowSkin>
  <myNS:DropShadowSkin state="hover">...</myNS:DropShadowSkin>
  <myNS:DropShadowSkin state="mousedown">...</myNS:DropShadowSkin>
  <myNS:BackgroundSkin state="normal">...</myNS:BackgroundSkin>
  <myNS:BackgroundSkin state="hover">...</myNS:BackgroundSkin>
  <myNS:BackgroundSkin state="mousedown">...</myNS:BackgroundSkin>
  <myNS:ToolTipSkin state="normal">...</myNS:ToolTipSkin>
  <myNS:ToolTipSkin state="hover">...</myNS:ToolTipSkin>
  <myNS:ToolTipSkin state="mousedown">...</myNS:ToolTipSkin>
</myNS:SkinnableWidget>

The xblShadowTree might contain the following:

<xbl:shadowTree>
  <xbl:content includes="myNS|DropShadowSkin[state=normal]" />
  <xbl:content includes="myNS|BackgroundSkin[state=normal]" />
  <g display="none">
    <xbl:content includes="myNS|TooltipSkin[state=normal]" />
  </g>
</xbl:shadowTree>

The component would respond to events and change the value of the 'includes' attribute based on the current interaction state for the given widget. When no tooltip is shown and the widget is in a "normal view" state, then script would set the 'includes' attribute on the <xbl:content> elements to point to the relevant child elements without having to know the ordinal position within the custom element. For example, to reference the "mousedown" child element, you could say includes="myNS|DropShadowSkin[state=mousedown]".

(Of course, the above example mixes presentation and content in the same way that HTML3.2's <font> element did, and so would not be a good design. However, similar scenarios occur in purely content-based designs and so the feature is still relevant.)

Using Selectors with multiple bindings

Suppose you want to implement the following <xforms:input> element using XBL with a shadow tree of SVG:

<xforms:input ref="...">
  <xforms:label>First name</xforms:label>
</xforms:input>

You can have one binding for the input element, with this shadow tree:

<svg:rect .../> <xbl:content includes="label"/>

And one binding for the label element, with this shadow tree:

<svg:text ...><xbl:content/></svg:text>

This is how all the widgets in Firefox are implemented.

4.1.2 Arguments in favor

Arguments in favor of this proposal:

4.1.3 Arguments against

Arguments against using CSS selectors:

4.2 Proposal: Use XPath Subset (Bound element children only)

4.2.1 Proposal

Another proposal is to use a highly restricted subset of XPath, the expression language that originated from XSL in 1999. The normative reference for all of XPath 1.0 is:

The proposed subset of XPath would match what was defined in RCC for its 'select' attribute on <refContent>:

A key feature that offers XBL component developers important flexibility is the "*[#]" option. With this feature, it is possible for a component to analyze the content model of the custom element and use script to set the 'includes' attribute to point to a particular child element which was identified by scripting logic. For example, suppose the custom element is allowed to look like this:

<myNS:SkinnableWidget>
  <myNS:DropShadowSkin state="normal">...</myNS:DropShadowSkin>
  <myNS:DropShadowSkin state="hover">...</myNS:DropShadowSkin>
  <myNS:DropShadowSkin state="mousedown">...</myNS:DropShadowSkin>
  <myNS:BackgroundSkin state="normal">...</myNS:BackgroundSkin>
  <myNS:BackgroundSkin state="hover">...</myNS:BackgroundSkin>
  <myNS:BackgroundSkin state="mousedown">...</myNS:BackgroundSkin>
  <myNS:ToolTipSkin state="normal">...</myNS:ToolTipSkin>
  <myNS:ToolTipSkin state="hover">...</myNS:ToolTipSkin>
  <myNS:ToolTipSkin state="mousedown">...</myNS:ToolTipSkin>
</myNS:SkinnableWidget>

The xblShadowTree might contain the following:

<xbl:shadowTree>
  <xbl:content includes="...ordinal reference to drop shadow skin..." />
  <xbl:content includes="...ordinal reference to background skin..." />
  <g display="none">
    <xbl:content includes="...ordinal reference to tooltip skin..." />
  </g>
</xbl:shadowTree>

The component would respond to events and change the value of the 'includes' attribute based on the current interaction state for the given widget. When no tooltip is shown and the widget is in a "normal view" state, then script would set the 'includes' attribute on the <xbl:content> elements to point to the relevant child elements by ordinal position within the custom element using "*[#]" syntax. For example, to reference the first child element, you would say includes="*[1]". This critical bit of flexibility when using fully encapsulated components is not available by tagname or ID matching.

4.2.2 Arguments in favor

Arguments for using a subset of XPath:

4.2.3 Arguments against

Counter-arguments against proposals involving XPath:

4.3 Proposal: Use XPath Subset (Any descendants of bound element)

4.3.1 Proposal

Another proposal is a variation on the XPath proposal which would allow the XPath subset to reference any nodes under the bound element, not just child nodes. With this variation, allowable XPath expressions would be extended to allow the shorthand "/" syntax to represent a child axis and the "text()" syntax to allow selection of text nodes. For example, "a/b/text()" would be supported and would select all text nodes that are child nodes of b and grandchild nodes of a.

Additional rules would be added such that it would not be possible for one <xbl:content> element to reference a descendant node and then another <xbl:content> element to reference one of the ancestor elements of that descendant node. Here are proposed rules to achieve this:

This extra flexibility is particularly useful for implementing XForms user interface controls. For example, suppose you want to implement the following <xforms:input> element using XBL with a shadow tree of SVG:

<xforms:input ref="...">
  <xforms:label>First name</xforms:label>
</xforms:input>

This extra flexibility allows the binding to use <xbl:content> on the text node for the label element as follows:

<svg:text x=... y=...><xbl:content includes="xforms:label/text()"/></svg:text>

Note that in some cases there is a way to use recursive XBL to satisfy the ability to apply XBL to nested child elements (such as in the <xforms:label> example above). However, this recursive approach is not a generally robust facility and can fall apart when child elements appear in multiple different contexts and require different shadow trees for each context. In the particular case of <xforms:label>, the shadow trees may need to be different depending on whether the parent element is a button control (<xforms:trigger>), a text entry control (<xforms:input>), or whatever. In one case, it might be sufficient to do a simple <xbl:content> to the content of the label, but in another case it might be necessary to copy/transform the textual content.

Also, the various textstring-oriented common labels in XForms (<xforms:label>, <xforms:hint>, <xforms:help>) all have the ability to either include text inline or use the 'model' and 'ref' attributes to bind to instance data. A desirable feature in the future would be to reference indirectly through an XForms model item property (with a possible calculation expression) which is then itself bound to the instance data. One way to pull this off would be to offer an XForms-knowledgeable XPath extension function which takes an XPath pointer to one of <xforms:label>, <xforms:hint>, <xforms:help> as a parameter (e.g., xforms-bound-data(xforms:label)). Such a growth path is only possible if XPath syntax is used as the technology foundation today.

[Comment from member of XBL-TF: It should be noted that a significantly simpler way of handling these use cases is applying XBL to elements from CSS (the 'binding' property). This would be a lot simpler than extending XPath as is suggested above -- especially since extending XPath would require changing the UA's code, at which point why not just implement XForms natively.

For example, to handle different labels for <xforms:input> and <xforms:trigger> you would do:

trigger > label { binding: url(xforms.xbl#triggerLabel) }
input > label   { binding: url(xforms.xbl#inputLabel) }

Similarly, to handle inline <xforms:hint> vs <xforms:hint ref=""> you could easily do:

hint[ref] { binding: url(xforms.xbl#hintWithRef);  }
hint { binding: url(xforms.xbl#hintWithoutRef);  }

To be perfectly honest, though, if I were implementing XForms myself I wouldn't really be trying to do it declaratively. It's a nice theoretical excercise, but at the end of the day it would just be faster to have bindings for each element (with maybe subelements like <label> bound bound based on their parent, as in the example above), and then handle attributes like "ref" using script.]

4.3.2 Arguments in favor

Arguments for using a subset of XPath:

4.3.3 Arguments against

4.4 Proposed compromise: Use only single unqualified tag names

4.4.1 Proposal

A proposed compromise: Use only single unqualified tag names, with matches being determined purely by local name, ignoring namespaces altogether.

4.4.2 Arguments in favour

4.4.3 Arguments against

5 Outside Feedback

Kurt Cagle on 02 Sept 2004 argued for XPath. Here is a snippet:

2) I'm going to put my two cents worth in for binding with XPath, for several reasons -

a) One of the reasons for the XBL specification in the first place was to provide the implementation layer between SVG and XForms, and XForms supports XPath. Without the support in XBL (where I feel it most belongs) much of the more sophisticated actions inherent within XForms require become problematic, if not impossible.

b) Most current "complete" SVG implementations exist in an environment when such XPath support already exists (Java, COM, .NET, Rhino, Mozilla Seamonkey, libXML, etc.) and as such the necessity for vendors to build their own XPath implementations is somewhat reduced.

c) XPath significantly reduces the amount of imperative code needed within applications (I'm thinking specifically of the <xbl:content> tag here), which I see as one of the major rationales for SVG over a platform dependent implementation such as GDI. Moreover, even in that imperative code, the preferred node selection capability would probably be to use XPath rather than go through the pain of trying to navigate the tree manually. I'd far rather see

<xbl:content src="bar[position() % 2 = 0]"/>
then a complex block of procedural code to do the same thing - select every even child "bar" element.

the equivalent in CSS would be src="bar:nth-child(even)" (level 3)

d) I have often used the complexity of XPath as one of the reasons for not incorporating it in SVG. However, it has been my experience in teaching classes on SVG and dealing with readers as a technical writer that if they are sufficiently savvy to master rudimentary SVG skills, they can easily master rudimentary XPath.

e) I would recommend that you mandate the full XPath solution for SVG Basic, and the reduced set XPath solution for SVG Tiny. I understand the memory requirements that SVGT targets have, making it difficult to implement the full set, but a simnple tree walker parser can readily be implemented (and indeed probably already exists).

f) A quick argument against using CSS Selectors - The CSS selector model beyond the simplest matching mechanisms is generally not well understood by more than a small proportion of the web development universe, in great part because the browser with the largest market share does not support that functionality properly. Again, this comes from experience dealing with readers and students when I teach CSS classes. Moreover, the CSS model requires the use of certain reserved characters (the ">" greater-than character) to facilitate its operation for the more sophisticated operations that will cause compilation errors with many XML parsers.

actually > is perfectly safe, it's < that causes issues (and that's not part of Selectors)

Tobias Reif on 02 Sept 2004 said the following:

I'm generally for XPath

Nigel McFarlane on 17 Oct 2004 gave lengthy feedback on various sXBL issues. Regarding this issue, here are some snippets:

I think also there is little support for complex include options. This choice could be put off until XBL 2.0... For me, option 5. or 6 is more than sufficient for includes= until experience points to clearly urgent needs. I would hope for an XHTML class= syntax solution at most. (This comment was probably in response to the sXBL spec talking about options for supporting full XPath or full CSS selectors)

includes= in the Mozilla codebase's XBL has been deprecated as a feature...

This does not actually appear to be the case.

A similar feature in the Mozilla codebase is a filtering system for command observers. There, the filtering system has never been completed, because there has never been a pressing need. All of the Mozilla work has managed very well without it

Elliotte Harold on 06 Dec 2004 said the following:

My feeling is that full XPath 1.0 is a minimum syntax for the includes attributes. I assume the context node for the XPath expression would be the matched node.

However, I really wonder if this goes far enough. I can foresee a lot of use cases that need something Turing complete. For instance, you might want to place each subsequent ten nodes in a different box. I can't see how to do that with just XPath when you don't know the number of nodes in advance.