cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Ivelin Ivanov" <ive...@apache.org>
Subject Re: Flow and XMLForm
Date Tue, 07 May 2002 02:26:05 GMT
Daniel,

I added parts of your email to the current readme.txt which ships with
XMLForm.
Hope you don't mind. Included author reference of course.

see below...

----- Original Message -----
From: "Daniel Fagerstrom" <daniel.fagerstrom@swipnet.se>
To: <cocoon-dev@xml.apache.org>
Sent: Saturday, May 04, 2002 10:39 AM
Subject: RE: Flow and XMLForm


> ovidiu@apache.org wrote:
> > Hi Ivelin,
> >
> > On Mon, 29 Apr 2002 08:22:55 -0500, "Ivelin Ivanov"
> > <ivelin@apache.org> 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.


This is so well stated, that I couldn't help adding it to the README.txt
Check it out and let me know if it's fine with you.

>
>
> 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());
> }

Thanks for the example. It helps me understand the flow concepts further.
Question: Where would you handle business logic?
For exampe if the next step in a wizard depends on what was selected in the
current step,
and some data has to be pulled out from an external resource and made
available to the next wizard
page.

>
> 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 would be curious to learn how validation can be kept flexible as well.
In the next release of XMLForm I will apply a request made by Konstantin
to not do validation on Previous.

> 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.

Some of the real-life apps which my team builds needs to deal with Prev.

> * 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.

Great summary. There is no way I could have responded better to Ovidiu's
message.

I agree that these two frameworks can and should integrate.
I am strugglinng big time with cleanly separating the responsibilites
between the two at this point though.
Will greatly appreciate further suggestions in this direction.


Cheers,

Ivelin


>
> What do you think?
>
> /Daniel Fagerstrom
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: cocoon-dev-unsubscribe@xml.apache.org
> For additional commands, email: cocoon-dev-help@xml.apache.org
>


---------------------------------------------------------------------
To unsubscribe, e-mail: cocoon-dev-unsubscribe@xml.apache.org
For additional commands, email: cocoon-dev-help@xml.apache.org


Mime
View raw message