20 May 2009

XForms for Bioinformatics : my notebook.


Here, I describe my experience with XFORMS:(W3C) XForms is an XML application that represents the next generation of forms for the Web. By splitting traditional XHTML forms into three parts—XForms model, instance data, and user interface, it separates presentation from content, allows reuse, gives strong typing—reducing the number of round-trips to the server, as well as offering device independence and a reduced need for scripting.

XForms currently requires the XForms-plugin for Firefox. This plugin is available https://addons.mozilla.org/en-US/firefox/addon/824. The current post was written using Mozilla XForms 0.8.6ff3.

In this post I show how to send a RDF+XML document describing a SNP to a web server using XForms. The form contains a field for the name of the SNP. It also contains a table with two columns (chromosome and position) for mapping the SNP. As this SNP could be mapped more than once on the genome (don't use this for genotyping !), the user will be able to append a row at the end of the table for each position.


Note: The file must be an Xhtml file and the form must send its data to the same domain.

The <HEAD> contains the <xforms:model> This element represents a form definition and is used as
a container for elements that define the XForms Model.

<xforms:model> contains the <xforms:instancel>. An instance defines a template for the data to be collected. Here the template is a RDF file describing a SNP. This SNP is mapped twice.
<xforms:instance id="me">
<rdf:RDF>
<bio:SNP rdf:about="">
<bio:rsId>rs25</bio:rsId>
<bio:mapping>
<bio:Position>
<bio:chromosome>chr1</bio:chromosome>
<bio:position>1000</bio:position>
</bio:Position>
</bio:mapping>
<bio:mapping>
<bio:Position>
<bio:chromosome>chr2</bio:chromosome>
<bio:position>2000</bio:position>
</bio:Position>
</bio:mapping>
</bio:SNP>
</rdf:RDF>
</xforms:instance>

We then bind the node of this instance to an unique descriptor using an xpath expression. Note that the attribute @type can be used to add a restriction to this form (for example the position must be a non-negative integer), if the form is not validated, the data won't be send to the server. A finer validation could also be performed if an XSD schema was attached to the model. Note also that the @rdf:about (a link to the ncbi for the SNP) attribute will be calculated from the name of the SNP.
<xforms:bind nodeset="/rdf:RDF/bio:SNP/bio:rsId" id="rsId" required="true( )"/>
<xforms:bind nodeset="/rdf:RDF/bio:SNP/@rdf:about" calculate="concat('http://www.ncbi.nlm.nih.gov/SNP/snp_ref.cgi?rs=',substring(../bio:rsId,3))"/>
<xforms:bind nodeset="/rdf:RDF/bio:SNP/bio:mapping/bio:Position/bio:chromosome" type="xsd:NMTOKEN" id="mapChrom" required="true( )"/>
<xforms:bind nodeset="/rdf:RDF/bio:SNP/bio:mapping/bio:Position/bio:position" type="xsd:nonNegativeInteger" id="mapPos" required="true( )"/>

We then describe how the data should be submited. Here are two <xforms:submission>: one send the data as XML just like a regular html form, the other send a mail (this second form didn't worked).

<xforms:submission action="echo.php" method="post" id="submit" ref="/rdf:RDF" instance="me" encoding="ISO-8859-1" replace="all"/>
<xforms:submission action="mailto:me@yahoo.fr" method="post" id="mail" ref="/rdf:RDF" instance="me" encoding="ISO-8859-1" replace="all"/>


Then, the input fields are written in the body of the XHTML document. Each field contains a xforms:label as well as a xforms:alert displayed if the field is not valid.
<xforms:input ref="bio:chromosome">
<xforms:label>Chr</xforms:label>
<xforms:alert class="inline">Chromosme is a xsd:NMTOKEN</xforms:alert>
</xforms:input>

For each position of this SNP, the fields are inserted in a table using <xforms:repeat>
<table border="1"><xforms:repeat nodeset="/rdf:RDF/bio:SNP/bio:mapping/bio:Position" id="repeatpositions"><tr>
<td>

<xforms:input ref="bio:chromosome">
<xforms:label>Chr</xforms:label>
<xforms:alert class="inline">Chromosome is a xsd:NMTOKEN</xforms:alert>
</xforms:input>
</td>
<td>
<xforms:input ref="bio:position">
<xforms:label>Pos</xforms:label>
<xforms:alert class="inline">Position must be greater or equals to 0</xforms:alert>
</xforms:input>
</td>
</tr></xforms:repeat></table>

A button is used to append a new row in this table:
<xforms:trigger>
<xforms:label>Insert Row</xforms:label>
<xforms:insert nodeset="/rdf:RDF/bio:SNP/bio:mapping/bio:Position" at="index('repeatpositions')" position="after" ev:event="DOMActivate"/>
</xforms:trigger>

And at the end, here are the two 'submit' buttons:
<xforms:submit submission="submit">
<xforms:label>Go</xforms:label>
<xforms:hint>Click to post</xforms:hint>
</xforms:submit>
<xforms:submit submission="mail">
<xforms:label>Mail</xforms:label>
<xforms:hint>Click to Send</xforms:hint>
</xforms:submit>

... and in the header, a little piece of CSS for styling:
<style type="text/css">
@namespace xforms url("http://www.w3.org/2002/xforms");

xforms|input {
color:blue; font-weight:bold;font-size:20px;width:500px
}

xforms|label {
color:blue; font-weight:bold;font-size:20px;width:500px
}

</style>




And here is the XML sent to the server

<rdf:RDF>
<bio:SNP rdf:about="http://www.ncbi.nlm.nih.gov/SNP/snp_ref.cgi?rs=25">
<bio:rsId>rs25</bio:rsId>
<bio:mapping>
<bio:Position>
<bio:chromosome>chr1</bio:chromosome>
<bio:position>1000</bio:position>
</bio:Position>
</bio:mapping>
<bio:mapping>
<bio:Position>
<bio:chromosome>chr2</bio:chromosome>
<bio:position>2000</bio:position>
</bio:Position>
</bio:mapping>
</bio:SNP>
</rdf:RDF>


All in one...

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:bio="http://ontology.lindenb.org/snp#"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<head>
<title>XFORM</title>
<!-- Let's add style to the XFORM components -->
<style type="text/css">
@namespace xforms url("http://www.w3.org/2002/xforms");

xforms|input {
color:blue; font-weight:bold;font-size:20px;width:500px
}

xforms|label {
color:blue; font-weight:bold;font-size:20px;width:500px
}

</style>

<!--

This element represents a form definition and is used as
a container for elements that define the XForms Model.

-->


<xforms:model>

<!-- instance defines a template for the data to be collected. -->
<xforms:instance id="me">
<!-- we send a RDF document to the server -->
<rdf:RDF>
<bio:SNP rdf:about="">
<bio:rsId>rs25</bio:rsId>
<bio:mapping>
<bio:Position>
<bio:chromosome>chr1</bio:chromosome>
<bio:position>1000</bio:position>
</bio:Position>
</bio:mapping>
<bio:mapping>
<bio:Position>
<bio:chromosome>chr2</bio:chromosome>
<bio:position>2000</bio:position>
</bio:Position>
</bio:mapping>
</bio:SNP>
</rdf:RDF>
</xforms:instance>

<xforms:bind nodeset="/rdf:RDF/bio:SNP/bio:rsId" id="rsId" required="true( )"/>
<xforms:bind nodeset="/rdf:RDF/bio:SNP/@rdf:about" calculate="concat('http://www.ncbi.nlm.nih.gov/SNP/snp_ref.cgi?rs=',substring(../bio:rsId,3))"/>
<xforms:bind nodeset="/rdf:RDF/bio:SNP/bio:mapping/bio:Position/bio:chromosome" type="xsd:NMTOKEN" id="mapChrom" required="true( )"/>
<xforms:bind nodeset="/rdf:RDF/bio:SNP/bio:mapping/bio:Position/bio:position" type="xsd:nonNegativeInteger" id="mapPos" required="true( )"/>
<xforms:submission action="echo.php" method="post" id="submit" ref="/rdf:RDF" instance="me" encoding="ISO-8859-1" replace="all"/>
<xforms:submission action="mailto:me@yahoo.fr" method="post" id="mail" ref="/rdf:RDF" instance="me" encoding="ISO-8859-1" replace="all"/>
</xforms:model>
</head>
<body>
This page requires the
<a href="https://addons.mozilla.org/en-US/firefox/addon/824">XForms plugin for Firefox</a><hr/>
<xforms:input bind="rsId">
<xforms:label>RsId</xforms:label>
<xforms:hint>Rs##</xforms:hint>
</xforms:input><br/>
<table border="1">

<xforms:repeat nodeset="/rdf:RDF/bio:SNP/bio:mapping/bio:Position" id="repeatpositions"><tr>
<td>

<xforms:input ref="bio:chromosome">
<xforms:label>Chr</xforms:label>
<xforms:alert class="inline">Chromosme is a xsd:NMTOKEN</xforms:alert>
</xforms:input>
</td>
<td>
<xforms:input ref="bio:position">
<xforms:label>Pos</xforms:label>
<xforms:alert class="inline">Position must be greater or equal to 0</xforms:alert>
</xforms:input>
</td>
</tr></xforms:repeat>
<tfoot><tr>
<xforms:group>
<xforms:trigger>
<xforms:label>Insert Row</xforms:label>
<xforms:insert nodeset="/rdf:RDF/bio:SNP/bio:mapping/bio:Position" at="index('repeatpositions')" position="after" ev:event="DOMActivate"/>
</xforms:trigger>
</xforms:group>
</tr></tfoot>
</table>

<xforms:submit submission="submit">
<xforms:label>Go</xforms:label>
<xforms:hint>Click to post</xforms:hint>
</xforms:submit>
<xforms:submit submission="mail">
<xforms:label>Mail</xforms:label>
<xforms:hint>Click to Send</xforms:hint>
</xforms:submit>
<tr/>
<hr/>
<h6><a href="mailto:plindenbaum@yahoo.fr">Pierre Lindenbaum PhD</a> |
<a href="http://plindenbaum.blogspot.com">http://plindenbaum.blogspot.com</a></h6>
</body>
</html>




That's it,
Pierre

No comments: