cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Konstantin Piroumian <KPiroum...@protek.com>
Subject RE: HEADS UP - cocoon form handling (long!!)
Date Tue, 09 Apr 2002 14:43:58 GMT
> From: Torsten Curdt [mailto:tcurdt@dff.st] 
> 
> HEADS UP - cocoon form handling
> -------------------------------
[...]

Personally I would stay as close to XForms specification as possible (in all
markup parts, including contraints and events), although several parts are
not possible on the server side or would require too much client code
(JavaScript XPath, etc.). 

Reasons are:
	- it is a specification that addresses most of the possible cases
	- there is a hope that some day XForms would replace HTML forms and
in that case it'll be possible to use Cocoon forms as-is without any
additional transformation
	- we need an agreement on terms and processing models and this can
be achieved without reinventing the wheel

>                        INTRODUCTION OF TERMS
> 
>                                -o-
>                            The Instance
> 
> Form handling is always about collecting and validating user 
> input that
> finally gets submitted. Since this collection process is not always
> finished in a single request-cycle (wizards) you need some 
> kind of store
> to save the data until you can finally submit it. This store can be 
> either a DOM or Beans. We call the general store of those data 
> "instance" according to the current XForms working draft.
> 
>                                -o-
>                               Views
> 
> This instance needs to be filled by the submission of one or 
> more pages 
> of the current media. (we will focus on HTML right now) So 
> what the user
> actually sees might only be a "view" or a part of the 
> instance. And only
> this part will be POSTed and saved into the instance when the 
> user hits
> the "next" button.
> 
>        [------------instance-----------]
> HTML: [-----view1-----][-----view2----]
> WML:  [--view1--][--view2--][--view3--]
> 
> The view maps values from the instance to controls. Syntax reminds on
> XForms:
> 
>    <i:instance id="feedback-form">
>      <i:textbox ref="user/firstname"/>
>      <i:textbox ref="user/lastname"/>
>      ...
>    </i:instance>

Why input fields are children of instance? And should we support multiple
instances? Why not use pure XForms syntax? It will look like this:

    <xforms:group ref="feedback-form">
      <xforms:input ref="user/firstname"/>
      <xforms:input ref="user/lastname"/>
      ...
    </xforms:group>

(Field captions as well as other possible elements and attributes are
omitted).

> 
>                                -o-
>                              Populating
> 
> Taken from the ExFormular project we call this saving into 
> the instance 
> on a POST "populating". There are two different approaches when 
> populating. Direct and indirect. While the direct populating 
> method is 
> quite straight forward on the first glance: "go through the 
> request and 
> save the request parameters into the instance" it has some major 
> problems as of the POST behaviour of checkboxes: on "true" 
> there will be 
> a request parameter, on "false" there will be no request parameter at 
> all. So with direct population you cannot set checkboxes to 
> "false". The 
> other method is indirect population. With this approach you actually 
> *know* what parameters *should* come with the request. So a missing 
> checkbox parameter means "set this checkbox to false". 
> Although we could 
> use the direct population (with some workarounds) we aggreed on using 
> indirect populating as it is the cleaner approach in the long run. No 
> hidden field or something like that...

That's good. And this will require to create an object model of the form to
be able to iterate through its fields, according constraints, etc. This will
also help in cases, when there are not 'relevant' (see XForms 'relevant'
constraint) fields. This means, that not all the fields are necessary to be
taken into account for the current request depending on values of some other
fields (not sure that it's easy to implement, though).

> 
>                                -o-
>                              Phases
> 
> A phase defines a set of nodes of an instance. Phases are usally used
> in the validation and population process.

Would we need this if we knew which fields are relevant for the current
request?

> 
>                                -o-
>                             Preceptor
> 
> Our instance can be expressed in XML. Directly when it's a 
> DOM or mapped
> via Castor when we have beans. This means we should be able to use the
> commonly used validation methods to validate our instance (= data of a
> form). We would usually  call them Schemas but since the term
> collides with short form of the W3C XML Schema validation we 
> aggreed on
> "preceptor" for a general validity description of an XML 
> document. Such 
> a desciption will be served via pipeline and then "compiled" 
> and saved 
> into the scope of the instance. The JARV project shares 
> almost the same 
> idea here. Unfortunately they do not have support for partial 
> validation 
> yet, too.

I would keep Schema as it is also used in XForms to describe to model schema
(which is not required to be W3C XML Schema). Preceptor is not obvious and
is difficult to pronounce ;)

> 
> There are two different parts of XML document validity:
>   a) structure of the document
>   b) content of nodes

