Generating XML from a form to send to the server

Its easy to load some XML data and either create a form using XSLT, or data-bind the form to an XML source document. But what about sending the completed form data back to the server?
You don't always have control over the format the server needs. It could be that an existing service requires an XML document of a certain format to be HTTP POSTed.

This tutorial shows how to generate the XML and includes a new widget to make it simple.

Using the l:payload widget

The payload widget belongs in the Backbase Labs namespace: www.backbase.com/2007/labs with prefix lowercase L.
Inside the widget, you place the 'template' that generates your desired XML.

<?xml version="1.0" encoding="UTF-8"?>
<div
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:b="http://www.backbase.com/2006/btl"
        xmlns:c="http://www.backbase.com/2006/command"
        xmlns:d="http://www.backbase.com/2006/tdl"
        xmlns:e="http://www.backbase.com/2006/xel"
        xmlns:xi="http://www.w3.org/2001/XInclude"
        xmlns:l="http://www.backbase.com/2007/labs"
        xmlns:smil="http://www.w3.org/2005/SMIL21/BasicAnimation">

       
<xi:include href="payload.xml" />

<l:payload name="serviceForm">
        <Payload xmlns="www.example.com/eg">
                <Complaint>
                        <c:attribute name="submitted"
                                select="string(.//b:calendar[@name='submitted']/@value)" />

                        <c:attribute name="priority" select="string(.//b:spinner[@name='importance']/@value)" />
                        <c:attribute name="subject" select="string(.//input[@name='subject']/@value)" />
                        <c:value-of select="string(.//textarea[@name='description']/property::value)" />
                </Complaint>
                <User>
                        <c:attribute name="FirstName" select="string(.//input[@name='firstName']/@value)" />
                        <c:attribute name="Surname" select="string(.//input[@name='lastName']/@value)" />
                        <c:attribute name="Agreed" select="string(.//input[@name='agreed']/@checked)" />
                </User>
        </Payload>
 </l:payload>
       
<b:button>
        Send to server
        <e:handler event="click">
                <e:with select="preceding-sibling::l:payload">
                        <e:call method="generate" context="id('ServiceForm')"/>
                        <c:load url="/saveData" method="POST" select="property::payload" />
                </e:with>
        </e:handler>
</b:button>
</div>

This first loads the widget definition. the l:payload widget has an optional name to identify it.
It's contents is the same as the contents for c:create. You may use the c:attribute and c:value-of elements, and they are evaluated in the given context.

The button calls the payload widget's generate method using the ServiceForm as the context (where the variable data comes from). The payload generates the XML, serializes it, and stores the resulting string in its payload property.

Payload in action

You can run the example using the attached code and you will see the pre-populated form:
image

Start the debugger before you press the Send to server button - this ensures that your request is captured and displayed by the debugger. Naturally a 404 error was returned because I did not have a service running to catch the request. But you can see the generated XML in the Request Body section of the report in the Network tab of the debugger.
image

Enjoy!

AttachmentSize
Creating Payload.zip3.65 KB
form.jpg41.5 KB
debugger.jpg187.75 KB

Comments

Another solution

I have created an alternate solution for those times when quick-and-dirty will do that doesn't require a widget. It basically comes down to creating a variable with an XMLDocument and using c:create to generate XML inside the document. Another small trick is escaping to Javascript for the XPath calls so that we can set the context of the XPath to "bb.document", a.k.a. the model space.

<?xml version="1.0" encoding="UTF-8"?>
<div
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:b="http://www.backbase.com/2006/btl"
        xmlns:c="http://www.backbase.com/2006/command"
        xmlns:d="http://www.backbase.com/2006/tdl"
        xmlns:e="http://www.backbase.com/2006/xel"
        xmlns:xi="http://www.w3.org/2001/XInclude"
        xmlns:l="http://www.backbase.com/2007/labs"
        xmlns:smil="http://www.w3.org/2005/SMIL21/BasicAnimation">

       
        <e:variable name="payload">
                <e:data type="text/xml"><root /></e:data>
        </e:variable>
       
        <b:button>
                Send to server
                <e:handler event="click">
                        <c:create destination="$payload/*[1]" mode="replace">
                                <Payload xmlns="www.example.com/eg">
                                        <Complaint>
                                                <c:attribute name="submitted" select="javascript: bb.evaluateSmart('string(.//b:calendar[@name=\'submitted\']/@value)', bb.document)" />
                                                <c:attribute name="priority" select="javascript: bb.evaluateSmart('string(.//b:spinner[@name=\'importance\']/@value)', bb.document)" />
                                                <c:attribute name="subject" select="javascript: bb.evaluateSmart('string(.//input[@name=\'subject\']/@value)', bb.document)" />
                                                <c:value-of select="javascript: bb.evaluateSmart('string(.//textarea[@name=\'description\']/property::value)', bb.document)" />
                                        </Complaint>
                                        <User>
                                                <c:attribute name="FirstName" select="javascript: bb.evaluateSmart('string(.//input[@name=\'firstName\']/@value)', bb.document)" />
                                                <c:attribute name="Surname" select="javascript: bb.evaluateSmart('string(.//input[@name=\'lastName\']/@value)', bb.document)" />
                                                <c:attribute name="Agreed" select="javascript: bb.evaluateSmart('string(.//input[@name=\'agreed\']/@checked)', bb.document)" />
                                        </User>
                                </Payload>
                        </c:create>
                       
                        <c:load url="/saveData" method="POST" select="javascript: bb.xml.serialize(payload)" />
                       
                </e:handler>
        </b:button>
       
</div>

There are a few disadvantages to this method. One is having to escape to Javascript. Another is the requirement of a global variable instead of a locally-scoped one.

Question about example

I'm new to Backbase (and web GUIs in general), but not XML. In your example, I was a little confused about the <e:with select="preceding-sibling::l:payload"> tag.

It seems to me that upon cursory reading of the xml, that the preceding-sibling::l:payload axis would not select anything, because I'm reading it as the preceding-sibling of the <e:with> tag.

Can you explain to me why the preceding-sibling is relative to the <b:button> and not the <e:with>?

XPath

Technically, the preceding-sibling:: is relative to the current element in the model tree.
When you open the Backbase debugger you see the model tree in one tab and the View (HTML DOM) tree in another tab.
Now run this example and look at the page in the Backbase Debugger's Model tab. See how the e:handler tags are not shown in the model? They have become event handlers (shown on the right, underneath attributes, properties, you'll see inline handlers).
In other words, the context node for XPath is preserved within child elements if those child elements are execution tags and not actual model nodes.

Since you are new to Backbase, I'd highly recommend investing 1-2 hours to read the Application Developer's Guide. It provides a really solid foundation to understand how Backbase works, and addresses questions like this.
Good luck!