You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Daniel Fagerstrom <da...@swipnet.se> on 2002/04/15 00:00:54 UTC

[RT] Forms and wizards (was: RE: HEADS UP - cocoon form handling (long!!))

Berin Loritsch wrote:
> Ivelin Ivanov wrote:
<snip/>
> > Would you scetch an example of a non-trivial app which does not use
> > JavaBeans?
<snip/>
> I know I am side-stepping your question, however I have not run into
> a situation where I needed beans at all.  So your assumption that every
> non-trivial application needs beans is not valid.
<snip/>
> What you invariably run into in the Cocoon world if you use beans is
> a double mapping: DB to bean, and bean to schema.  That approach does
> not scale well at all.  Not to meantion there are unnecessary
> conversions that can be the source of problems.  KISS (Keep It
> Simple Stupid).
>
> Keep your memory lean.  Beans don't let that happen--or they force
> you to be too smart for your own good.

I find Ivelins and Torstens work on form handling very promising, but I
share Berins (and some other commenter), concern that they are maybe trying
to find answers to some unnecessarily complicated problems.

I'll discuss form handling an multipage form handling (wizards), and try to
give some proposals on how to _not_ solve some of open questions and issues
discussed in
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=101834333817122&w=2. While
at it, I'll also share some provocative thoughts about continuations and
show some heavy use of the hammer anti pattern ;)

One page forms
--------------

We start with a simple one page form. Say that we want to collect some data
about a user of our system. Typically we want the form to be partially
filled in with some default data or something that the user already have
filled in. So we start with something like:

<map:match pattern="userForm.html">
  <map:generate src="userDefault.xml"/>
  <map:transform src="userForm.xsl"/>
  <map:serialize/>
</map:match>

Here the input data is xml (I guess I don't have to argue about why that is
a good idea ;) ), it might be directly from a file, from a db, from
JavaBeans or whatever you might prefer. "userForm.xsl" is a simple
stylesheet that creates a partially filled in html form from its input, (you
can use Velocity or some other template generator instead if you like). To
make the connection between the xml input data and the form field names
simple we use xpaths as field names as is done in XForms (Ivelin, Torsten
and Konstantin do the same). The form stylesheet will have fields like this:

<input type="text" name="/user/name" value="{/user/name}"/>

As these form stylesheets are rather boring to write, we let our computer do
the work:

<map:match pattern="*Form.xsl">
  <map:generate src="{1}Form.xform"/>
  <map:transform src="xForm2xsl.xsl"/>
  <map:serialize type="xml"/>
</map:match>

We can describe our form in terms of some appropriate subset of the form
control part of XForms or maybe in some home brewed form describing
language. "xForm2xsl.xsl" is a stylesheet that takes an Xform description as
input and creates another stylesheet that in turns takes the default data as
input and creates an html form. Konstantin have submitted something similar:
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=101429833513052&w=2 a while
ago. He stays closer to the XForms standard, which contains the instance as
a part of the xforms document, IMHO the XForms standard mixes concerns by
doing so. Anyway by follow the XForms way of doing things Konstantin don't
have to write xslt generating xslt, but have instead to use some extension
functions (evaluate).

Ok, now we can use our automatically generated form stylesheet:

<map:match pattern="userForm.html">
  <map:generate src="userDefault.xml"/>
  <map:transform src="cocoon:/userForm.xsl?continue=userPost.html"/>
  <map:serialize/>
</map:match>

We also use a "poor mans continuation" trick, by sending the url that the
form is supposed to post to, as a request parameter to the form stylesheet
generator. This makes the page flow explicit in the sitemap as it should be.

Time to take care of the data posted from the form:

Input handling
--------------

Even if we would prefer xml data in the post, it will probably take some
time before that is the usual case. By using xpaths as field names we have
at least an implicit description of an xml document. So what we need to do
is the following:
* Create an xml document from the request parameters
* Validate the input data
  Invalid -> Resend the partially filled in form with error messages
* Store or use the data
* Send a success page or the next form

This can look like:

<map:match pattern="userPost.html">
  <map:generate type="xrequest"/>
  <map:transform type="schematron" src="user.sch"/>
  <map:match type="pipe-state" test="fail">
    <map:transform src="cocoon:/userForm.xsl?continue=userPost.html"/>
    <map:serialize/>
  </map:match>
  <map:transform type="write" method="overwrite" src="dbxml:/user"/>
  <map:transform type="read" src="success.html"/>
  <map:serialize/>
</map:match>

* The "xrequest" generator builds an input xml document from the (xpath)
request-parameters.
* The "schematron" transformer validates the input data, set some
"pipe-state" request attribute to "success" or "fail" and give some kind of
report about the errors.
* The "pipe-state" matcher is pipe state aware (cf. the recent discussions
about pipe aware selectors), i.e. it depends on the state of the
"pipe-state" request parameter as it is _after_ the execution of the
validator.
* If the validation failed the input is piped to the form stylesheet and
sent back to the user. The form stylesheet also have rules for rendering the
error report.
* If the validation succeeds the data is sent to a store of some kind.
* A success report is generated.

