Author's Note: When I first wrote this I had been working under the assumption that the XBL2 code hosted on Google was in fact a Google project. I have since learned that it was the brainchild of Sergey Ilinsky (http://www.ilinsky.com/), who has more recently been working on a number of other rich Internet applications.My apologies for any confusion this may have caused.
As web applications replace web pages on the Internet, there are a number of approaches that are being taken to add new functionality to these sites. One approach, the one perhaps most heavily used by applications, is programmatically controlling different parts of a web page via scripts and user events. In most cases, this process creates some form of binding on elements after the fact, which can often lead to fairly messy JavaScript code both in terms of long blocks of scripts and inline event handlers calling those JavaScript functions.
However, there's another approach that may have the potential to both simplify your applications and contribute significantly to reuse. The idea behind it is deceptively simple: in a web page's CSS page, you define what's called a behavior, a script that binds to a given behavior language document written in mixed XML and JavaScript called the XML Binding Language (XBL). Once the page loads, any element that's associated with that particular rule will gain the behavior, essentially acting as a new “element” with it's own presentation, it's own responses to user input and its own underlying data.
XBL has been floating around in various incarnations since the early 2000s. Microsoft created a type of binding called behaviors in the late 1990s, but the technology never really caught on with other browsers. In early 2003, XBL was introduced in Firefox as one way of building extensions using the XML User-interface Language (XUL), though XBL wasn't formally specified as a standard outside of Firefox. XBL bindings have worked in Firefox web pages almost from the inception of the browser, but again, other vendors didn't follow suit.
In 2006, Ian Hickson of Google published the first version of the XBL 2.0 specification as part of the W3C Web Application Formats Working Group, based in part upon the Mozilla XBL 1.0 language but aimed towards rectifying a number of the design issues that tended to cause problems with the Firefox implementation. XBL 2.0 has been a candidate recommendation since 16 March 2007, but has been waiting for the required two formal implementations of XBL 2 to be submitted that are considered a necessary precondition for a working draft to become a formal recommendation (typically after a short “Proposed” status for final comments).
Mozilla announced in 2008 that they were looking to have an XBL 2 version likely with their 4.0 release ... this effort is underway now, and it's very likely that they will achieve this goal, especially with a formal candidate recommendation status that's unlikely to change its underlying functionality.
Google, for it's part, took an alternative route that's similar to the approach they took recently with the SVG Web project. Rather than waiting for other browser vendors to adopt XBL 2, they've recently created a JavaScript based XBL2 code project at http://code.google.com/p/xbl/, with the code designed in such a way that it will work across any browser. Currently it supports all major browser versions produced within the last four years. While it doesn't completely mitigate the requirement for scripting, implementing it within your web page only requires the addition of a single script element in the header of the document:
<script type="text/javascript" src="xbl.js"></script>
Once included, any behaviors that are defined within the CSS stylesheet will be invoked, regardless of browser. Additionally, the xbl.js library (available from the project site above) also performs a check before calling the library to see if XBL2 support is enabled natively. If it is, then the code will defer to the (presumably browser optimized) XBL library that's native to that platform.
Declaring a Twitter XBL Element
An interesting exercise, echoing something I've done previously on this site, is to build a mechanism that would take Twitter feeds and display the most recent messages in a person's "friends" channel within a website. This isn't a pure client solution: it assumes that there is a proxy on the same server as supplies the initial web page that communicates with twitter and passes a JSON stream back to the client. However, the <twitter> XBL component handles the presentation and updating of this information.
A typical web page that uses XBL can often seem remarkably clean and straightforward. In the case of the Twitter app, for instance, the code would look as follows:
<head>
<title>Twitter Test</title>
<script type="application/javascript" src="../lib/xbl2/xbl.js"/>
<style type="text/css"><![CDATA[
twitter {binding:url('twitter.xml#twitter');width:400px;height:500px;}
]]></style>
</head>
<body>
<h1>Twitter Test</h1>
<p>This is a Twitter Test.</p>
<table>
<tr>
<td>
<twitter frame="myframe"/>
</td>
<td>
<iframe id="myframe" name="myframe" src="" width="600" height="500"/>
</td>
</tr>
</table>
</body>
</html>
What's perhaps most noteworthy here is the near absence of apparent JavaScript code, with the exception of the XBL library binding itself. The <twitter> component is simply given as a tag, identified earlier in the CSS declaration:
where twitter.xml is the name of the file containing the XBL while #twitter indicates the XBL binding with that particular id attribute within the file.
One effect of this is a clear separation of concerns, and a corresponding simplicity of code - without the need for complex, undifferentiated HTML intermixed with code, the HTML content can be much simpler and easy to follow. This opens up the idea of navigational elements, header and footer elements and so forth simply being defined (or in some cases redefined) as XBL extensions.
In this case, the application so embedded presents itself as a set of input boxes for username and password to the respect Twitter account, a button for sending the content, and then a pane showing the most recent tweets. Once every thirty seconds, the application auto-updates (Twitter.com keeps auto-updates down to no more than 150 per hour, so thirty seconds between queries (120 per hour) fits within that envelope).
Additionally, the <twitter> element also contains an (optional) attribute called frame. If an iframe or HTML frame is specified on the page and the @name of the frame is given in the @frame attribute, then any time a user clicks a link in the tweetpane, that link will appear in the frame (Figure 1). Otherwise the link will just open up a new browser tab or window, depending on user settings.
Building a Basic Binding
The binding xml file itself consists of a containing <xbl> element which in turn wraps an optional script element and one or more <binding> elements, each with it's own unique id. The XBL binding in turn is broken up into up to four distinct sections:
<script>...</script>
<binding id="twitter">
<template>...</template>
<implementation>...</implementation>
<resources>...</resources>
<handlers>...</handlers>
</binding>
</xbl>
The <script> element is run prior to instantiation of any of the bindings (and the results are available to all bindings), and as such often contains references for libraries such as jQuery. The JavaScript that this supports can either be placed inline or could be specified as a distinct file referenced by the @src attribute. In the case of twitter.xml, no script is needed (it's typically not, unless you need specialized libraries).
The <template> element holds HTML markup code that will be visually substituted for (or more properly contained by) the existing bound tag and its descendants. In essence, <template> describes the markup "bones" of the component. Not all XBL bindings need specific hard coded template implementations, though most do. In the case of the Twitter component, the structure describes the various core pieces, though without the rows of Twitter data (this is generated in the implementation section):
<table>
<tr>
<td>
<table id="controller">
<tr>
<th>User Name:</th>
<th colspan="2">Password:</th>
</tr>
<tr>
<td>
<input type="text" id="username" style="width:150px;" value="kurt_cagle"/>
</td>
<td>
<input type="password" id="password" style="width:150px;" value="my_password"/>
</td>
<td>
<input type="button" id="feedbutton" value="Retrieve"/>
</td>
</tr>
</table>
<div id="container">
<table id="internal"/>
</div>
</td>
</tr>
</table>
</template>
Identifiers (ids) are in scope only to the containing binding, not the overall document. This means that you can't retrieve something like the <table id="interval"> using document.getElementById('interval') - as #interval is effectively non-existent within the containing document's scope. There are a number of advantages to this approach, not least of which being that you can have multiple bindings on the same page with the same internal ids without namespace collision, something that was a major problem with the Mozilla XBL 1.0 version.
If the template provides the bones, the implementation provides the muscle and brains. The <implementation> element holds JavaScript, though this typically is specified as a JSON object that is then associated with the specific target or bound element. This is essentially the code "interface" for the object.In the case of the twitter binding, this is fairly exhaustive:
({
xblBindingAttached: function() {
boundElement = this;
this.shadowTree.getElementById('feedbutton').addEventListener('click', this.getFeed, false);
this.boundElement = this;
frame = this.shadowTree.getAttribute('frame');
interval = this.shadowTree.getAttribute('interval');
},
boundElement:null,
frame:"",
interval:30,
getFeed: function(){
var shadowTree = boundElement.shadowTree;
var internal = shadowTree.getElementById("internal");
var username = shadowTree.getElementById("username").value;
var password = shadowTree.getElementById("password").value;
var http = new XMLHttpRequest();
if (interval > 0) {setTimeout(boundElement.getFeed,interval * 1000)};
// Note - you're passing password via cleartext here, something stronger recommended
var url = "twitter.xq?username="+username+"&password="+password;
http.open("GET",url,true);
http.onreadystatechange = function() {
if (http.readyState == 4){
internal.innerHTML = '';
var tweets = eval(http.responseText);
for (tweetCt in tweets) {
var buf = [];
var tweet = tweets[tweetCt];
var text = tweet.text;
text = text.replace('&'," and ");
text = text.replace(/(http:\/\/\S+).*/,'<a href="$1" target="__frame__">$1</a>');
text = text.replace("__frame__",frame);
if (shadowTree.getElementById("id")==null){
buf.push("<tr class='tweet_row' id='"+tweet.id+"'>");
buf.push("<td class='tweet_cell'><img src='"+tweet.user.profile_image_url+"' width='48' height='48'/></td>");
buf.push("<td class='tweet_cell'><b>"+tweet.user.name+":</b> "+text+"</td>");
buf.push("</tr>");
var output = buf.join("");
internal.innerHTML = output + internal.innerHTML;
}
}
}
};
http.send(null);
}
})
]]></implementation>
In this particular case, the xblBindingAttached method is invoked whenever the binding is "attached" to the element in question, and is almost always used for initialization. Similarly, the xblBindingDetached method is invoked just prior to the binding connection being removed (such as through some form of CSS class manipulation), and typically is used for cleaning up the associated changes.
In order for a binding to work, a temporary HTML tree is built and kept under the control of the XBL binding code. This tree - called a shadowTree, holds the actual working copy of the bindings document object model (or DOM), and is a property of the bound element. In order to retrieve elements within the shadowTree, this, rather than document, should be the root class for getElementByID, such as in the line:
this.shadowTree.getElementById('feedbutton').addEventListener('click', this.getFeed, false);
which retrieves the feedbutton object.
The boundElement property is manually associated here with the this object pointer, in order to make it more evident what object is being referenced (especially as this can have different values within different contexts.
The getFeed() function, on the other hand, is specifically assigned as the handler when the feed button is depressed, and does the bulk of the real work within the binding. It retrieves the username and password for a given Twitter account, then performs an XMLHttpRequest in order to get the feed as a JSON object. The request is made to a server proxy (written in XQuery below, though it could be written in any language) that actually pulls the twitter feed from Twitter.com then passes it on to the client on the same server that the Twitter.xhtml page came from. While there are some implementations of the newer cross-domain XMLHttpRequest() calls, the technology is still new enough that it's not yet widely adopted - thus the use of a proxy server.
Once retrieved as JSON and converted into an array of status messages known informally as "tweets", the getFeed() function iterates through the set and retrieves the tweet.id property, then compares this with the existing panes in the Twitter panel table. If the id matches an existing object, the new tweet is dropped, but if not, it's added to the top of the tweet stack, pushing old messages down. From there, the text is cleaned up (the incoming stream is not always HTML friendly, especially with regard to ampersands and related constructs), and images, names and text are all packaged together into a tweet to be displayed.
Bindings can be difficult to work with when dealing with asynchronous invocations of methods - such as timeouts and other threaded events, so closures can be useful to pass relevant contexts to the appropriate handlers. In this case, once getFeed() is called, it also invokes a setTimeout call which invokes the method again after an interval specified by the @interval attribute, defaulting to thirty seconds. If @interval is set to 0, this will turn off the update capability by bypassing this call.
The <handlers> section provides generalized event handlers for the XBL binding overall. While there are none specified in the example, a typical set of XBL handler might look something like the following:
<binding id="events">
<handlers>
<handler event="click" phase="default-action"
button="1" click-count="1" modifiers="none"
trusted="true">
this.activate();
</handler>
<handler event="keypress" phase="default-action"
key="Enter" modifiers="none"
trusted="true">
this.activate();
</handler>
<handler event="DOMActivate" phase="default-action">
if (event.target == this.boundElement)
this.boundElement.ownerDocument.location.href = this.href;
</handler>
</handlers>
...
<!-- it is assumed that the implementation for this binding
implements a .activate() method that fires the DOMActivate
event on itself. -->
</binding>
</xbl>
In general, such event handlers are wrappers around the relevant JavaScript handler scripts. Note as well that these are relevant only to the domain within the binding, not the larger document.
Resources cover both the use of stylesheets and external media resources (images, sounds, video, etc.) that may be used by the binding itself. In the case of the Twitter component, the stylesheet for controlling the component is expressed inline as:
<style><![CDATA[
td.tweet_cell {
background-color:#E0E0FF;
border:outset 2px;
font-family:Arial;
font-size:9pt;}
#container {overflow-y:auto;
display:block;
width:400px;
height:500px;}
]]></style>
</resources>
The same stylesheet could also be referenced as an external file via the @src attribute.
<style src="twitter.css"/>
</resources>
The <prefetch> element (also part of <resources>) performs a preload of media resources for assignment to <img> or similar HTML (or related) elements. By preloading, you can assure that the images are automatically loaded in before the binding initially renders. The <prefix> syntax is straightforward:
<prefetch src="myImage.jpg" id="myImage"/>
</resources>
with a required src and option id. The W3C specification for XBL2 provides a sample of how such resources would be prefetched and referenced:
xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="light">
<template>
<html:img id="l" src="red.png" alt=""/>
</template>
<resources>
<prefetch src="red.png"/> <!-- this one isn't necessary, since
the UA will fetch this one as soon as it sees the <html:img> element -->
<prefetch src="green.png"/>
</resources>
<implementation>
({
red: function() {
this.shadowTree.getElementById('l').src = 'red.png';
},
green: function() {
this.shadowTree.getElementById('l').src = 'green.png';
},
})
</implementation>
</binding>
</xbl>
The full XBL document for the Twitter binding is contained in Twitter.xml:
<xbl xmlns="http://www.w3.org/ns/xbl">
<binding id="twitter">
<implementation><![CDATA[
({
xblBindingAttached: function() {
boundElement = this;
this.shadowTree.getElementById('feedbutton').addEventListener('click', this.getFeed, false);
this.boundElement = this;
//var buf = [];for (var prop in this.shadowTree){buf.push(prop);}
//alert(buf.join(', '));
frame = this.shadowTree.getAttribute('frame');
},
boundElement:null,
frame:"",
targetIFrame:function(src){
alert(src);
},
getFeed: function(){
var shadowTree = boundElement.shadowTree;
var internal = shadowTree.getElementById("internal");
var username = shadowTree.getElementById("username").value;
var password = shadowTree.getElementById("password").value;
var http = new XMLHttpRequest();
setTimeout(boundElement.getFeed,60000);
// Note - you're passing password via cleartext here, something stronger recommended
var url = "twitter.xq?username="+username+"&password="+password;
http.open("GET",url,true);
http.onreadystatechange = function() {
if (http.readyState == 4){
internal.innerHTML = '';
var tweets = eval(http.responseText);
for (tweetCt in tweets) {
var buf = [];
var tweet = tweets[tweetCt];
var text = tweet.text;
text = text.replace('&'," and ");
text = text.replace(/(http:\/\/\S+).*/,'<a href="$1" target="__frame__">$1</a>');
text = text.replace("__frame__",frame);
if (shadowTree.getElementById("id")==null){
buf.push("<tr class='tweet_row' id='"+tweet.id+"'>");
buf.push("<td class='tweet_cell'><img src='"+tweet.user.profile_image_url+"' width='48' height='48'/></td>");
buf.push("<td class='tweet_cell'><b>"+tweet.user.name+":</b> "+text+"</td>");
buf.push("</tr>");
var output = buf.join("");
internal.innerHTML = output + internal.innerHTML;
}
}
}
};
http.send(null);
}
})
]]></implementation>
<template>
<table>
<tr>
<td>
<table id="controller">
<tr>
<th>User Name:</th>
<th colspan="2">Password:</th>
</tr>
<tr>
<td>
<input type="text" id="username" style="width:150px;" value="kurt_cagle"/>
</td>
<td>
<input type="password" id="password" style="width:150px;" value="mermaid"/>
</td>
<td>
<input type="button" id="feedbutton" value="Retrieve"/>
</td>
</tr>
</table>
<div id="container">
<table id="internal"/>
</div>
</td>
</tr>
</table>
</template>
<!-- <handlers></handlers> -->
<resources>
<style><![CDATA[
td.tweet_cell {
background-color:#E0E0FF;
border:outset 2px;
font-family:Arial;
font-size:9pt;}
#container {overflow-y:auto;
display:block;
width:400px;
height:500px;}
]]></style>
</resources>
</binding>
</xbl>
Generating the Data Stream
As mentioned previously, because of the cross-browser and cross-domain issues, in general it is better to make use of a server proxy to pull in the relevant Twitter streams. While there are a number of different potential implementations for such a stream, I laid it upon myself as a challenge to create such a proxy stream for an XML REST-based Database, in this case the eXist-db server, both because the application I was developing was based on it and because I was trying to figure out how to proxy a JSON stream.
The xquery to build such a stream was pretty straightforward (and corresponds to how one would do it in a language such as Ruby or PHP):
declare option exist:serialize "method=text mediatype=text/plain";
let $username := request:get-parameter("username","")
let $password := request:get-parameter("password","")
let $auth := concat("Basic ",util:string-to-binary(concat($username,":",$password)))
let $results := httpclient:get(
xs:anyURI("http://twitter.com/statuses/friends_timeline.json"),
false(),
<headers>
<header name="Authorization" value="{$auth}"/>
</headers>)
let $tweets := util:binary-to-string($results)
return $tweets
In this case, the username and passwod were retrieved from the relevant query string parameters, then were munged together into a basic authentication string to be used for a header. The routine util:string-to-binary() converts a text string to Base 64 Binary (which is used to encode binary content over the web). http-client:get() then invoked a GET command over HTTP (much as you would with the XMLHttpRequest object), with the result returned as a binary representation that then needs to be converted back into a JSON string with util:binary-to-string(). This is then returned to the output of the call. Then,
http://localhost:8080/rest/twitter/twitter.xq?username=kurt_cagle&password=mypassword
would invoke the XQuery routine and retrieve the relevant Twitter friends stream. This could be extended to other user streams as well just by changing the Twitter URL.
Tying Up Bindings
It's hard to say whether Google's XBL2 implementation will really catch on, although it has a number of factors going for it. The code is remarkably cross platform - it works on all contemporary browsers with the possible exception of Konquerer. That doesn't necessarily mean that JavaScript code written within the bindings will satisfy that same restriction, of course, but having the framework in place can go a long way to making such code browser independent.
Bindings make for cleaner layout and code and encourages componentization at the browser level, which in turn promotes code reuse and the development of core libraries. Because of the encapsulation involved, you don't generally have to worry about id or namespace collisions at the scripting or styling level, which reduces the likelihood that such code won't work because a given id happens to be a core one in the base scripting library. It also makes it much easier to test component development in isolation without having to worry about dependencies within a given web page causing spurious debugging results.
Overall, it may very well be that XBL's time is just now arriving. With the stabilizing of the AJAX space, and the resources of a company like Google behind it, XML as a binding language has a great deal to offer and very little downside.
Kurt Cagle is the managing editor for XMLToday.org and a software developer/architect/writer focusing on the web technologies space.
This article was first published as Simplify Your Apps with the XML Binding Language 2.0 on the DevX.com network.
- Kurt Cagle's blog
- Add new comment

