XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

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

The first thing we need to do is to extend our MetaXSLGUI which was presented in the previous article, so that the generated XSLGUI knows where and when to generate plus signs. The following is what our XSLGUI would look like after the extension:

<?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="course">
    <xsl:param name="path"/>
    <xsl:variable name="index">
      <xsl:number count="course"/>
    </xsl:variable>
<xsl:variable name="maxOccurs" select="3"/>
    <xsl:variable name="nodeCount" 
                     select="count(../course)"/>
    <b>course </b>
<xsl:if test="$nodeCount < $maxOccurs">
      <a>
        <xsl:attribute name="href">
          <xsl:value-of 
            select="concat('javascript:submitForm(',
                            "'",$path,
                            '/course[', $index,']',
                            "'", ',', 
                            "'",'insert',
                            "'",');')"/>
        </xsl:attribute>
        <xsl:attribute name="onClick">
          <xsl:value-of 
            select="concat('submitForm(',"'",
                            $path,'/course[', $index, 
                            ']', "'", ',', 
                            "'", 'insert', 
                            "'", '); 
                            return false;')"/>
        </xsl:attribute>
        +
      </a>
    </xsl:if>
    <xsl:apply-templates select="*">
      <xsl:with-param name="path" 
        select="concat($path,'/course[', $index,']')"/>
    </xsl:apply-templates>
  </xsl:template>
  ...
  <xsl:template match="phone">
    <xsl:param name="path"/>
    <xsl:variable name="index">
      <xsl:number count="phone"/>
    </xsl:variable>
<xsl:variable name="maxOccurs" select="3"/>
    <xsl:variable name="nodeCount" 
      select="count(../phone)"/>
    <b>phone: </b>
    <!--  The output of the following will look like
             this: <input name="/person/phone[2]" 
                        value="0630458920"/> 
    -->
    <input>
      <xsl:attribute name="name">
        <xsl:value-of 
          select="concat($path,'/phone[', 
                         $index,']')"/>
      </xsl:attribute>
      <xsl:attribute name="value">
        <xsl:value-of select="text()"/>
      </xsl:attribute>
    </input>
<xsl:if test="$nodeCount < $maxOccurs">
      <!--  The output of the following will look 
               like: 
               <a href="javascript:submitForm(
                                    '/person/phone[2]',
                                    'insert');" 
                     onClick="submitForm('
                              /person/phone[2]',
                              'insert'); 
                              return false;">
                              +</a> 
      -->
      <a>
        <xsl:attribute name="href">
          <xsl:value-of 
            select="concat('javascript:submitForm(', 
                           "'",$path,
                           '/phone[', $index, ']',
                           "'", ',', 
                           "'", 'insert',
                           "'", ');')"/>
        </xsl:attribute>
        <xsl:attribute name="onClick">
          <xsl:value-of 
            select="concat('submitForm(',"'",
                           $path,'/phone[', $index,']',
                           "'", ',',
                           "'", 'insert',
                           "'",'); 
                           return false;')"/>
        </xsl:attribute>
        +
      </a>
    </xsl:if>
  </xsl:template>
  ...
</xsl:stylesheet>

Here is the extended MetaXSLGUI.

The value of the maxOccurs attribute in the XSD is passed to the template of the element. On every match the number of elements in that position in the document is counted and set as nodeCount. Then a check is done to see if nodeCount is smaller than the maxOccurs of the element. If that is the case the element will get a plus sign. The plus sign is then a link which submits our form with the appropriate parameters. (We could use the same trick to add minus signs to remove elements from the instance document.)

0

When the user clicks on the plus sign next to the second course, a request will be sent to the server with the XPath position of the element for which an insert is requested. It is possible to insert the element before or after the element with the plus sign. In this example we insert the element before the element with the plus sign. Using the XPath notation we know that the new course element has to be inserted before the second course in the person element. The server makes an XUpdate document with an insert-before command:

<?xml version="1.0" encoding="UTF-8"?> 
<xu:modifications 
       xmlns:xu="http://www.xmldb.org/xupdate">
  <xu:insert-before select="/person/course[2]">
    <insert-course/>
  </xu:insert-before>
</xu:modifications>

We don't insert the course element itself but, rather, an insert-course element instead. The reason for that is because at the server side we do not have any knowledge of the structure of the element that has to be inserted. All we know from the incoming request is that the user requests to insert a course element before the second course element (/person/phone[2]).

This XUpdate document will be executed on a temporary copy of the original (Marc.xml) instance document. Now we have an XML document (labeled as XML+) with an additional tag which is not defined in our XSD but is merely meant as a temporary help tag:

<?xml version="1.0" encoding="UTF-8"?>
<person 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="Person.xsd">
        
  <name>Marc</name>
  <phone>0153816546</phone>
  <phone>0630458920</phone>
  <date_of_birth>1978-01-21</date_of_birth>
  <course>
    <course_name>TCP/IP</course_name>
    <course_code>T465</course_code>
  </course>
<insert-course/>
  <course>
    <course_name>Java Programming</course_name>
    <course_code>J867</course_code>
  </course>    
</person>

See the following figure.

Inserting elements

Figure 2. Inserting elements

To be able to transform this XML+ to our XML document, we have to have an XSLT which knows how to substitute an <insert-elementName/> tag with the element tag it should really be. This XSLT (called XSL+) is created using the XSD. In this XSLT for every element of the XSD the corresponding match is created with the element(s) which has to substitute the insert-tag in XML+. The XSL+ has the function of substituting the insert tag while keeping the original structure and values of the elements intact

The following shows parts of the XSL+:

<?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:element name="person">
      <xsl:apply-templates select="*"/>
    </xsl:element>
  </xsl:template>
  ...
  <xsl:template match="insert-phone">
    <xsl:element name="phone"/>
  </xsl:template>
  
  <xsl:template match="insert-course">
    <xsl:element name="course">
      <xsl:element name="course_name"/>
    </xsl:element>
  </xsl:template>
  
  <xsl:template match="insert-person">
    <xsl:element name="person">
      <xsl:element name="name"/>
      <xsl:element name="date_of_birth"/>
      <xsl:element name="phone"/>
    </xsl:element>
  </xsl:template>
  ...
</xsl:stylesheet>

The XML+ with the insert-course tag will be transformed to a valid instance document which is the same as the original XML document plus a course element. Marc.xml would now look like:

<?xml version="1.0" encoding="UTF-8"?>
<person 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="Person.xsd">
        
  <name>Marc</name>
  <phone>0153816546</phone>
  <phone>0630458920</phone>
  <date_of_birth>1978-01-21</date_of_birth>
  <course>
      <course_name>TCP/IP</course_name>
      <course_code>T465</course_code>
  </course>
  <course>
      <course_name/>
  </course>
  <course>
      <course_name>
        Java Programming
      </course_name>
      <course_code>
        J867
      </course_code>
  </course>    
</person>

Only the course_name is added into the course element. This is because course_name has a minOccurs of 1 (by default) and course_code has a minOccurs of 0, which means that it is not a mandatory element. After validation this XML document can be transformed into a GUI using our XSLGUI, just like any other instance document.

Pages: 1, 2, 3

Next Pagearrow