You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Ovidiu Predescu <ov...@apache.org> on 2002/04/30 07:46:26 UTC

Flow and XMLForm

Hi Ivelin,

On Mon, 29 Apr 2002 08:22:55 -0500, "Ivelin Ivanov" <iv...@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?

Ovidiu

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


Re: Flow and XMLForm

Posted by Ivelin Ivanov <iv...@apache.org>.
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" <da...@swipnet.se>
To: <co...@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"
> > <iv...@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


RE: Flow and XMLForm

Posted by Daniel Fagerstrom <da...@swipnet.se>.
ovidiu@apache.org wrote:
> Hi Ivelin,
>
> On Mon, 29 Apr 2002 08:22:55 -0500, "Ivelin Ivanov"
> <iv...@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.


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: cocoon-dev-unsubscribe@xml.apache.org
For additional commands, email: cocoon-dev-help@xml.apache.org