<design-issues>
In the above example collection of the data and storing of the data
(population of the instance) are separated while I&T combine them. There are
so many possible storages for instance data e.g.: beans and dom in session
and request attributes, files, relational db:s, xml db:s, business objects
and so on, that it seem overwhelming to create a common "instance" interface
for them all, better just put the data in the pipe and let the storage of
it, be someone others concern.

I&T also discuss the indirect vs. direct population problem and proposes to
use direct population of instances (cf. the link above for details). The
example above uses the indirect approach, but could easily be made direct by
giving a template instance as a "src" parameter. We have used designs like
the one above for nearly a year in the company I work for and have never had
any problems with indirect population, IMHO this is a concern for the
storage model.

I think the result of our recent "pipe-awareness" discussion is that the
success or failure of a validation transformer should be put in some "meta"
parameter, probably in a request attribute. We still need to find a good way
to report the details of the errors. One possibilities is: having a separate
result document with pairs of xpaths and error messages, (that explains what
was wrong at that position). Another: annotating the document with error
attributes at the faulty elements, e.g.

<foo>
  ...
   <bar err:error="not a number">qwerty</bar>
</foo>

The first variant is more general and elegant, and the second is much more
easy to use as input for a stylesheet. I prefer the second one :)

The "write" transformer is mainly a thought experiment, it is like tee in
unix. It does the same thing as the WritableSourceTransformer but the source
name is in the sitemap instead than in the input document. I placed the
"method" attribute in it to indicate that if we want to make things like xml
db:s writable sources, we have to find a way to describe what kind of update
method we want to use.

The "read" transformer doesn't care about its input and just puts the
content of its src attribute in the pipeline.

In many cases, there is no already written source or writable source for our
storage and we have to work a little bit harder, e.g. by writing own
mappings between e.g. xml and relational db:s or xml and java beans. There
are some tools that can create at least part of the mapping from some
scheme, e.g. Castor and XML-DBMS http://www.rpbourret.com/xmldbms/.
</design-issues>

Wizards
-------

Here we define multi page forms (or wizards) as building one xml document
from several form pages.

I&T suggests that the structure of the instance and the views should be as
decoupled as possible:

>       [------------instance-----------]
>HTML: [-----view1-----][-----view2----]
>WML:  [--view1--][--view2--][--view3--]

and also that validation could be done at still other substructures that not
necessarily are connected to the views (cf their paragraph about views and
phases).

IMO one can simplify the problem considerably by deciding that the view
always are non-overlapping sub trees of the instance, and that we have one
scheme for each view. I know that this is not a completely generic solution,
but after all we probably did some modeling when we designed our instance.
The sub trees probably describes conceptually different areas, so hopefully
we can reuse this thinking by couple the views to these different areas. If
on the other hand the instance is based on a lousy model, why don't build a
new one for our wizard, then we can always use xslt to transform our view
model to the instance model.

Time for some code:

<map:resource name="form">
  <map:transform src="cocoon:/{query}Form.xsl?continue={query}Post.html"/>
  <map:serialize/>
</map:resource>

<map:resource name="filled-form">
  <map:transform type="read" src="session:/{wizard}/{query}"/>
  <map:call name="form">
    <map:parameter name="query" value="{query}"/>
  </map:call>
</map:resource>

<map:resource name="store">
  <map:generate type="xrequest"/>
  <map:transform type="schematron" src="{query}.sch"/>
  <map:match type="pipe-state" test="fail">
    <map:call name="form">
      <map:parameter name="query" value="{query}"/>
    </map:call>
  </map:match>
  <map:transform type="write" src="session:/{wizard}/{query}"/>
</map:match>

Here I mainly restate our earlier code in terms of parameterized resources,
so that I don't have to repeat myself all the time. The "wizard" parameter
is for the root element of the xml document, and query is for the sub
documents and views. We store everything in a xml document in a session
attribute while filling in the queries in the wizard session.

As an example we do a simple survey for cocoon users:

<map:match pattern="cocoonSurvey/**">
  <map:parameter name="wizard" value="cocoonSurvey"/>

  <map:match pattern="**/start.html">
    <map:act type="write">
      <map:parameter name="from" src="dbxml:/cocoonSurvey[@id='default']"/>
      <map:parameter name="to" src="session:/cocoonSurvey"/>
    </map:act>
    <map:call name="filled-form">
      <map:parameter name="query" value="personal"/>
    </map:call>
  </map:match>

  <map:match pattern="**/personalPost.html">
    <map:call name="store">
      <map:parameter name="query" value="personal"/>
    </map:call>
    <map:call name="filled-form">
      <map:parameter name="query" value="system"/>
    </map:call>
  </map:match>

  <map:match pattern="**/systemPost.html">
    <map:call name="store">
      <map:parameter name="query" value="system"/>
    </map:call>
    <map:select type="xpath">
      <map:when test="/system/platform[.='linux']">
        <map:call name="filled-form">
          <map:parameter name="query" value="linuxDetails"/>
        </map:call>
      </map:when>
      <map:when test="/system/platform[.='windows']">
        <map:call name="filled-form">
          <map:parameter name="query" value="windowsDetails"/>
        </map:call>
      </map:when>
      <!-- ... -->
    </map:select>
  </map:match>

  <map:match pattern="**/linuxDetailsPost.html">
  <!-- ... -->
  </map:match>

  <map:match pattern="**/windowsDetailsPost.html">
  <!-- ... -->
  </map:match>

  <map:match pattern="**/lastPost.html">
    <map:call name="store">
      <map:parameter name="query" value="last"/>
    </map:call>
    <map:act type="write">
      <map:parameter name="from" src="session:/cocoonSurvey"/>
      <map:parameter name="to" src="dbxml:/cocoonSurvey[@id='1234']"/>
    </map:act>
    <map:transform type="read" src="success.html"/>
    <map:serialize/>
  </map:match>
