[EMAIL PROTECTED] wrote: > Hi Ivelin, > > On Mon, 29 Apr 2002 08:22:55 -0500, "Ivelin Ivanov" > <[EMAIL PROTECTED]> wrote: > > > one of the action items on your list a couple weeks ago was to > > evaluate the possibility of integration between Schecoon and the > > XMLForm framework. Have you had time to do that yet? > > I looked at the code in scratchpad, but it's unclear to me how this > integration could proceed with the current incarnations of XMLForm and > the flow layer. I still need to spend more time thinking about this. > > Do you have any ideas about it?
I'm not Ivelin, but I have some ideas anyhow ;) Background ---------- The aim of XMLForm, AFAIU, is to build and edit an xml document (called the instance), subject to constraints from some schema (XMLSchema, Schematron, ...), through a sequence of form pages. The instance is either a dom-document or a Java bean-structure or a mix. XMLForm consist, AFAIU, of three main components: * Form - is responsible for the instance and validation of it. Form objects are stored in request attributes for one page forms and session attributes for wizards (multi page forms). A Form can be populated from the request parameters. * XMLFormTransformer - takes a form descriptor, (similar to XForms) as input and fill it with data and error messages from a Form object that is referred in an attribute "view". * AbstractXMLFormAction, (WizardAction) - creates the Form object if necessary and populates it with data based on the request parameters. It can also take care of flow handling and checkbox state. XMLForm - flow layer integration -------------------------------- As we assume that there is anything to integrate, I guess that it is obvious that the flow layer should be responsible for the flow handling. For wizards there are two levels of flow handling: if a form is filled in in a faulty way it should be resend with the faulty content and error messages. There is also page flow where the choice of the next form page might depend on earlier input. The next question is: who should be responsible for handling the Form object? In XMLForm, actions that inherit from AbstractXMLFormAction, e.g. WizardAction is responsible for this. In an XMLForm - flow layer integration, handling of the Form object should IMHO be the responsibility for the flow layer. After all, the aim of a wizard flow script is to (possibly through several form pages) update the state of an instance. If this should be obvious from reading the flow script, the handling of the Form object should be explicit in it. One-page forms -------------- To take care of a one-page form we need to: 1. Create and configure a Form object. 2. Create and send an html form page and prefill it with data from the form object, return address (continuation), and possibly add error messages. 3. Read the input from a POST, populate the Form object with the input and go back to step 2. if the input is invalid. This could be coded as: function getUserInput(form, view) { do { sendPage("wizard/"+ view + ".html", {"id" : form.getId()}); form.populate(cocoon.request()); } while (!form.valid()); } Here, the parameter "form" is a Form object and "view" is a string. I don't follow the interfaces in XMLForm in every detail. Note that thanks to the continuations, we can group together the form page code, followed by the code that takes care of its output and not the other way around: take care of input from last form followed by generating the next form page, as in the sitemap. <map:match pattern="*.html"> <map:generate src="{1}.xml"/> <map:transform type="xmlform"> <map:parameter name="id" value="{id}"/> <map:parameter name="action" value="{continuation}"/> <map:transform/> <map:transform src="stylesheets/wizard2html.xsl"/> <map:transform src="stylesheets/xmlform2html.xsl"/> <map:serialize type="html"/> </map:match> This is like in the example sitemap for XMLForm, with the differences that: We have no XMLFormAction, its responsibilities are moved to the flow layer. The XMLFormTransformer uses the continuation parameter, (from the flow layer) for setting the "action" attribute of the form, and "id" for setting the "id" attribute for referring to the Form object. The later part is not necessary but I think it gives a better SoC if the form descriptors doesn't know what instance they are supposed to update, if they know, you can't reuse e.g. a "fill in user data form" between wizards. Multi page forms ---------------- A wizard could be coded like: function cocoonSurvey() { form = new Form(...); getUserInput(form, "userIdentity"); getUserInput(form, "deployment"); getUserInput(form, "system"); if (form.getValue("/system/os") == "Linux") getUserInput(form, "linuxDetails"); else if (form.getValue("/system/os") == "MacOSX") getUserInput(form, "macOSXDetails"); else if (form.getValue("/system/os") == "Windows") getUserInput(form, "windowsDetails"); getUserInput(form, "confirm"); storeResults(form, db); } Where the form constructor get default values, schema etc as input. I also assume, (as I guess one generally assume while using the flow layer?), that there is a submit button on each form page. If one want to edit earlier form pages in the flow one is supposed to press submit on the current one before using the backward button on the browser if one want to save the content of the current form. In Ivelins example there is a next and a previous button in the form pages. If we want something like that in the flow layer the code gets a little bit less neat: ... userIdentity: getUserInput(form, "userIdentity"); deployment: getUserInput(form, "deployment"); if (cocoon.request.getParameter("action") == "previous") goto userIdentity; system: getUserInput(form, "system"); if (cocoon.request.getParameter("action") == "previous") goto deployment; ... I'm not certain about the goto syntax in JS, but I guess you get the idea. Is there a better way to code it? I think there are at least three ways to attack this problem, (except for writing something as ugly as the above code): * Don't care about it and use a "submit" button instead of "next" and "previous" buttons - I think this is the cleanest solution and I tend to prefer it. On the other hand, after having met all kind of lousy implementations of multi page forms I am a little bit reluctant to use the "backward" button in my browser while filling in forms, I guess most people have similar experience. * Using finite state machines for describing the flow :( * Adding some ingenious mechanism to the flow layer that handle "previous"-buttons automagically. Conclusion ---------- If I didn't miss anything important above, I think that XMLForm and the flow layer can be integrated with a fairly small effort. In the example code above I used some small additions to the Form class, but I don't think any of them are necessary, the only thing that is necessary is to insert the continuation address in the action attribute in the html form. This could be done either in the XMLTransformer, as above or in one of the following XSLTTransformers or maybe even by writing the form descriptors in XSP. What do you think? /Daniel Fagerstrom --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, email: [EMAIL PROTECTED]