Here is the description of the content of the RNGtoHTMLform.xsl transformation.

The main RelaxNG markups are converted into XHTML markups and information about the XML structure is inserted into the form.

the generation of XML from the values entered in the form is further explained there.

Form generation

Follow the steps

  1. Enter some RelaxNG specification in the textarea.
  2. Click on "transform ->" to get the XHTML form generated from that specification.
  3. You have the generated markups in the textarea and its displayed result.

Benefits

Generating web forms from XML specifications creates the bridge between data description and ways to create and modify data.

It also reduces the pain of writing and updating all the XHTML markups needed in a form.

Explanation

Generation of XPath pointer

Each input field of the generated XHTML form will have a "name" attribute containing a XPath expression which designates the place of that value in the XML to generate. Let us take an example with a piece of RelaxNG schema :

<rng:element name="root">
	<rng:attribute name="att">
		<rng:data type="string" />
	</rng:attribute>
</rng:element>
That specifies a XML like that one :
<root att="aString" />
The resulting XHTML form must be :
<label>att</label>
<input type="text" />
In order to be able to generate valid XML from that form, we will set the attribute "name" of the input tag to the XPath expression : "/root/@att". that means the value entered here will be the value of the attribute "att" of the root markup "root". That gives that XHTML :
<label for="/root/@att">att</label>
<input type="text" name="/root/@att" />
So, for each of the RelaxNG markup found in the schema, a behaviour is defined in the XSLT. Those behaviours are explained below.

Correspondances table

RelaxNG markupbehaviour
/ <form>
grammar namespaces declaration : <namespace prefix="" uri=""/> ...
start initializes the variable pathInXml to ''
ref go to its definition in schema or included schema(s) if not found
include look to the definition in schema(s) included
define continues browsing
interleave continues browsing
optional opens a <div class="optional">
anyName not supported
zeroOrMore ou oneOrMore adds "+" and "-" buttons opens a <div class="multiple"> adds "[]" to pathInXml
element adds namespace prefix to the markup name replaces previous "[]"(if exists) by a suffix "[1]" adds the result to pathInXml (with "/" between) if the following markup is text or data, adds a <label> otherwise, opens a <p>
list if followed by <zeroOrMore> or <oneOrMore> and then <choice>, creates checkbox for each value otherwise continues browsing
choice opens a <select> markup if followed by value, adds an attribute sendselect="yes", the value selected will be sent to generate XML otherwise, adds an option for each ref or element found and a hidden div containing the content of that choice
attribute adds "/@attributeName" to pathInXml opens a <p> and adds a <label>
text creates a <textarea>
data type="boolean" creates two radio buttons "true" and "false"
data type="anyURI" creates an <input type="file" />
data creates an <input type="text" />
documentation opens a <div class="documentation">

Work around firefox XSLT processor issue

Problem is that firefox XSLT processor does not support XPath axis "namespace::". So it is not possible to retrieve in the XSLT transformation, the namespaces declared in the XML currently analyzed. In my case, that creates a problem when I attached their prefix to the names of the markups. In order to do that, I get the namespace of the markup defined in the schema and I browse the MAIN namespaces (declared in the main schema) in order to retrieve the corresponding prefix.

When the XSLT transformation is done by firefox XSLT processor, I can not have access to that namespace declaration which could normally be stored in global variable "namespaces" that way :

	<xsl:variable name="namespaces" select="/rng:grammar/namespace::*"/>
What I do to work around that issue is that, before triggering the XSLT transformation, I parse the XML document with javascript functions, and for each "xmlns:..." namespace declaration, I add a special markup "nsp:namespace" under the "grammar" markup of the RelaxNG schema. The code for that is :
var grammarNode = xml.getElementsByTagNameNS("http://relaxng.org/ns/structure/1.0","grammar").item(0);
if (grammarNode) {
	var grammarNodeAttrs = grammarNode.attributes;
	for (var i = 0; i < grammarNodeAttrs.length; i++) {
		if (grammarNodeAttrs[i].nodeName.match('xmlns')) {
			var namespace = xml.createElementNS("namespace_declaration","nsp:namespace");
			var prefix = grammarNodeAttrs[i].localName.replace(/^xmlns$/,"");
			namespace.setAttribute("prefix",prefix);
			namespace.setAttribute("uri",grammarNodeAttrs[i].value);
			grammarNode.appendChild(namespace);
		}
	}
}
So the resulting "nsp:namespace" markup has two attributes "prefix" and "uri". Empty prefix is supported.

Participation

All those developments are released under Cecill licence.

The project Forms Generator is available on a svn, contact me for more information. In the future, a project might be created on sourceforge.

Projects svg 3d, XSD to RelaxNG converter, javascript SAX parser, javascript RelaxNG validator, javascript datatype library are published on Google code. Project javascript SAX parser is also published on Github.

Requirements

In order to have javascript working as expected, please use last version of firefox.

For the applets, you will need to have java installed on your computer.