</map:match>

In this example we fill the xml structure that we put in the session, with
default data from a db in the beginning, and store the result in a db in the
end. We use a pipe-aware selector to choose between several paths in the
wizard, depending on the last answer, (we could achieve even larger
flexibility by making choices based on xpath expressions applied on the
session data). Note that the flow control is based on the same continuation
trick as we used in the "one page form" example. The value of the "continue"
parameter is used for the submit button. Also note that we can use the back
and forward button of our browser as much as we want. As soon as you push
the submit button and your data is valid, the data for that page is stored,
and as soon you push the refresh button on a form page, its current content
will be filled in.

A problem is that if one first say that one is a linux user and submit the
linux data, and the go back and say that one is a windows user, and fill in
the windows data, booth the windows and the linux data continue to be
stored. To handle this problem further mechanisms are needed.

<design-issues>
>From a component point of view there is not much new in the wizard compared
to the one page form. We use a writeable session source that is mainly a
non-existing repackaging of functionality already in the
SunShineTransformer, we could have used that instead, and the same applies
to the "write" action. We also use a pipe-content-aware selector besides the
pipe-state-aware selector.

As a consequence of that we always store a page before showing a new the
pages will get misleading names, booth the linuxDetails and the
widowsDetails form page will have the url: systemPost.html. This can be
handled by having obscure names like large numbers so that no one notices,
or by using redirect, which is considered bad. Are there other alternatives
in the http protocol? Something like an internal redirect?
</design-issues>

Continuations
-------------

Why do I keep using the term "continuation" for the trick of sending the
address of the next page as an argument to the current generated page? Isn't
a continuation an object that contains the whole current state of the
program? Actually booth descriptions are true, it all depends on what's in
your program language.

The sitemap together with the continue parameter is a program language
although a quite small one. It contains selection: select and match, and it
contains global variables: session and request attributes, writable
resources and so on, and by using the continuation parameter we introduces a
goto construction. Thus: a small programming language. In such a small
language a continuation is just a program pointer - in the sitemap case: an
url. The control structures in structured programming: sequence, selection
and repetitions can be translated to goto selection (and the other way
around). So it would be rather easy to translate the structured programming
concepts mentioned to a sitemap as the one above.

If we extend our language with (possibly recursive) functions, we need to
take care of a call stack of program pointers also. This stack of uri:s
could be stored in a continuation object or in a hidden form field. If we
introduce local variables in our language we need to put these in the
continuation object as well. Local variables introduces the possibility for
"what if" scenarios, i.e. that you can have several independent instances of
the same form page. For some kind of webapps: e.g. shopping carts and
checkout sequences, this kind of behavior is IMHO harmful, (cf discussion
between Ovidiu and me:
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=101856443021128&w=2,
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=101858926504890&w=2,
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=101861458122598&w=2,
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=101870096719351&w=2). I
would propose that in a large class of webapps you don't need more than the
continue parameter described above. Another aspect is of course that the
sitemap with continuation parameter sucks as a web application programming
language. So you would anyway need a better language for describing
complicated flow, but I still wonder if something as powerful as
continuations with local variables is needed.

Using the hammer anti-pattern
-----------------------------

After all the recent discussion about what you not are supposed to do in the
sitemap I can not help to feel like provoking a little ;)

Principle: "Everything can and should be done in the sitemap" ;)

As we saw in the examples above we have always to combine the handling of
the input of one form with the construction of the next form. This is
because we need to have a match statement that surrounds the two. It would
be more natural to combine the form generation with its input handler:

<map:resource name="form-handling">
  <map:call name="filled-form">
    <map:parameter name="query" value="{query}"/>
  </map:call>
  <fm:label name="{query}Post.html"/>
  <map:call name="store">
    <map:parameter name="query" value="{query}"/>
  </map:call>
</map:resource>

Here some kind of environment is supposed to detect that a serialize is
followed of a generate, and make a continuation available. "fm:label" is a
way to give a name to the continuation if one don't want an automatic one.

Here is our example again:

