Database-backed Application pt3
Using NetKernel with a DB to create an Address book application
Release Notes
REST Service
Batch Processing
Intray PDF Distiller
Database-backed Application pt1
Database-backed Application pt2
Database-backed Application pt3
Active URIs
License
Change History
NetKernel History
Acknowledgements

Database-backed Application

Part 3 - Database interaction to complete the application

Summary

In part 2 we built an XRL template and showed how active content can be included. We also created an XForm to enter new data. We now need to complete the XForm data submission and finish the browser.

XForm submission

Previously we said that once an XForm's constraints are satisfied a the submission target, in this app xform_process.idoc will be called with the instance data supplied as parameter. Here is an idoc to create a database entry from the instance data...

<idoc>
  <seq>
    <instr>
      <type>stm</type>
      <operand>
        <sql />
      </operand>
      <operator>
        <stm:group xmlns:stm="http://1060.org/stm">
          <stm:set xpath="/sql"> INSERT INTO entries VALUES ( null, '
            <stm:param xpath="/nvp/firstname/text()" />', '
            <stm:param xpath="/nvp/lastname/text()" />', '
            <stm:param xpath="/nvp/add1/text()" />', '
            <stm:param xpath="/nvp/add2/text()" />', '
            <stm:param xpath="/nvp/add3/text()" />', '
            <stm:param xpath="/nvp/add4/text()" />', '
            <stm:param xpath="/nvp/region/text()" />', '
            <stm:param xpath="/nvp/country/text()" />', '
            <stm:param xpath="/nvp/zip/text()" />', '
            <stm:param xpath="/nvp/phone1/text()" />', '
            <stm:param xpath="/nvp/phone2/text()" />', '
            <stm:param xpath="/nvp/phone3/text()" />', '
            <stm:param xpath="/nvp/fax/text()" />', '
            <stm:param xpath="/nvp/email1/text()" />', '
            <stm:param xpath="/nvp/email2/text()" />', '
            <stm:param xpath="/nvp/email3/text()" />', '
            <stm:param xpath="/nvp/web1/text()" />', '
            <stm:param xpath="/nvp/web2/text()" />', '
            <stm:param xpath="/nvp/notes/text()" />' );
          </stm:set>
        </stm:group>
      </operator>
      <param>this:param</param>
      <target>var:sql</target>
    </instr>
    <instr>
      <type>sqlUpdate</type>
      <operand>var:sql</operand>
      <target>this:response</target>
    </instr>
    <instr>
      <type>buildSessionResourceURI</type>
      <operand>this:param:session</operand>
      <operator>
        <key>xform</key>
      </operator>
      <target>var:xformSession</target>
    </instr>
    <instr>
      <type>delete</type>
      <operand>curi:var:xformSession</operand>
    </instr>
    <instr>
      <type>HTTPredirect</type>
      <operand>
        <uri>/addressbook/</uri>
      </operand>
      <target>this:response</target>
    </instr>
  </seq>
</idoc>

This process dynamically builds an SQL INSERT statement from the submitted parameter. It uses the sqlUpdate accessor to execute the SQL statement on the RDBMS. The new entry is then in the DB. Finally it deletes the XForm from the session - it is not important here how this is done other than to say all session resources are referenced by URI and that the key for an XForm session object is 'xform'. The result is the XForm is finished with and the entry is in the database. Finally we do an HTTPredirect back to the main page.

Main Browser

We've got a means of entering data we now need to enable the record browser. First we need to make the "main" link active and create a source of content. Edit the main link as shown below and add the new "browser" link which executes browser.idoc.

<links> ...
  <link>
    <name>main</name>
    <ext>/</ext>
    <int>active:xrl-html+operator@ffcpl:/links.xml+template@ffcpl:/resources/mastertemplate.xml+content@xrl:browser</int>
    <args>links,param,session</args>
  </link>
  <link>
    <name>browser</name>
    <int>active:dpml+operand@ffcpl:/resources/browser.idoc</int>
    <args>links,param,session</args>
  </link>
</links>

The changes to the links now mean that the main page will pull in the content supplied from the browser.idoc. Here is the browser.idoc, copy this to resources/

<idoc>
  <seq>
    <instr>
      <type>stm</type>
      <operand>
        <sql />
      </operand>
      <operator>
        <stm:group xmlns:stm="http://1060.org/stm">
          <stm:set xpath="/sql"> SELECT * FROM entries WHERE lastname LIKE '
            <stm:param xpath="/nvp/letter/text()" />%' OR lastname LIKE '
            <stm:param xpath="translate(/nvp/letter/text(), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />%' ORDER BY lastname;
          </stm:set>
        </stm:group>
      </operator>
      <param>this:param</param>
      <target>var:sql</target>
    </instr>
    <instr>
      <type>sqlQuery</type>
      <operand>var:sql</operand>
      <target>this:response</target>
    </instr>
    <instr>
      <type>xslt</type>
      <operand>this:response</operand>
      <operator>style_address.xsl</operator>
      <param>this:param</param>
      <target>this:response</target>
    </instr>
    <exception>
      <instr>
        <type>copy</type>
        <operand>
          <div />
        </operand>
        <target>this:response</target>
      </instr>
    </exception>
  </seq>
</idoc>

This process dynamically generates an SQL query statement using the /nvp/letter/text() supplied as the parameter to this idoc.

But what is the parameter? Remember that we said the REST interface to the main page is /addressbook/?letter=x and because we provided <args>param,sesssion</args> with the browser link the URL query parameter is passed through by the mapper from the external request. If the param is stated in the args the XRL mapper will pass it down to all recusively included links.

So we have a dynamically created SQL query - it matches surnames begining with a given letter (we use an XPath trick to support upper case as well as lower case). Next the SQL query is made on the DB using the sqlQuery accessor. Finally the results of the query are styled with a stylesheet (provided below, copy this as 'style_address.xsl' to resources/).

That's it you can now click on a letter and view all the matching entries. We'll leave it as an exercise to add the search facillity, there are many other ways this app can be improved, like supporting editing and deletion of entries etc. If you want to cheat you can download and install the complete application using the install wizard - this includes the search and has a glamorous CSS stylesheet too!

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" />
  <xsl:param name="param" />
  <xsl:template match="/">
    <div>
      <xsl:choose>
        <xsl:when test="$param/nvp/letter">
          <div style="font-size: 30px;">
            <xsl:value-of select="translate($param/nvp/letter, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
          </div>
        </xsl:when>
        <xsl:otherwise>
          <div style="font-size: 30px;">
            <xsl:value-of select="$param/nvp/search" />
          </div>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:apply-templates />
    </div>
  </xsl:template>
  <xsl:template match="null">
    <div style="font-size: 15px; margin-left: 5px; margin-top: 5px;">No Entries</div>
  </xsl:template>
  <xsl:template match="results">
    <xsl:apply-templates />
  </xsl:template>
  <xsl:template match="row">
    <table cellpadding="0" cellspacing="0" style="margin-top: 15px; margin-bottom: 15px;">
      <tr>
        <td>
          <table cellpadding="0" cellspacing="0" style="padding: 5px; margin-bottom:5px;">
            <tr>
              <td colspan="10">
                <table cellpadding="0" cellspacing="0" style="padding-right: 5px">
                  <tr>
                    <td style="padding-right: 5px;">
                      <xsl:value-of select="lastname" />
                    </td>
                    <td>
                      <xsl:value-of select="firstname" />
                    </td>
                  </tr>
                </table>
              </td>
            </tr>
            <tr>
              <td valign="top" width="200">
                <table cellpadding="0" cellspacing="0" style="padding-right: 5px">
                  <tr>
                    <td>
                      <xsl:value-of select="add1" />
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <xsl:value-of select="add2" />
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <xsl:value-of select="add3" />
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <xsl:value-of select="add4" />
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <xsl:value-of select="region" />
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <xsl:value-of select="country" />
                    </td>
                  </tr>
                </table>
              </td>
              <td valign="top" width="200">
                <table cellpadding="0" cellspacing="0" style="padding-right: 5px">
                  <tr>
                    <td>
                      <xsl:value-of select="phone1" />
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <xsl:value-of select="phone2" />
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <xsl:value-of select="phone3" />
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <xsl:value-of select="fax" />
                    </td>
                  </tr>
                </table>
              </td>
            </tr>
            <tr>
              <td valign="top">
                <table cellpadding="0" cellspacing="0" style="padding-right: 5px">
                  <tr>
                    <td>
                      <xsl:value-of select="email1" />
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <xsl:value-of select="email2" />
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <xsl:value-of select="email3" />
                    </td>
                  </tr>
                </table>
              </td>
              <td valign="top">
                <table cellpadding="0" cellspacing="0" style="padding-right: 5px">
                  <tr>
                    <td>
                      <xsl:value-of select="web1" />
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <xsl:value-of select="web2" />
                    </td>
                  </tr>
                </table>
              </td>
            </tr>
            <tr>
              <td colspan="10" style="font-style: italic;">
                <xsl:value-of select="notes" />
              </td>
            </tr>
          </table>
        </td>
      </tr>
    </table>
  </xsl:template>
</xsl:stylesheet>

1060® NetKernelTM Documentation
(C) 2003-2004 1060 Research Limited

Send Feedback

© 2003,2004, 1060® Research Limited
1060 registered trademark, NetKernel trademark of 1060 Research Limited