c) data dependency 

>                                -o-
>                           Content Validation
> 
> Let's focus on the content first. It's the most important 
> thing for form
> validation. Each preceptor defines some kind of rules, restrictions,
> assertations for the content of nodes of the instance. As 
> general term 
> we will call them "constraints". Probably the most important 
> constraints 
> from the grammar based world (schema,relaxng) are
> 
>   *) regular expressions constraint
>   *) enumeration or choice constraint
>   *) minimum number value constraint
>   *) maxmimum number value constraint
>   *) minimum string length constraint
>   *) maximum string length constraint
>   *) ...
> 
> While schematron only has a single but very powerful constraint that
> combines all the above into the
> 
>   *) XPath expression constraint (except for regex until XPath 2.0)

We can use XForms markup for model schema description and use Schematron for
validation. Although, I'm not sure for other implementations.

> 
>                                -o-
>                           Structure Validation
> 
> The structure validation takes care of the instance to conform to a
> described xml structure. We have not yet aggreed if the 
> structure should
> be fully described by the preceptor or a partial describtion may be
> sufficient. This decision has a major impact on the building of the
> instance and the implementation details.

What about the validation against contraints? Say, 'required' fields? Maybe
we can develop our own validator for XForms binding contraints?

> 
>                                -o-
>                           Building the Instance
> 
> At the start of the flow an instance needs to be created to take the
> values of the POSTs. If we want to support structure 
> validation we need 
> to make sure that already the empty instance conforms to the 
> preceptor. 
> As of this we need to create all the required nodes in this 
> instance then.

How do we deteremine required nodes? 

> 
>                        A SIMPLE FORM VALIDATION
> 
> This is how we would like to see form validation in action:
> 
>   1. Introspection happens at the start of flow. An empty 
> instance gets
>      created and save into the desired scope. It can also get filled
>      with some inital values.

Agree. 

> 
>   2. The controller (an action or schecoon) will choose the 
> first view to
>      present to the user.

Also agree.

> 
>   3. If the user now presses a (submit) button the values get 
> populated
>      into the instance and then validated. If some 
> constraints failed we
>      go back to the first view telling the user which constraint have
>      failed otherwise present him the next view.

Flow controller also should determine that the process is finished and
perform some business logic calls with collected data, isn't it? After that
some default (success page) should be displayed.

> 
> Unfortunately this looks much easier at the first glance than 
> it is. We
> will now try to talk about the problems we have encounter so far.
> (and there possible sollutions ;)
> 
> on 1)
>    How do we specify an introspection for a flow?
> 
>      This can easily be done either with schecoon or with the 
> multiaction
>      that comes with precept. But the question is: Should 
> this be modeled
>      in XML, in java or a scripting language?

Form descriptor can be dynamic and have special tags for this, e.g.:
<instance>
	<castor:insertBean .../>
<instance>
Then it will be used as source for IntrospectionAction:

<map:act type="init">
	<map:parameter name="form-descriptor"
value="cocoon:/get-form?form-id=102" />
</map:act>

Seems a little complicated...

> 
> on 2)
>    How does the controller know which view is the first one and what
>    views are actually available?

For a good wizard it would be also needed to know what actions are available
('next', 'previous', 'done', etc.).

> 
>      This could be set from the introspection. If not 
> specified the first
>      view from a possible descriptor could be taken.
>      See also "VIEWS AND PHASES".

This depends on the flow engine. Should we focus on this now?

> 
> on 3)
>    How does the controller know what to populate and validate on a
>    submit?
> 
>      Inside the views or in a descriptor like it is in Struts 
> we should
>      probably have a mapping of the phases to buttons.
>      See "VIEWS AND PHASES".

This can be addressed by using XForms 'relevant' contraint and some of the
events. Say, treat a button as event, then go through the form description
to find out which fields are affected with this event.

> 
>    And how does he know about the current and the next view?
> 
>      Same as above. This can happen in the controler or be specified
>      in the view.
>      See "VIEWS AND PHASES".

This is also flow controller specific.

> 
>    What if we don't want to populate and validate all 
> controls in a view?
> 
>      We need to keep in mind to decouple the phases from the views
>      See "VIEWS AND PHASES".

See 'relevant' contraint in XForms.

> 
>    How do we present the failed constraints to the user?
> 
>       We can use the InstanceTransformer to insert a 
> list/tree of errors
>       into the SAX stream somewhere in the view or output the failed
>       constraints with the controls itself.

Agree. 

> 
>    How can we only validate parts of an instance?
> 
>       Unfortunately most current validation implementations don't
>       support partial validation of documents yet. Schematron is
>       one exception. Maybe some of the authors can assist here.