<map:match pattern="cocoonSurvey/**">
  <map:parameter name="wizard" value="cocoonSurvey"/>

  <fm:sequence uri-prefix="cocoonSurvey">

    <fm:label name="start.html"/>
    <map:act type="write">
      <map:parameter name="from" src="dbxml:/cocoonSurvey[@id='default']"/>
      <map:parameter name="to" src="session:/cocoonSurvey"/>
    </map:act>

    <map:call name="form-handling">
      <map:parameter name="query" value="personal"/>
    </map:call>

    <map:call name="form-handling">
      <map:parameter name="query" value="system"/>
    </map:call>

    <fm:select type="xpath">
      <fm:when test="/system/platform[.='linux']">
        <map:call name="form-handling">
          <map:parameter name="query" value="linuxDetails"/>
        </map:call>
      </fm:when>
      <fm:when test="/system/platform[.='windows']">
        <map:call name="filled-form">
          <map:parameter name="query" value="windowsDetails"/>
        </map:call>
      </fm:when>
      <!-- ... -->
    </fm:select>

    <!-- ... -->

    <map:act type="write">
      <map:parameter name="from" src="session:/cocoonSurvey"/>
      <map:parameter name="to" src="dbxml:/cocoonSurvey[@id='1234']"/>
    </map:act>

    <map:transform type="read" src="success.html"/>
    <map:serialize/>

  </fm:sequence>
</map:match>

The new construction "fm:sequence" handles the url as "map:mount" it also
automates continuation handling by analyzing its content pipeline components
and making an url to each generator be available in a continuation parameter
for the components earlier in the pipe up to the next generator.

Implementation
--------------

If we exclude the last section what do we need to implement if we would like
to have what I describe above? Not much actually, we need the "xrequest"
generator, a validation transformer and pipe aware selectors. It could be
nice to have an "xForm2xsl.xsl" stylesheet also, but it is not necessary,
one can write form stylesheets manually also. The read and write
transformers and the new writable sources are not necessary at all there are
already transformers that do the same work. But maybe not as smooth in the
proposed framework.

Torsten have already implemented most of the functionality of an "xrequest"
generator but as an action, it would be fairly easy to repackage it as a
generator, I have an implementation that I can donate "as is", although it
would need some more polishing.  Torsten and Ivelin have also implemented
some different variants of validation transformers. And I contributed a
prototype implementation of pipe-aware selection some while ago. Booth would
need some small adjustments to work together as described above.

The great unsolved problems
---------------------------

There are probably tons of unsolved problems, but two particularly tricky
are:
* Order restrictions: E.g. A user cannot go back after having committed a
certain page.
* There might be several paths from the first to the last page in the
wizard, only the data submitted in pages along the path that was chosed in
the end should be stored in the end. An instance of this problem was
described in the end of the "wizard" section.

I have no solution to these problems, but I think that they become easier to
solve if there is a simple and explicit connection, between forms and
submitted data.


That's more than enough ;)

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


RE: [RT] Forms and wizards (was: RE: HEADS UP - cocoon form handling (long!!))

Posted by Torsten Curdt <tc...@dff.st>.
<snip/>

> > Sorry, I tent not to agree here... the problems are there... Of couse if
> > depends on what you are heading. Your proposal here is exactly what we at
> > dff *don't* want... we want a clean and simple interface to the form
> > handling and validation facitlities that should be (later) really a part
> > of cocoon. What you are proposing here is to build cocoon form handling
> > and validation *with* cocoon and not *for* it. Let me state explicitly:
> >
> > There should be not necessarily more than a single pipeline and not more
> > than one transformer involved (except the last stylesheet for the
> > serializer)
> Ok, we seem to have fairly different goals, I often use several transformers
> and pipelines and find that much more productive than having to write
> actions in Java.

I don't want to write java for simple forms either... I want to model my
forms completely by creating

 a) a XML validity description (XSD... whatever)
 b) some XML views

and for simple forms - that's it... and this information is handed to the
controller (an action) to do whatever he needs... all I say is: this
should not be part of the sitemap!

> > > * The "xrequest" generator builds an input xml document from the (xpath)
> > > request-parameters.
> >
> > Are you saying you want to build a view from the request??
> I'm not just saying that I want to do it, my colleagues and I are building
> all our webapps that way, since quite a while, and find it much more
> productive than the more traditional ways of form handling.

Sorry, but this would definitly would not work for us here... Where do you
get your <titles/> etc from? Do you have it in your XSLs?

> If you want to do prepopulation it could easily be achieved by giving the
> generator an xml-document as input, through the src-argument.
>
> > what about the checkboxes here?
> That was a surprising part of your "HEADS UP" post, I have used plenty of
> checkboxes and never experienced the "check box problem". I asked a
> colleague about it, and he couldn't recall having any check box problems.
> Maybe I have misunderstood something or maybe we use checkboxes in different
> ways.

...again: a checkbox will not provide an request parameter value when it's
not checked - so you don't know about whether there is a checkbox or not..
Please try it...

> I think you are going to run into problems in the long run anyway if you
> choose to use indirect population: Check the repeat construction in XForms
> http://www.w3.org/TR/2002/WD-xforms-20020118/slice9.html#ui-repeat if you
> use that together with checkboxes it will be problematic to prepopulate the
> document.

you might want to look into exFormular... it's already solved there...

> I'll take another example: we have developed a interview
> management system that among many other things are used for very large scale
> medical research, the questionnaire contains a number of thousand questions,
> which questions that are asked are dependent on earlier answers and
> typically just a few percent of all the questions are asked under a
> particular interview session. Would it be a good idea to prepopulate the
> instance in this case? Ok, this example is of course very large scale, but I
> think it illustrates that in many cases it is unrealistic to explicitly
> enumerate everything that is _not_ said.

are you talking about the building of the instance?

> > And you have no impact on the document...
> That is part of the point, I want to validate the input and possibly
> transform it into another format before putting it in the document.
>
> > currently the
> > views in our examples have only those "mapping" in there but that's not
> > for always!
> Didn't get that.

ok... you lost me I lost in the above... ;)


<root>
  <title>The Form</title>
  <info>
    Please enter all bla here
  </info>

  <f:group>
    <f:input ref="form/bla">
      <f:caption>Please enter bla</f:caption>
    </f:input>
  </f:group>
</root>

....so where does the text an the caption come from when you create this
from a request??

> > > * The "schematron" transformer validates the input data, set some
> > > "pipe-state" request attribute to "success" or "fail" and give
> > some kind of
> > > report about the errors.
> >
> > Let me make this clear: I don't like a transformer to validate my forms
> > because this should happen inside the Controler which IMHO is supposed to
> > be an action... I'd like to be able to easily write an action that
> > can validate my form and then act on the result...
> Let me make this clear: I don't want to have to write actions, for handling
> ordinary form input ;)

that's not an argument to put this stuff in the sitemap! SoC!! I would
like to configure the controller and don't want it in the sitemap!

> > > In the above example collection of the data and storing of the data
> > > (population of the instance) are separated while I&T combine
> > them. There are
> > > so many possible storages for instance data e.g.: beans and dom
> > in session
> > > and request attributes, files, relational db:s, xml db:s,
> > business objects
> > > and so on, that it seem overwhelming to create a common
> > "instance" interface
> > > for them all, better just put the data in the pipe and let the
> > storage of
> > > it, be someone others concern.
> >
> > I don't aggree here... in real world cases (guess 90%) the following 3
> > stores should be fine...
> >
> >  * DOMInstance
> >  * BeanInstance
> >  * EJBInstance
> >
> There seem to be several real worlds ;) I would have said, that in 90% of
> the "real world cases", one have a one page form where the content is put
> directly in an SQL DB.

well, I can't remeber when I had to write a one-page form last time... but
I aggree: also 90% of our "real world cases" are mapped to a SQL DB... but
IMHO that's not the point... you present the form (maybe in multiple
pages) the form data gets collected in an instance and on the end the form
is saved into the DB. Please understand that the instances are usually
only pre-buffers before stuff gets into the backend. If you deal only with
one-page forms you don't really need that... but even then there are a
couple of reasons for that. And we needs this if we want to come up with a
general form handling that also supports muli-page forms...

> > The instance is (normaly) only used for pre-buffering before submission.

see...

<snip/>

> > That's way too uncomfortable... What if you move one textbox from one view
> > over into another one?
> I prefer to have a framework that makes it really easy to write the 90% most
> common cases, and make the more complicated cases doable, than having one
> that makes simple things complicated ...

same here...

> > I know some people don't share my vision yet but I see it this way:
> >
> > * one guy writes a e.g. XSD with XMLspy defining the structure of the
> > business object (the form) ...he has no clue about java or XSLT.
> >
> > * someone else get's this XSD an defines the views onto this documents. He
> > "only" needs to understand the XSD and needs to know a bit how to
> > use cocoon.
> >
> > * another one builds the XSLT. All he gets is XML as usual...
> I share your vision, and IMO we will reach it first when more people are
> starting to realize that data should be described in terms of XML and that
> the natural place for XML is in the pipeline ;) not in any actions. Even if

you mean the sitemap... not everything should go into the sitemap...
please guys - SoC.

> I share your vision I wouldn't like to force people using XSD, I don't think
> it is worthwhile in simple cases. In many simple cases it is a better idea
> to try to design your forms so that you don't have to validate anything or
> maybe just a few fields, and in that case Schematron might be a simpler
> solution than XSD.

Did you ever read what I wrote? I want to support XSD, RelaxNG, Schematron
and whatever people like to implement...

*sigh*
--
Torsten


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


RE: [RT] Forms and wizards (was: RE: HEADS UP - cocoon form handling (long!!))

Posted by Daniel Fagerstrom <da...@swipnet.se>.
Torsten Curdt wrote:
> On Mon, 15 Apr 2002, Daniel Fagerstrom wrote:
<snip/>
> > I find Ivelins and Torstens work on form handling very promising, but I
> > share Berins (and some other commenter), concern that they are
> maybe trying
> > to find answers to some unnecessarily complicated problems.
>
> Sorry, I tent not to agree here... the problems are there... Of couse if
> depends on what you are heading. Your proposal here is exactly what we at
> dff *don't* want... we want a clean and simple interface to the form
> handling and validation facitlities that should be (later) really a part
> of cocoon. What you are proposing here is to build cocoon form handling
> and validation *with* cocoon and not *for* it. Let me state explicitly:
>
> There should be not necessarily more than a single pipeline and not more
> than one transformer involved (except the last stylesheet for the
> serializer)
Ok, we seem to have fairly different goals, I often use several transformers
and pipelines and find that much more productive than having to write
actions in Java.

<snip/>
> > * The "xrequest" generator builds an input xml document from the (xpath)
> > request-parameters.
>
> Are you saying you want to build a view from the request??
I'm not just saying that I want to do it, my colleagues and I are building
all our webapps that way, since quite a while, and find it much more
productive than the more traditional ways of form handling.

If you want to do prepopulation it could easily be achieved by giving the
generator an xml-document as input, through the src-argument.

> what about the checkboxes here?
That was a surprising part of your "HEADS UP" post, I have used plenty of
checkboxes and never experienced the "check box problem". I asked a
colleague about it, and he couldn't recall having any check box problems.
Maybe I have misunderstood something or maybe we use checkboxes in different
ways.

I think you are going to run into problems in the long run anyway if you
choose to use indirect population: Check the repeat construction in XForms
http://www.w3.org/TR/2002/WD-xforms-20020118/slice9.html#ui-repeat if you
use that together with checkboxes it will be problematic to prepopulate the
document. I'll take another example: we have developed a interview
management system that among many other things are used for very large scale
medical research, the questionnaire contains a number of thousand questions,
which questions that are asked are dependent on earlier answers and
typically just a few percent of all the questions are asked under a
particular interview session. Would it be a good idea to prepopulate the
instance in this case? Ok, this example is of course very large scale, but I
think it illustrates that in many cases it is unrealistic to explicitly
enumerate everything that is _not_ said.

> And you have no impact on the document...
That is part of the point, I want to validate the input and possibly
transform it into another format before putting it in the document.

> currently the
> views in our examples have only those "mapping" in there but that's not
> for always!
Didn't get that.

> And you are still not save with the checkbox problem if you
> don't use direct population...
See above

> > * The "schematron" transformer validates the input data, set some
> > "pipe-state" request attribute to "success" or "fail" and give
> some kind of
> > report about the errors.
>
> Let me make this clear: I don't like a transformer to validate my forms
> because this should happen inside the Controler which IMHO is supposed to
> be an action... I'd like to be able to easily write an action that
> can validate my form and then act on the result...
Let me make this clear: I don't want to have to write actions, for handling
ordinary form input ;)

<snip/>
> > In the above example collection of the data and storing of the data
> > (population of the instance) are separated while I&T combine
> them. There are
> > so many possible storages for instance data e.g.: beans and dom
> in session
> > and request attributes, files, relational db:s, xml db:s,
> business objects
> > and so on, that it seem overwhelming to create a common
> "instance" interface
> > for them all, better just put the data in the pipe and let the
> storage of
> > it, be someone others concern.
>
> I don't aggree here... in real world cases (guess 90%) the following 3
> stores should be fine...
>
>  * DOMInstance
>  * BeanInstance
>  * EJBInstance
>
There seem to be several real worlds ;) I would have said, that in 90% of
the "real world cases", one have a one page form where the content is put
directly in an SQL DB.

> The instance is (normaly) only used for pre-buffering before submission.
>
>
> > I&T also discuss the indirect vs. direct population problem and
> proposes to
> > use direct population of instances (cf. the link above for details). The
> > example above uses the indirect approach, but could easily be
> made direct by
> > giving a template instance as a "src" parameter.
>
> Did you mix direct vs. indirect above?
Yes, I did.

<snip/>
> > I think the result of our recent "pipe-awareness" discussion is that the
> > success or failure of a validation transformer should be put in
> some "meta"
> > parameter, probably in a request attribute.
>
> ...I still don't like it ;-)
I can understand that, if you prefer to write actions before doing the work
in the pipeline you will not have any use for it.


> > >       [------------instance-----------]
> > >HTML: [-----view1-----][-----view2----]
> > >WML:  [--view1--][--view2--][--view3--]
> >
> > and also that validation could be done at still other
> substructures that not
> > necessarily are connected to the views (cf their paragraph
> about views and
> > phases).
> >
> > IMO one can simplify the problem considerably by deciding that the view
> > always are non-overlapping sub trees of the instance, and that
> we have one
> > scheme for each view. I know that this is not a completely
> generic solution,
>
> That's way too uncomfortable... What if you move one textbox from one view
> over into another one?
I prefer to have a framework that makes it really easy to write the 90% most
common cases, and make the more complicated cases doable, than having one
that makes simple things complicated ...


> I know some people don't share my vision yet but I see it this way:
>
> * one guy writes a e.g. XSD with XMLspy defining the structure of the
> business object (the form) ...he has no clue about java or XSLT.
>
> * someone else get's this XSD an defines the views onto this documents. He
> "only" needs to understand the XSD and needs to know a bit how to
> use cocoon.
>
> * another one builds the XSLT. All he gets is XML as usual...
I share your vision, and IMO we will reach it first when more people are
starting to realize that data should be described in terms of XML and that
the natural place for XML is in the pipeline ;) not in any actions. Even if
I share your vision I wouldn't like to force people using XSD, I don't think
it is worthwhile in simple cases. In many simple cases it is a better idea
to try to design your forms so that you don't have to validate anything or
maybe just a few fields, and in that case Schematron might be a simpler
solution than XSD.

> > but after all we probably did some modeling when we designed
> our instance.
> > The sub trees probably describes conceptually different areas,
> so hopefully
> > we can reuse this thinking by couple the views to these different areas.
>
> unfortunately this will only work if you have enough space to display
> it... have you ever build a wap site?
No, I have succeeded in staying away from it this far ;) I'll wait till the
platforms become a little bit more mature, if I can.

> (or what else is comming soon for
> the mobiles? You are lucky when you can display a whole address in one
> view ;-)
One field is no problem, it is a complete sub tree. What I mean is that if
you want to use views that take nodes from several possibly overlapping sub
trees, it becomes much more complicated to manage e.g. validation and I
wonder if it is worthwhile, remember to stay away from FS ;)

> > If
> > on the other hand the instance is based on a lousy model, why
> don't build a
> > new one for our wizard, then we can always use xslt to
> transform our view
> > model to the instance model.
>
> too much work...
So, the guy who is writing XSD, without knowing Java and XSLT complicates
your life that much ;)

> didn't you aggree on keeping it simple? I like to have as
> little files as possible for having a clean (SoC) sollution.
I want to keep thing simple. We might have different ideas about what is
simple.

<snip/>

> Daniel, I hope you don't resent it but I'm thinking we should stear in a
> different direction if we want to be as elegant as Struts...
I think we should strive for something much more elegant than struts ;)

/Daniel Fagerstrom



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


Re: [RT] Forms and wizards (was: RE: HEADS UP - cocoon form handling (long!!))

Posted by Torsten Curdt <tc...@dff.st>.
On Mon, 15 Apr 2002, Daniel Fagerstrom wrote:

> Berin Loritsch wrote:
> > Ivelin Ivanov wrote:
> <snip/>
> > > Would you scetch an example of a non-trivial app which does not use
> > > JavaBeans?
> <snip/>
> > I know I am side-stepping your question, however I have not run into
> > a situation where I needed beans at all.  So your assumption that every
> > non-trivial application needs beans is not valid.
> <snip/>
> > What you invariably run into in the Cocoon world if you use beans is
> > a double mapping: DB to bean, and bean to schema.  That approach does
> > not scale well at all.  Not to meantion there are unnecessary
> > conversions that can be the source of problems.  KISS (Keep It
> > Simple Stupid).

...exactly that's the idea KIASASAP (Keep It As Simple And Stupid As
Possible ;-)

But not only for the implementation... even more important for the user
point of view!

> > Keep your memory lean.  Beans don't let that happen--or they force
> > you to be too smart for your own good.
>
> I find Ivelins and Torstens work on form handling very promising, but I
> share Berins (and some other commenter), concern that they are maybe trying
> to find answers to some unnecessarily complicated problems.

Sorry, I tent not to agree here... the problems are there... Of couse if
depends on what you are heading. Your proposal here is exactly what we at
dff *don't* want... we want a clean and simple interface to the form
handling and validation facitlities that should be (later) really a part
of cocoon. What you are proposing here is to build cocoon form handling
and validation *with* cocoon and not *for* it. Let me state explicitly:

There should be not necessarily more than a single pipeline and not more
than one transformer involved (except the last stylesheet for the serializer)

<snip/>

> ...He stays closer to the XForms standard, which contains the instance as
> a part of the xforms document, IMHO the XForms standard mixes concerns by
> doing so.

Exactly!


> Input handling
> --------------
>
> Even if we would prefer xml data in the post, it will probably take some
> time before that is the usual case. By using xpaths as field names we have

:) unfortunately


>
> <map:match pattern="userPost.html">
>   <map:generate type="xrequest"/>
>   <map:transform type="schematron" src="user.sch"/>
>   <map:match type="pipe-state" test="fail">
>     <map:transform src="cocoon:/userForm.xsl?continue=userPost.html"/>
>     <map:serialize/>
>   </map:match>
>   <map:transform type="write" method="overwrite" src="dbxml:/user"/>
>   <map:transform type="read" src="success.html"/>
>   <map:serialize/>
> </map:match>
>
> * The "xrequest" generator builds an input xml document from the (xpath)
> request-parameters.

Are you saying you want to build a view from the request?? what about the
checkboxes here? And you have no impact on the document... currently the
views in our examples have only those "mapping" in there but that's not
for always! And you are still not save with the checkbox problem if you
don't use direct population...


> * The "schematron" transformer validates the input data, set some
> "pipe-state" request attribute to "success" or "fail" and give some kind of
> report about the errors.

Let me make this clear: I don't like a transformer to validate my forms
because this should happen inside the Controler which IMHO is supposed to
be an action... I'd like to be able to easily write an action that
can validate my form and then act on the result...

> * The "pipe-state" matcher is pipe state aware (cf. the recent discussions
> about pipe aware selectors), i.e. it depends on the state of the
> "pipe-state" request parameter as it is _after_ the execution of the
> validator.
> * If the validation failed the input is piped to the form stylesheet and
> sent back to the user. The form stylesheet also have rules for rendering the
> error report.
> * If the validation succeeds the data is sent to a store of some kind.
> * A success report is generated.
>
> <design-issues>
> In the above example collection of the data and storing of the data
> (population of the instance) are separated while I&T combine them. There are
> so many possible storages for instance data e.g.: beans and dom in session
> and request attributes, files, relational db:s, xml db:s, business objects
> and so on, that it seem overwhelming to create a common "instance" interface
> for them all, better just put the data in the pipe and let the storage of
> it, be someone others concern.

