Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Simplify Your Apps with the XML Binding Language 2.0 : Page 2

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.


advertisement

Building a Basic Binding

The binding xml file itself consists of a containing [xml]<xbl>[/xml] element which in turn wraps an optional <script> element and one or more [xml]<binding>[/xml] elements, each with it's own unique id. The XBL binding in turn is broken up into up to four distinct sections:

<xbl>   <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 java-script that this supports can either be placed inline or could be specified as a distinct file referenced by the [xml]@src[/xml] 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. See Listing 1).

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 java-script, 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 (see Listing 2).

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:

<xbl xmlns="http://www.w3.org/ns/xbl"> <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 java-script 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:

<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> </pre></code> <p> The same stylesheet could also be referenced as an external file via the [xml]@src[/xml] attribute. <p> <pre><code> <resources>   <style src="twitter.css"/> </resources>

The <prefetch> element (also part of [tt]<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:

<resources>   <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:

<xbl xmlns="http://www.w3.org/ns/xbl"     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 (see Listing 3).

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 namespace httpclient = "http://exist-db.org/xquery/httpclient"; 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 as 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 java-script 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 contributing editor for O'Reilly Media. He is currently working on a book about XBRL. Follow him on Twitter at twitter.com/kurt_cagle.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap