Why Linus Torvalds is wrong about XML

Linus Torvalds is one of the most revered figures in modern computer science and has made the kind of contributions to the world that I hope to achieve. However, given his global audience, his recent statements about XML give me pause for reflection.

I have worked with XML in a number of jobs, helped with the specification of international XML formats, written tutorials on their use, and even made my own XML format (with reason I might add). And I must say, in reply to Linus’s statement that

XML is the worst format ever designed

XML isn’t the problem, it is more that the problem is bad programmers. Computer Science is a broad field, not covering just the creation of programs, but also the correct specification of information for computation. The lack of appreciation for that second aspect has seen the recent rise of “Data Science” as a field – a mash of statistics, data management and programming.

While it is undenyable that many programmers write bad XML, this is because of poor understanding and discipline. One could equally say, people write bad code, lets stop them writing code. People will always make mistakes or cut corners, the solution is education, not reinventing the wheel.

Linus and the rest of the Subsurface team are well within their rights to use the data formats they choose, and I am eager to see what new formats he can design. But with that in mind, I will address some of the critiques of Linus and others about XML and point out their issues, followed by some handy tips for programmers looking at using XML.

XML should be human readable

I did the best that I could with XML, and I suspect the subsurface XML is about as pretty and human-readable as you can make that crap

CSV isn’t very readable, C, Perl and Python aren’t very human readable. What is “human-readable” is very subjective, as even English isn’t human-readable to non-English speakers.

Restricting ourselves to just technology, CSV isn’t very readable as for any non-trivial amount of data as the header will scroll off the top of the screen, and data will overflow onto the next line or outside the horizonal boundaries of the screen. One could argue that its possible in Excel, OpenOffice or using a VIm/Emacs plugin to lock the headers to the top of the screen – and now we have used a tool to overcome limitations in the format.

Likewise, the same can be said for computer code, code-folding, auto-completion of long function and variable names and syntax highlighting are all software features to overcome failures in the format and make the output more “human-readable”. Plain-text supports none of the above, yet no one would recommend using Notepad to write code for the lack of features.

Likewise, I would never, ever recommend writing XML in a non-XML editor. Auto-adding of closing tags, checking schema as you type, easy access to the schema via hotlinks from elements and attributes, and XPath query and replace are all vital functions of a good XML editor. All of these make writing XML much easier and approachable, and compared to code or CSV, a programmer should spend only as much time in an XML editor to understand the format to make writing XML in code easier.

While it can be said that a poor craftsman blames his tools, a good craftsman knows when to use the right tools as well.

XML files should standalone

This is most visible in this bug raised in Subsurface where it is stated that:

Subsurface only ever stores metric units. But our goal is to create files that make sense and can be read and understood without additional information.

Now, examination of a sample of the XML from subsurface shows a glaring contradiction. There is nothing in this file that says that units are in metric. The distance ‘m’ could equally stand for ‘miles’, and while the order of magnitude would make misinterpretation for a human hard, a dive computer with an incorrect understanding may miscalculate the required oxygen pressure leading to potential death. To accurately understand this file, I need to find the documentation, i.e additional information. The reason for schema is to explicitly describe a data file.

Additionally, because data is stored as “human-readable” strings, I could validly put in “thirty metres” instead of “30.0 m” as a depth. At this point the program might fail, but as someone writing the data elsewhere I’d have no reason why. Apart from being a description of the data, schema exists as a contract. If you say the data is of this form, then these are the rules you must conform to. When you are looking at sharing data between programs or organisations this ability to lean on a technical enforcement is invaluable as making “bad” data is that much harder.

XML shouldn’t need other formats

This is a tricky one, as when people think of XML, even if they have made a schema their mid stops there. XML isn’t just a format, its more a suit of related formats that can make handing and manipulating information easier.

Its worth noting that people have raised databases within that thread as an alternative – SQL is only a query language, but requires the formal Database Definition Language to describe the data and an engine to query over it. Likewise, HTML without CSS, Javascript or any number of programming and templating languages that power the web would be much less useful to the general public.

Similarly, isolating XML from XML schemas, mean your data has no structure. Isolating XML from XQuery and XPath mean you have no way of querying your data. Without XSLT there is no easy, declarative way to transform XML, and having done this with traditional languages and XSLT, the latter makes using and transforming XML much easier. Ultimately, using XML without taking advantage of many of the technologies that exist in the entire XML landscape is not using technologies to its best.

Tips for good XML

With all of that aside, XML like all technologies can be used poorly. However, when done well and documented properly, a good XML format with an appropriate schema can reduce errors and give vital metadata that gives data context and longevity. So I present a few handy tips for using XML well.

  1. Only use XML when appropriateXML is best suited to complex data, especially hierarchical data. As Linus (and others) points out in the linked thread tabular data is much better suited to CSV or more structured tablular formats, simple key values can be stored in ini files, and markup text can be done in HTML, Markdown or any number of other formats.
  2. Look for other formats.If you are thinking of using XML for your tool – stop and see what others have already done. The world doesn’t need another format, so if you are thinking of doing so you should have a very, very good reason to do so.
  3. Use a schema or doctypeIf you are chosing to make your own format, this is the most important point. If you chose to use XML, make a schema. How you choose to capture this Doctype, XSD Schema, Schematron, Relax NG is largely irrelevant. What is important is that your data format is documented. There are even tools that can automate creating schema stubs from documents, so there is no excuse not to. As stated an XML schema is the formal contract about what your data is and lets others know that if the data doesn’t conform to this format then it is broken.
  4. Use XML datatypesXML already has specifications for text, numeric, datetime and identification data. Use these as a starting point for your data.
  5. Store one type of data per field.While the difference between <dive duration="30:00 mins"> and <dive duration="30" durationUnit="mins"> is minimal, the former uses a single string for two pieces of data, while the latter uses two fields, a number and an enumerable, each storing one piece of data. An even better solution is using the XML duration data type <dive duration="PT30M"> based on the existing ISO 8601 standard.

Book Review: H.G. Wells The Time Machine

After finishing the Harry Potter series (which doesn’t need another poorly written review), I decided for something older, shorter and a little more mature and decided to tackle some books I’ve been meaning to read for a long time – namely H.G. Wells more well known works.

I fortunately found an anthology – if two stories can be called so – of H.G. Wells “The Time Machine” and “The Invisible Man”. First of all, the story is thinly veiled critique of the aristocracy of Victorian Britain, the idea that the segmentation and stagnation of class would lead to the eventual dulling of the minds of the leisure class, while the underclasses become more violent and brutish.

However, the one thing I did find interesting is the relationship between the unnamed Time Traveller, the Narrator and Weena – an Eloi woman of the future. The story can be broken into two sections, those where the Narrator introduces the cast at the start and closes the story at the end, each about a chapter or so each, while the bulk of the novel in-between is the Narrators recollection of the Time Travellers account of their travel. Here, I say their for a very important reason- by the Narrators account the Time Traveller is a man, while the Time Traveller does nothing to speak of their gender or race during the story.

The reason this is fascinating, is that during their travels the Time Traveller meets a meek, child-like Eloi woman who accompanies them on their future adventure. Reading the Time Traveller as intended as a man, presents a view of Victorian gender relations, where women were treated as child-like and in need of a man for protection. However, I found myself attempting to read the story and interpret it as though the Time Traveller could have been a woman and comparing the subtext. Reading the Time Traveller as a woman however, Weena becomes more like a child-like companion, and it reads less like a patriarchal reinforcement of a man overseeing the safety of a woman, but  more as a story of a woman managing their maternal instincts against their scientific drive and desire to return home – and funnily enough this reminded me of Aliens.

Given that people often lament the lack of female leads in fiction and movies, this seems to be one where the role could easily be played or read as a woman with very little change to the original text.

Next up, The Handmaids Tale and then The Invisible Man.

New release: Canard Question Module Editor v0.2.1

Its been a while since my last post, and while a few emails and updates to GitHub have happened, I haven’t written a formal announcement here. The big news of which two releases of the Canard Question Module Editor have been published and made available.

Version 0.2 went out on October 1st and Version 0.2.1 went out on the 9th. Normally, there’d be a larger gap between releases, however, very shortly after version 0.2 went out the door a handful of troublesome bugs were discovered regarding the handling of multilingual text. So a second version went out the door very shortly after that included some bug fixes and some new features tht made dealing with multiple languages easier.

Canard Screenshot

Additionally, the QFingerTabsWidget that was discussed in an earlier post, has seen a number of updates to allow for icons and a more responsive design of horizontal text in horizontally aligned tabs. This has become larger than just a gist and will in the coming weeks be spun of into its own GitHub repository.

Lastly, with Canard in a relatively stable state, and with the “plug-in architecture” in a usable state I’m going to focus on creating SQBL transformations for input, output and visualisation. So suggestions for target formats and languages, or updates or changes to existing plugins would be welcome in the comments.

If anyone is interested in following updates to SQBL or Canard, I’d strongly recommend following the SQBL Mailing lists to keep up to date with releases and new plugins as they are published.

Canard feature update: Bulk Question Editor

Just a nice and quick update to show off the latest addition to Canard. Post-IASSIST I’ve been working on getting a CS-Pro to SQBL converter. As a part of this I needed to actually install CSPro, and it turns out it has some pretty cool features. Not least of which was the ability to view and editor (in a simple way) all of the questions in a block.

In the words of Steves Jobs (and many, many others), Good Artists Borrow, Great Artists Steal, and I worked about implementing this in Canard. Below is a screenshot of the new Canard “Bulk Question Editor” accessible when you click on the “Flow Logic” of a module.

Screenshot of the new Canard Bulk Question Editor

Screenshot of the new Canard Bulk Question Editor

At this stage this change has been checked into the Canard GitHub for testing and will be rolled into the next release of Canard, which will be out… soon.

Book Review: Brave New World

So my latest literary outing was a re-read of Aldous Huxley’s “Brave New World”. While, there are tons of reviews that do a great job of comparing Huxley’s Brave New World with Orwells 1984 and our current surveillance state, there is one short passage from late in the book, that resonated with me this read through.

One of the principal functions of a friend is to suffer (in a milder and symbolic form) the punishments that we should like, but are unable, to inflict upon our enemies.

In the midst of a long essay on the dangers of giving ourselves over to technological advances, this quote is hidden and is, I think, one of the better, albeit more cynical, descriptions of friendship I have read.

Simple XML validation within PyQt TextEdit fields

As part of Canard, there is need for a very simple XML editor while the rich-text capabilities are finalised. So for the upcoming release, rather than work with a complex GUI, I’ve taken the easy option and will just allow the user to edit the very cut back rich text XML itself.

The complication with this is that a survey designer could write some invalid XML, which would be inserted into the rest of the document and break the entire file. The solution is to provide as-you-type validation of the XML to check that is valid. Fortunately, this is not as difficult as might be imagined, thanks to how easy to put together PyQt and Python are in general

Below is a screen shot of this little editor in action, with a very short code snippet that demonstrates how to do as-you-type XML validation inside of a PyQt application.

Simple PyQT XML Editor in action

Simple PyQT XML Editor in action

import sys
from lxml import etree
from PyQt4 import QtCore, QtGui

class editor(QtGui.QMainWindow):
    def __init__(self):
        super(editor, self).__init__()
        self.text = QtGui.QTextEdit()
        self.setCentralWidget(self.text)
        self.text.textChanged.connect(self.validate)
        
        self.statusBar()
        self.setWindowTitle('Simple XML editor')
        self.show() 
    def validate(self):
        try:
            root = etree.fromstring(str(self.text.toPlainText()))
            self.statusBar().showMessage("Valid XML")
        except etree.XMLSyntaxError, e:
            msg = e.error_log.last_error.message
            line=e.error_log.last_error.line
            col=e.error_log.last_error.column
            self.statusBar().showMessage("Invalid XML: Line %s, Col %s: %s"%(line,col,msg))
        except:
            self.statusBar().showMessage("Invalid XML: Unknown error")
        
def main():
    app = QtGui.QApplication(sys.argv)
    w = editor()
    sys.exit(app.exec_())
 
if __name__ == "__main__":
    main()

Practical XForms – Todo-list – Part 3: Adding bindings to collect the correct data

This is the third in an ongoing series that examines the practical uses of XForms by building a todo list. In this tutorial we are going to build on part 1 (where we built our data model) and part 2 (where we refined the data model to support looping). In this tutorial we will cover ways of using binds and inline schemas to correctly type the data model and use correct input types.

We left of from tutorial 2, with a user interface that looked like this:

A nearly completed XForm to-do list

A nearly completed XForm to-do list

The problem with this is that we are required to enter dates and state whether the task is complete manually. What would be preferred is if we could use a checkbox or date picker. A naive approach is to edit the interface directly, and alter the Xforms input into a checkbox. Below, we have code that generates a XForms select option that presents a series of checkboxes, however since we are dealing with binary information, we only need one item to select from:

1
2
3
4
5
<xf:select ref="@complete" appearance="full" >  
    <xf:item>
         <xf:value>true</xf:value> 
    </xf:item>
</select>
A task list with tick boxes

A task list with tick boxes

But the problem with this is that if the true value isn’t selected, rather than the value be false, it will instead be empty. Additionally there is no “date input” input type, so we’d have to make a custom date picker. We could again hack how we evaluate this value, and make custom handlers for different datatypes, or… we could type our data correctly.

Using XForms Binds to provide data-typing

XForms is very data-driven in how it operates, and conforms very strongly to the Model-View-Controller design pattern. We have already covered to View – the HTML/XForms code presented to the user – and the Model – the data model that we have designed to describe the information we hope to capture – now its time to look at the Controller aspect of XForms, the XForms bind. Binds have a lot of uses, dictating the connections between the model and the view,  they can be used to compute values, control when certain inputs are available and they can be used to provide explicit data-typing for elements in the model.

To demonstrate this we will revert the insert into our xf:model some bindings for our data:

1
2
3
4
5
6
7
<xf:bind nodeset="//task/@complete" type="xs:boolean"/>
<xf:bind nodeset="//task/@dueDate" type="xs:date"/>
<xf:bind nodeset="//task" type="xs:string" readonly="./@complete=true()"/>
<!-- later -->
<td><xf:input ref="."/></td>
<td><xf:input ref="@complete"/></td>
<td><xf:input ref="@dueDate" /></td>

Here we have reverted our complete entry field to a simple input, but have declare it to be an XML boolean datatype, similarly we have declared the due date to be an XML date and the task name to be a string. We have also demonstrated the ability to disable content based on the binding by saying that a task can only be edited if it has been completed. The end result of this simple and declarative change is shown below:

A more completed task list

A more completed task list

The above image shows several changes have taken place:

  • The complete field now has a tick-box (not shown is the fact that this will store a true or false value without further scripting required)
  • The due date field has a button with ellipses (…) that when pressed shows a date selector.
  • Although subtle, the first task and due date are grayed out indicating it has been disabled. Similarly, the button that would drop down the date selector for the first task is now gone.

So far we now have a fairly complete user interface for managing our tasks. You can see the full code for the task list on Github, or view all past code in the same repository. In the next tutorial we’ll look at an alternate way of providing datatyping  by linking to or including inline XML schemas, which can be useful when the data structure is known ahead of time. Then we’ll look at defining submission methods so we can save our data with a web server.

PyQt Interlude – Shift+Tab to de-indent text in QTextEdit

While searching for a solution to tabbing through QTableWidgets in PyQt, I found this old question on StackOverflow that needed help creating the code necessary to allow a QTextEdit to capture Shift-tab to deindent code.

Below is the thoroughly commented code that explains how all this works:

Soon another Canard update, and the next exciting installment in the XForms tutorial!

Practical XForms – Todo-list – Part 2: Looping through a dynamic data model

In the previous tutorial we began building an XForms to-do list. The last exercise left us with a to-do list that allowed us to view an edit a single task, not terribly useful, but a starting point. In this tutorial we are going to build on the first and allow a user to manage multiple tasks.

A screenshot of the complete part 1 of the todo list

Our todo list where we left off.

 Extending our data model

As with the first tutorial, the first thing we need to do is work with the data model, altering it to allow for the management of multiple tasks. To do this we will change our XForms data instance to capture a task list which itself contains a number of tasks.

1
2
3
4
5
6
<xf:instance xmlns="">
    <tasklist>
        <task complete="false" dueDate="2013-07-27">Pick up milk</task>
        <task complete="true" dueDate="2013-07-27">Make tutorial part 1</task>
    </tasklist>
</xf:instance>

Unfortunately, the XForms will continue to look the same as the inputs that were placed in HTML the first tutorial expect a single task.

Looping through the data model

Having defined our repeating data instance, writing the declarations for a repeating user interface becomes a trivial affair – we simply need to wrap our current elements in an XForms repeat (sorry for the repetition (and that pun)). The nodeset or binding in a repeat element allows us to point to a set of elements that will have the child xforms controls under the repeat applied the them.

1
2
3
<xf:repeat nodeset="/tasklist/task">
        ...
</xf:repeat>

So in the above code we are declaring that we are repeating across the task elements under the tasklist node. In this case we have been very specific, declaring the XPath for the repeated element, but  the important thing to note, is that this would repeat any matching elements. So if we had multiple tasklists, we could target all tasks by using the Xpath “//task”.

Now that we have declared what elements to loop over, the next task is to change the inputs to be relative to the repeated element, so inside the body we get:

1
2
3
4
5
6
7
8
9
10
11
<xf:repeat nodeset="/tasklist/task">
    <xf:input ref=".">
        <xf:label>Task name:</xf:label>
    </xf:input>
    <xf:input ref="@complete">
        <xf:label>Complete:</xf:label>
    </xf:input>
    <xf:input ref="@dueDate" >
        <xf:label>Due date:</xf:label>
    </xf:input>
</xf:repeat>

And our form now looks like this:

A repeating form.

A repeating form.

Sadly, while we are getting the intended repetitions, it doesn’t look right.

Intertwining HTML and XForms

What we have here isn’t just a set of some unrelated fields, but could be argued to be tabular data. So we should mark it up as such. Fortunately, inside a repeat element everything is repeated, not just the XForms controls. So, by adding a table wrapper with appropriate headings, we can wrap the repeat like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<table>
    <thead>
        <tr>
            <th>Task name</th>
            <th>Complete</th>
            <th>Due date</th>
        </tr>
    </thead>
    <tbody>
        <xf:repeat nodeset="/tasklist/task">
            <tr>
               <!-- Each xf:input wrapped in its own td -->
            </tr>
        </xf:repeat>
    </tbody>
</table>

Since we now have labels for each field in the header, we can remove them and we get something that looks like this:

A tabular to-do list

A tabular to-do list

This could have also been done using only CSS (and I’ll leave the arguments about table layouts for the comments).

Reviwing our HTML+XForm so far

Now is a good point to show all of the code and look at the changes. So far this tutorial we’ve extended the data model, wrapped our inputs inside of a repeat, and we’ve remove the labels in lieu of table headers and remove the CSS as our inputs are now wrapped in table cells:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml-stylesheet href="xsltforms/xsltforms.xsl" type="text/xsl"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms" >
    <head>
        <title>XForms todo list</title>
        <xf:model>
            <xf:instance xmlns="">
                <tasklist>
                    <task complete="false" dueDate="2013-07-27">Pick up milk</task>
                    <task complete="true" dueDate="2013-07-27">Make tutorial part 1</task>
                </tasklist>
            </xf:instance>
        </xf:model>
    </head>
    <body>
        <table>
            <thead>
                <tr>
                    <th>Task name</th>
                    <th>Complete</th>
                    <th>Due date</th>
                </tr>
            </thead>
            <tbody>
                <xf:repeat nodeset="/tasklist/task">
                    <tr>
                        <td><xf:input ref="."/></td>
                        <td><xf:input ref="@complete"/></td>
                        <td><xf:input ref="@dueDate" /></td>
                    </tr>
                </xf:repeat>
            </tbody>
        </table>
    </body>
</html>

Adding and deleting tasks

To now we’ve only been able to manage tasks that already are in the data model, so the next step is to be able to add tasks of our own and delete old ones. To do this we need to add some buttons to the interface. In XForms the HTML button is replaced by an XForms trigger. So if we insert this code after the table:

1
2
3
<xf:trigger>
    <xf:label>Add Task</xf:label>