I don't aggree here... in real world cases (guess 90%) the following 3
stores should be fine...

 * DOMInstance
 * BeanInstance
 * EJBInstance

The instance is (normaly) only used for pre-buffering before submission.


> I&T also discuss the indirect vs. direct population problem and proposes to
> use direct population of instances (cf. the link above for details). The
> example above uses the indirect approach, but could easily be made direct by
> giving a template instance as a "src" parameter.

Did you mix direct vs. indirect above?

> We have used designs like
> the one above for nearly a year in the company I work for and have never had
> any problems with indirect population, IMHO this is a concern for the
> storage model.

SoC! this a problem of the controller...

> I think the result of our recent "pipe-awareness" discussion is that the
> success or failure of a validation transformer should be put in some "meta"
> parameter, probably in a request attribute.

...I still don't like it ;-)


> >       [------------instance-----------]
> >HTML: [-----view1-----][-----view2----]
> >WML:  [--view1--][--view2--][--view3--]
>
> and also that validation could be done at still other substructures that not
> necessarily are connected to the views (cf their paragraph about views and
> phases).
>
> IMO one can simplify the problem considerably by deciding that the view
> always are non-overlapping sub trees of the instance, and that we have one
> scheme for each view. I know that this is not a completely generic solution,

That's way too uncomfortable... What if you move one textbox from one view
over into another one?



I know some people don't share my vision yet but I see it this way:

* one guy writes a e.g. XSD with XMLspy defining the structure of the
business object (the form) ...he has no clue about java or XSLT.

* someone else get's this XSD an defines the views onto this documents. He
"only" needs to understand the XSD and needs to know a bit how to use cocoon.

* another one builds the XSLT. All he gets is XML as usual...

Checking against this XSD will make sure all data that will be stored are
valid in content and structure. (Note: we wouldn't use XSD because it
doesn't satisfy our needs... but there are others and others to come - if
not I will push the easyrelax stuff to become more mature...)

> but after all we probably did some modeling when we designed our instance.
> The sub trees probably describes conceptually different areas, so hopefully
> we can reuse this thinking by couple the views to these different areas.

unfortunately this will only work if you have enough space to display
it... have you ever build a wap site? (or what else is comming soon for
the mobiles? You are lucky when you can display a whole address in one
view ;-)

> If
> on the other hand the instance is based on a lousy model, why don't build a
> new one for our wizard, then we can always use xslt to transform our view
> model to the instance model.

too much work... didn't you aggree on keeping it simple? I like to have as
little files as possible for having a clean (SoC) sollution.

<snip/>

Hm... this could make sense... we could build the initial instance from a
pipeline...


  pipeline -> instance <- controller


Ivelin, what do you think? This could solve the "build from preceptor"
problem...

<snip/>

> After all the recent discussion about what you not are supposed to do in the
> sitemap I can not help to feel like provoking a little ;)
>
> Principle: "Everything can and should be done in the sitemap" ;)

My hackles are raising ;) ...I really hope you are only provoking...


<snip/>

> Here is our example again:
>
> <map:match pattern="cocoonSurvey/**">
>   <map:parameter name="wizard" value="cocoonSurvey"/>
>
>   <fm:sequence uri-prefix="cocoonSurvey">
>
>     <fm:label name="start.html"/>
>     <map:act type="write">
>       <map:parameter name="from" src="dbxml:/cocoonSurvey[@id='default']"/>
>       <map:parameter name="to" src="session:/cocoonSurvey"/>
>     </map:act>
>
>     <map:call name="form-handling">
>       <map:parameter name="query" value="personal"/>
>     </map:call>
>
>     <map:call name="form-handling">
>       <map:parameter name="query" value="system"/>
>     </map:call>
>
>     <fm:select type="xpath">
>       <fm:when test="/system/platform[.='linux']">
>         <map:call name="form-handling">
>           <map:parameter name="query" value="linuxDetails"/>
>         </map:call>
>       </fm:when>
>       <fm:when test="/system/platform[.='windows']">
>         <map:call name="filled-form">
>           <map:parameter name="query" value="windowsDetails"/>
>         </map:call>
>       </fm:when>
>       <!-- ... -->
>     </fm:select>
>
>     <!-- ... -->
>
>     <map:act type="write">
>       <map:parameter name="from" src="session:/cocoonSurvey"/>
>       <map:parameter name="to" src="dbxml:/cocoonSurvey[@id='1234']"/>
>     </map:act>
>
>     <map:transform type="read" src="success.html"/>
>     <map:serialize/>
>
>   </fm:sequence>
> </map:match>


ahhh... seems you are not only provoking ?! =8-||

IMHO this is flow stuff that needs to be separated...

> The great unsolved problems
> ---------------------------
>
> There are probably tons of unsolved problems, but two particularly tricky
> are:
> * Order restrictions: E.g. A user cannot go back after having committed a
> certain page.

no problem... this depends on the controller...


<snip/>

> That's more than enough ;)

Quite some stuff to read ;)

> What do you think?

Daniel, I hope you don't resent it but I'm thinking we should stear in a
different direction if we want to be as elegant as Struts...

cheers
--
Torsten


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