Sign In/My Account | View Cart  
advertisement


Listen Print Discuss

Web-based XML Editing with W3C XML Schema and XSLT, Part 2
Pages: 1, 2, 3

MetaXSL+

What we need is an XSLT stylesheet which takes our XSD and transforms it into the corresponding XSL+. The concept applied is the same as the concept used for the generation of XSLGUI. The stylesheet which generates the XSL+ is called MetaXSL+ here.

XML Schema to XSL+ processor
Figure 3. XML Schema to XSL+ processor

The basic task of the MetaXSL+ is as follows:

  1. For every element make an xsl:template with the match attribute equal to the name of the element.
  2. If the element is a datatype element, add it and the functions needed to produce the value of the element to this xsl:template
  3. If the element is complexType, add the xsl:apply-templates select="*" function
  4. For every element make an xsl:template with the match attribute equal to insert-elementName where elementName is the name of the element.
  5. If the element is complexType, add each child element (recursively) N times where N is the minOccurs of the child element

Creating new instance documents

We saw that the XSL+ is able to transform an insert-elementName tag into the corresponding element with the correct body. Now making an instance of Person.xsd is nothing else but a insert-person tag in a document (bootstrap). All we need is an XSLT which finds the first element of our XSD (person) and creates an XML+ document which consists of only one line namely:

<insert-person>

The following XSLT does the trick:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="xsd:element">
<xsl:variable name="inserttag" 
                 select="concat('insert-', @name)"/>
  <xsl:element name="{$inserttag}"/>
</xsl:template>
</xsl:stylesheet>

Using the same cycle as described above this new XML+ document will be transformed into an instance document using the XSL+. The result will be

<xsl:element name="person">
  <xsl:element name="name"/>
  <xsl:element name="date_of_birth"/>
  <xsl:element name="phone"/>
</xsl:element>

which is an initial instance of Person.xsd.

Inserting elements which do not appear in the instance document

The question now is how can we add an element which does not appear in the new instance document (an element with "minOccurs=0") such as the course in a new person instance or the course_code in a new course element.

There are different approaches possible:

  1. When making a new instance document, add all the elements to the document, including elements with a minOccurs equal to zero. This approach is an easy way out, and even though the created instance document is a valid document, it is not what we expect: an empty element is not equal to not having that element in the instance document.
  2. Adjust the XSLGUI so that it generates plus signs after each element. In our person example we would have a plus sign for course after name, one after date_of_birth and one after phone. This way if the user clicks on either of the first two plus signs the course element will be inserted at a place which is not allowed according to our XSD. An insert-course after the phone element will be valid. For an instance document with a huge number of elements this approach can be frustrating for the user as there will probably be lots of attempts before the user can find a valid location.
  3. Find a way through trial and error (validation) to know exactly where plus signs are meaningful and give that knowledge to the XSLGUI stylesheet. Conceptually it is an elegant solution but technically it is quite an effort to implement.
  4. Another solution and the one chosen in this article is to produce plus signs for the children of a complexType element at that level as follows. For all the children, if the child has a minOccurs equal to 0, and if the number of element occurrences in the document is equal to 0, produce a plus sign at the level of the complexType element containing the children.

In our example person is a complexType and its child course has a minOccurs equal to 0. The XSLGUI will be generated as follows:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:strip-space elements="*"/>

  <xsl:template match="person">
    <xsl:param name="root">
      /person
    </xsl:param>
    <xsl:variable name="index">
      1
    </xsl:variable>
    <html>
    <head>
      <title>person</title>
    </head>
    <body>
    <form name="xmsForm" action="xms.InputPage"
                            method="post">
      
      <!-- The output of the following will look 
              like:
              <a href="javascript:submitForm(
                          '/person[1]/course', 
                          'insertfirstposition');"
                    onClick="submitForm(
                            '/person[1]/course',
                            'insertfirstposition'); 
                            return false;">
                            Add course +
                            </a>
      -->              
<xsl:variable name="courseCount" 
                          select="count(course)"/>
      <xsl:if test="$courseCount='0'">
        <a>
          <xsl:attribute name="href">
            <xsl:value-of 
              select="concat('javascript:submitForm(', 
                              "'",'/person[',
                              $index,']','/course',
                              "'",',',
                              "'",
                              'insertfirstposition',
                              "'",');')"/>
          </xsl:attribute>
          <xsl:attribute name="onClick">
            <xsl:value-of 
              select="concat('submitForm(',
                              "'",'/person[',
                              $index,']','/course',
                              "'",',',
                              "'",
                              'insertfirstposition',
                              "'",'); 
                              return false;')"/>
          </xsl:attribute>Add course +
        </a>
      </xsl:if>
      <xsl:apply-templates>
        <xsl:with-param name="path" 
                           select="$root"/>
      </xsl:apply-templates>
      <input type="submit" name="action" 
                              value="save"/>
    </form>
    </body>
    </html>
  </xsl:template>
  ...
</xsl:stylesheet>

Now at the person level (top level), if the user clicks on the plus sign to insert a course, a request will be sent to the server with the action insertfirstposition and the XPath parameter will be /person/course. We know that the new instance document does not contain any course elements (otherwise we would not get a plus sign for course), so there is no way we could know where to insert a course element. All we know is that it has to be inserted at /person. Then, beginning at the first position in /person, insert the course and validate the document. If valid, we will use the XSLGUI to produce the GUI; otherwise, we will insert the element at the next position till we find a valid position for the course. This approach inserts the element at the first allowed location in the original instance document. Note that it might be desirable to insert the element not at the first possible location but somewhere else. This could become an issue in very complex combinations of elements.