</xf:trigger>

Gives us this:

Todo list with a new button

Todo list with a new button

However, at this point the button still does nothing, we need to attach an action or multiple actions to perform for a specific XForms event for this trigger. Actions can be performed for a number of reasons, such as the XForm being refreshed, when data elements are deleted or, as in this case, when a button is triggered. So we can attach an action to the trigger like so:

1
2
3
4
5
6
<xf:trigger>
    <xf:label>Add Task</xf:label>
    <xf:action ev:event="DOMActivate">
        <xf:insert nodeset="/tasklist/task" at="last()" position="after" />
    </xf:action>
</xf:trigger>

In this example, we have an action that is fired when this button is “activated”, and this triggers a task to be inserted at the end of the tasklist after the last element. However, the way this works, it will duplicate the last element, so we can remove the data in the new element like this:

1
2
3
4
5
6
7
8
9
<xf:trigger>
    <xf:label>Add Task</xf:label>
    <xf:action ev:event="DOMActivate">
        <xf:insert nodeset="/tasklist/task" at="last()" position="after" />
        <xf:setvalue ref="/tasklist/task[last()]" value="" />
        <xf:setvalue ref="/tasklist/task[last()]/@complete" value="false()" />
        <xf:setvalue ref="/tasklist/task[last()]/@dueDate" value="'1970-01-01'" />
    </xf:action>
</xf:trigger>

Here we have set the value of the texts and clears or resets the form data of the new element using the XPath evaluation in the @value attribute – hence the double quotes and the false() function. This gives us this:

A task list with a new task!

A task list with a new task!

The last thing to do is add a trigger to delete the currently selected row. This is very much like the last:

1
2
3
4
5
<xf:trigger>
    <xf:label>Delete task <xf:output value="index('tasks')"/>
    </xf:label>
    <xf:delete ev:event="DOMActivate" nodeset="/tasklist/task" at="index('tasks')"/>
</xf:trigger>

The two differences are that we have use the ability to shortcut how events are attached to actions. Rather than use an action element, we can attach the event attribute directly to the specific action itself. Secondly, we’ve also added an output element so we can see which task we are about to delete based on the index of the repeat element (which we have now given the id “tasks” to refer to). We can also style the currently listed row using CSS:

1
2
3
.xforms-repeat-item-selected * {
    background-color: #DDF;
}

All up this gives us:

A nearly completed XForm to-do list

A nearly completed XForm to-do list

A nearly complete To-do list! The code is starting to grow, but you can check out the code on the XForms To-do List Github.

In the next tutorial we will look at how we can provide data validation that will both alter our data and interface, and edit the inputs to provide hints when invalid data is entered.

Practical XForms – Todo-list – Part 1: Building and showing the data model

There was a recent post on Stack Overflow that was looking for the simplest way to create  a simple Todo list in HTML. Many of the comments highlighted the fact that HTML really has no dynamicness “built-in”" and began offering different Javascript libraries for building complex UIs and how to manage the connection between the two. Sadly the post was removed as a duplicate before I got a chance to offer an alternative – XForms. Despite low browser uptake, I am quite the fan of XForms, and given mature tools like XSLTForms that allow you to build an XForm and deploy to any XSLT enabled browser (which is almost all of them now). So with that long introduction done, I present this simple introduction to developing with XForms.


The to-do list is probably the second most prevalent programming tutorial available after “hello-world” especially for GUI development. So I present a simple tutorial to build a to-do list in XForms to offer a gentle introduction into the power of novel language. Before continuing you should probably have a small understanding of how to make forms in HTML, XML and XPath.

Building our data model

XForms has a strong adherence to the MVC paradigm and its strong separation of data and presentation so the first thing we can do is describe our data model. Given that we are building a simple to-do list at this stage we need to be able to capture 3 things:

  1. The task name
  2. The due date and
  3. If the task has been completed

Now given that all data for an XForm is captured within an XML document, we can immediately begin to know that our data model is going to look something like this:

1
<task complete="false" dueDate="2013-07-27">Pick up milk</task>

By wrapping this in an XForms:model element, we are done describing our data model. and convention dictates that this goes in the head of a document so, wrapping this all up in XML we get…