Maybe we can validate the document in whole, but ignore irrelevant parts?

> 
> Since much of the problems are phases / views related we took 
> a closer look.
> 
> 
>                        VIEWS AND PHASES
> 
> 
> First thing our discussion revealed was that views and phases are not
> necessarily the same. They might be the same for the most 
> easy webforms
> but as soon as it comes to more complex applications you need to 
> decouple them. They describe different things:
> 
>   *) phases describe a set of instance nodes to be validated
>   *) views describe a set of instance nodes to be displayed
> 
> So as a result we found that buttons should be bound to phases.
> Either within the view or within a descriptor:
> 
> a) within the view
> <view>
>    <instance id="..">
>      <textbox ref="user/firstname"/>
>      <textbox ref="user/lastname"/>
>      <button>
>        <caption>Next</caption>
>        <populate>phase2</populate>
>        <validate>phase2</validate>
>      </button>
>    </instance>
> </view>

Hm... Absolutely not XForms synax. Are we going to invent our own markup?

> 
> b) within a descriptor
> 
>     <no syntax yet/>

Maybe XForms bindings can solve this one?

> 
> Currently only schematron comes with a native phases support. All the
> others don't support partial validation yet. Although Torsten 
> is not so
> sure if this should be really part of the preceptor.
> (Torsten: as soon as you move a textbox from one view into 
> another one 
> you need alter your preceptor because the phases have 
> changed. For SoC 
> this should not be IMHO)

I am agree with Ivelin on this one. 

> 
> 
> But the question still remains: how can we implement phases for 
> preceptor other than schematron? All we came up was some kind of 
> PhaseResolver than can takes the same schematron file as 
> input for the 
> SchemtronPhaseResolver and other descriptors (to be defined) for e.g. 
> the RelaxNGPhaseResolver.

Seems to me a little artificial, it's not a good sign ;)

> 
>                        IMPLEMENTATION DETAILS
> 
>  From the above we came up with some minimalistic interfaces:
> 
> /**  the instance save and retrieves values based on an xpath
>    */
> interface Instance {
>    public void setValue( String xpath, Object value, Context context);
>    public Object getValue( String xpath );
> }

What about the
addValue(...)
removeValue(...)
?

> 
> /**  the preceptor validates nodes from a specific phase 
> looked up via 
> the phase resolver
>    *
>    */
> interface Preceptor {
>    public Collection validate( Instance i, PhaseResolver resolver, 
> String phase, Context context );
>    /* or better typesafe?
>    public Constraint[] validate( Instance i, PhaseResolver resolver, 
> String phase, Context context );
>    */

Why Constraint[] and not ContraintViolation[]? Shouldn't validate perform
validation then return an error list?

> }
> 
> /**  the constraint actually checks the the values of a node.
>    *  it's usually a wrapper to existing "restrictions,rules,..."
>    */
> interface Constraint {
>    public boolean isSatifiedBy( Object value, Context context );
>    public String getId();
> }

Shoudn't it be used inside of validate to iterate through and get
ConstraintViolation or ValidationError objects?

> 
> /**  the phase resolver returns the xpaths for for phase
>    */
> interface PhaseResolver {
>    public String[] lookupNodesForPhase( String phase );
> }

IMO, 'getRelevantNodes()' sounds a little better.

> 
> 
>                          COMMENTS
> 
> from Torsten:
> - I am in favor of "structure validation" of forms. So all I 
> define is 
> the preceptor (xsd or relaxng) and this even describes how 
> the instance 
> has to look like. And I am then sure my instance looks like 
> the preceptor.
> - I am in favor of grammar markups like xsd or relaxng because then 
> constraints (e.g. EnumerationConstraints) can easily be used to fill 
> e.g. comboboxes (see example2 in precept) with e.g. 
> schematron all this 
> is "hidden" in expressions

Agree

> - Later I like to add an interface ClientJavaScript (or somthing like 
> that) so that constraints can produce javascript code for 
> client validation

This would be a cool feature.

> 
> from Ivelin:
> <nothing yet/>
> 
> Puh! Now it's your time ;)
> Any comments are welcome!!!

See above. More to come after looking closer to your samples.

Regards,
	Konstantin
_________________________________________
Konstantin Piroumian
Lead Developer
ICQ#: 2297575
* Work Tel#:  +7 095 795 0520 * 1288
* More ways to contact me
i See more about me
_________________________________________



> --
> Torsten + Ivelin
> 
> 
> ---------------------------------------------------------------------
> 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