- Quote
- 708 reads


Re: Making Web Apps Well Behaved with Google's XBL2
Google
A powerful search engine far away from others
An attractive set of applications and tools
But poorly language using and heavy implementation with misunderstanding of basic rules of html/xhtml
Far away of markup style, just hacking the language for fast implementation
Google is know on going to implement HTMLX (X>4) but HTML basic is not yet fully implemented (4 & XHTML)
As I read on Twitter: HTML5 is like IPv7
Re: Making Web Apps Well Behaved with Google's XBL2
I sure hope XBL's time has come. I find it much cleaner and easier to grasp and write than XSL, and it's also easier to follow and adapt than a JavaScript library with all aspects mixed in together. Will also be nice for cleaning up/extending the HTML so semantics can be added without the whole <div/span class=""/> extraneousness. I hope CSS Namespaces support will accompany it.
By the way, how do you tell if it is Google's project or not? Their code site lets anyone start an open source project. I do see that the project owner does look to be focusing on an impressive array of compatibility projects.
Re: Making Web Apps Well Behaved with Google's XBL2
This one specifically was pointed out to me as being a Google project by a Google employee, so I can say with reasonably high certainty that it comes from there.
I too would like to see XBL more widely adopted. There are a lot of possibilities with XBL, and I think that if more people can build separation of concern apps with it the chances are pretty good that it will, in time, become relatively commonplace.
Re: Making Web Apps Well Behaved with Google's XBL2
It's not from Google. Sergey Ilinsky wrote it - http://ilinsky.com/
He seems to have abandoned it and is putting his effort into AmpleSDK - http://www.amplesdk.com/
I agree that XBL has great potential. JS implementations (like the one you've referenced) have significant limitations, mostly because they can't hide the binding's shadow-tree from the page. See http://weblogs.mozillazine.org/roc/archives/2008/03/not_a_crossbrow.html for a discussion.
A few comments on this article and the twitter sample code:- The fact that Ian Hickson works for Google is irrelevant to the XBL2 spec.. - The sample code does not have a default namespace declaration for the HTML inside the template. - The article and sample code implies that the binding implementation is added as an interface of the bound-element, so that the "this" pointer in a handler or method will be the bound-element. This is incorrect. Code inside the binding will access the binding-object using the "this" pointer, and the bound-element via "this.boundElement". "shadowTree" is a property of the binding not the element. Thus XBL2 can have more than one binding attached to an element. - There is no xblBindingDetached() method. You could use xblLeftDocument()
- methods of the binding implementation can appear on the bound-element (if they don't override a default method), but when they are called ( eg element.method() ) then the "this" pointer in the method body points to the binding-object, not the element.- <twitter frame="myframe" /> isn't valid. Why not use <div class="twitter"><a target="myframe"></a></div>- As you mention, a cross-platform JS implementation of XBL doesn't necessarily facilitate cross-platform bindings. It could, however, be combined with a JS standards library, of which there are a few.
Re: Making Web Apps Well Behaved with Google's XBL2
Thanks for the corrections - it is sometimes hard to tell with Google projects.
The shadow tree issue is a major problem, and was a major problem with Firefox's XBL implementation as well.
I will definitely take a look at Ample SDK.
Re: Making Web Apps Well Behaved with Google's XBL2
Sorry for those points all ending up in one paragraph. Blame cut-and-paste.