The XUpdate document used to insert the new element at different positions is as follows:

   <?xml version="1.0" encoding="ISO-8859-1"?>
  <xu:modifications 
       xmlns:xu="http://www.xmldb.org/xupdate">
    <xu:append select="/person[1]" 
                  child=index>
       <xu:element name="insert-course"/>
    </xu:append>
  </xu:modifications>

Where index starts at 0 and increases by one till there is a valid position found.

Conclusion

This article described a concept in which elements can be inserted into an XML instance document through an auto-generated, form-based GUI, based on the XML Schema of the instance document and XSLT. The capability of editing and inserting or removing elements using the corresponding XML Schema makes it a complete and functional approach for the implementation of an XML web-based editor.

Resources


Comment on this articlePost your questions or comments on this article in our forum.
(* You must be a
member of XML.com to use this feature.)
Comment on this Article


Titles Only Titles Only Newest First
  • Support for choose option
    2006-04-03 14:12:02 Ram_Peri [Reply]

    Hi Ali, Arjan,
    Your approach to generating schema based froms is commendable. There are a few things that are not supported currently.
    1) Support for all basic types (string enum, integer, boolean etc.)
    2) Conditions.


    I am more interested in discussing how the choose option can be supported in the MetaXSLgui


    I have the following solution in mind, since I used a similar approach in my project.


    Generate the forms for all the children under the choose parent. Add javascript to enable(display) the child depending on the value to which the choose option is bound to.


    e.g. choose (condition) optionA optionB ...


    For sake of simplicity let us assume that the choose option is bound to the value of a parent element. Now we can generate javascript code around this element to display the appropriate subtree depending on the selection.
    Please comment. Thanks,
    -Ram



  • MetaXSLgui doesn't work?
    2003-08-19 16:35:46 Anthony Hope [Reply]

    Hi, I'm just taking my first, stumbling steps through the XML jungle at the moment, and I was trying to use Xalan to transform the Person.xsd schema using the MetaXSLgui stylesheet in your article. But it didn't work.


    All I get when I invoke Xalan is a single line:


    prompt% java Stylizer MetaXSLgui4.xsl person.xsd
    <?xml version="1.0" encoding="UTF-8"?>


    Not much for you to go on, I know, but is there a slight chance you might be able to tell me what I'm doing wrong?

    • MetaXSLgui doesn't work?
      2003-08-20 01:10:09 Anthony Hope [Reply]

      I just figured it out: I had to recompile the Stylizer app with namespace-awareness switched ON.


  • a generic solution
    2003-08-11 05:18:37 Ali Mesbah [Reply]

    As the article describes, the XSLgui is generated specifically by the
    MetaXSLgui using a Schema. Therefore the generated XSLgui is in our
    example specific to "person.xsd".
    For every new Schema, the MetaXSLgui generates a new XSLgui.
    However, the MetaXSLgui is not bound
    to a specific Schema (hence the name Meta). Bear in mind that the
    sample code given here for MetaXSLgui is only an example of a possible
    MetaXSLgui.
    The task of MetaXSLgui is to transform any given XML Schema into a XSLgui
    which in turn can transform an instance document into a GUI.

  • a generic solution
    2003-07-29 08:49:39 Erik Ostermueller [Reply]

    Is the physical .xsd used in the runtime process you're describing? It didn't look like it was.
    It looks like the xslt is peppered with different parts of the original person.xsd.


    Your xslt is tied to this particular schema (Person.xsd). I'm looking for a solution that works for any schema.


    The process might look like this:


    1) Create a schema by hand.
    2) run a code generator that creates a functional UI solely based on the information found in the schema. Like your solution, the UI would contain
    the four CRUD methods to maintain instance documents of the schema.
    3) The generated UI could be later enhanced with meta data that suggested which UI controls to use (radio buttons, check boxes, lists, etc).


    Chiba, Cocoon Forms and SchemoX come close to these requirements. HOwever, they're either not very mature or forgotten/unattended projects.


    SchemaWizard (http://ptlportal.communitygrids.iu.edu/schemawizard/index.html) is a good start, but it also looks like a 'lost child'.


    Perhaps we need to pool our resources to get this done.


    Erik Ostermueller
    erik.ostermueller@fnf.com

    • a generic solution
      2003-08-11 05:20:47 Ali Mesbah [Reply]

      As the article describes, the XSLgui is generated specifically by the
      MetaXSLgui using a Schema. Therefore the generated XSLgui is in our
      example specific to "person.xsd".
      For every new Schema, the MetaXSLgui generates a new XSLgui.
      However, the MetaXSLgui is not bound
      to a specific Schema (hence the name Meta). Bear in mind that the
      sample code given here for MetaXSLgui is only an example of a possible
      MetaXSLgui.
      The task of MetaXSLgui is to transform any given XML Schema into a XSLgui
      which in turn can transform an instance document into a GUI.

  • very nice
    2003-06-27 16:07:13 Eric Hanson [Reply]

    This is an exciting development, nice work! I wonder if there are similar efforts using other schemas, like RELAX NG.


    Eric

    • very nice
      2009-01-15 12:00:57 nico_deb [Reply]

      Yes, that exists :
      http://debeissat.nicolas.free.fr/forms.php
      There is a XSLT converter between XSD and RelaxNG so that should work with XSD input as well.