1
2
3
4
5
6
7
8
9
10
11
12
<?xml-stylesheet href="xsltforms/xsltforms.xsl" type="text/xsl"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms" >
    <head>
        <title>XForms todo list</title>
        <xf:model>
            <xf:instance xmlns="">
                <task complete="false" dueDate="2013-07-27">Pick up milk</task>
            </xf:instance>
        </xf:model>
    </head>
    <body/>
</html>

Along with the model there is some boilerplate HTML and an XML directive that calls XSLTForms so we can preview this in a web browser. Sadly, since we only have only defined our data there is nothing to see, yet…

Interacting with the data model

So with a piece of data defined, we can start building a way to actually interact with this. This is done through XForms input fields. Inserting an XForms element is very similar to using regular HTML inputs, however rather than giving it a name we need to point to an element or binding (which we will cover later) to store and retrieve data from.

1
2
3
<xf:input ref="//task" />
<xf:input ref="//task/@complete" />
<xf:input ref="//task/@dueDate" />

These pointers are either named bindings, or in the case above an XPath to an element in the data model. In the first we are pointing to the //task node, which will use the text of that node for the field, however in the others we are pointing to an attribute, eg. //task/@dueDate .

However, in the above case it will just a field with no label or indication of what it is, so we will add a label as well (I’ll just demonstrate the label task name):

1
2
3
<xf:input ref="//task">
    <xf:label>Task name:</xf:label>
</xf:input>

So now our complete document looks something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml-stylesheet href="xsltforms/xsltforms.xsl" type="text/xsl"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms" >
    <head>
        <title>XForms todo list</title>
        <xf:model>
            <xf:instance xmlns="">
                <task complete="false" dueDate="2013-07-27">Pick up milk</task>
            </xf:instance>
        </xf:model>
    </head>
    <body>
        <xf:input ref="//task">
            <xf:label>Task name:</xf:label>
        </xf:input>
        <xf:input ref="//task/@complete">
            <xf:label>Complete:</xf:label>
        </xf:input>
        <xf:input ref="//task/@dueDate" >
            <xf:label>Due date:</xf:label>
        </xf:input>
    </body>
</html>

And it looks like this:

A screenshot of the partially complete todo list

Our basic to do list

Now, there are a lot of flaws with this the two big ones being that we can only manage one task, and we have defined what is valid data for any of our fields. But we’ll take care of these in the next two tutorials. But for now, we’ll fix one flaw and add a little CSS styling to present the form in a better way to finish off this example. What we want is to have each field on their own line and have the fields all line up. Fortunately this is easy in to achieve in CSS:

1
2
3
4
5
6
7
.xforms-input  {
   display:block;
}
.xforms-label {
    display:inline-block;
    width:5em;
}

Because we’re using an internal CSS stylesheet, we need to use the CSS classes that target the HTML generated by XSLTForms, but when using an external stylesheet namespace CSS selectors can be used. Adding this into the document we get the following code (which you can very and fork on GitHub):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml-stylesheet href="xsltforms/xsltforms.xsl" type="text/xsl"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms" >
    <head>
        <title>XForms todo list</title>
        <xf:model>
            <xf:instance xmlns="">
                <task complete="false" dueDate="2013-07-27">Pick up milk</task>
            </xf:instance>
        </xf:model>
        <style type="text/css">
            .xforms-input {
            display:block;
        }
        .xforms-label {
            display:inline-block;
            width:5em;
        }
        </style>
    </head>
    <body>
        <xf:input ref="//task">
            <xf:label>Task name:</xf:label>
        </xf:input>
        <xf:input ref="//task/@complete">
            <xf:label>Complete:</xf:label>
        </xf:input>
        <xf:input ref="//task/@dueDate" >
            <xf:label>Due date:</xf:label>
        </xf:input>
    </body>
</html>

and it looks like this:

A screenshot of the complete part 1 of the todo list

Our final todo list

And there we have it a very simple, XForm built on a pre-defined data model using a declarative language that required very little coding to get done. In the next tutorial we will look at how we can alter our data and interface to display and edit multiple tasks as well as adding and deleting tasks.