bf:include – an alternative to XInclude
Since: betterFORM 5.0rc1 – buildNumber:11523
Author: Lars Wndauer
When building applications with many forms and especially when using a lot of subforms you’re often facing a lot of markup redundancy. This article shows a new utility in betterFORM to avoid such redundant parts thereby making your applications more maintainable.
In the XML world there is the well-known XInclude specification that handles includes in the XML markup language. However this specification only handles very simple file inclusions. If you have more fine-grained snippets to assemble you have to go for XPointer in addition which has unfortunately some shortcomings – it’s simply not or only partly implemented in many environments and has a somewhat crude syntax.
This article shows a more pragmatic approach which has been developed by the betterFORM team during its work on a large customer project.
Example 1 – simple inclusion
<xf:model> <xf:instance id="i-contacts" src="data/contacts.xml"/> <bf:include src="templates/binds-contacts.xml"/> </xf:model>
This isn’t differnt to what you would get from XInclude. It simply includes a complete file and replaces the <bf:include /> tag with that.
If authors don’t want to create a bind file for any group of binds but to manage them in a single file this is possible as well. Imagine a bind.xml as shown in example 2.
Example 2 – inclusion of a specific element
This example goes one step further allowing you to address a specific id in the referenced file. Consider the XML snippet below:
<binds> <bind id="b-contacts" nodeset="contacts"> <bind nodeset="user/@shortname" constraint="string-length(.) > 5" /> </bind> <bind id="b-events" nodeset="contacts"> … </bind </bind>
To reference the “b-contact” bind in your form simply use the fragment identifier on the URI: <bf:include src=”templates/binds.xml#b-contacts />.
This technique already allows to group similar contents together in one file but to use them in different contexts.
Form authors will quickly see how useful this small extension is, but they will also notice that in the real world things are often not as easy as this. Consider example 3.
Example 3 – add some markup to the inclusion
Often when building large form applications with XForms you’re facing markup that is largely the same in different contexts. This is especially true with many submissions that load the same data in different parts of the application. But you have to repeat the whole block just to add a different a different error-handler as the message in the example below:
<xf:submission id="s-load-data" resource="context:payload" method="get" replace="instance" instance="i-default"> <xf:message id="load-data-error-handler" ev:event="xforms-submit-error" ref="instance('i-lang')/msg[@key='submissionLoadError']"/> </xf:submission>
To handle this use case the bf:include mechanism provides an additional bf:action attribute that can be used to add some markup.
This can be achieved with the following markup:
<bf:include src="templates/submission.xml#s-load-data"> <xf:message bf:action="append" id="load-data-error-handler" ev:event="xforms-submit-error" (...) </bf:include/>
Please note the bf:action attribute here. This tells the engine to append the xf:message element to the included submission with id=”s-load-data”.
Extend Included Markup
Markup included via bf:include can easily be extended using the bf:action attribute. Example 4 shows how the bf:action attribute value “append” is used to chain a submission transforming the instance data to the “s-load-data” submission.
Example 4 – Append
<bf:include src="templates/submission.xml#s-load-data"> <xf:send bf:action="append" ev:event="xforms-submit-done" submission="s-transform-data"/> </bf:include/>
Overwrite Included Markup
Another scenario that comes up quite often is that a single piece of the included markup must be overwritten with some other markup. Example 5 shows how this can be achieved. Here the error message from example 3 is overwritten with another error submission handler:
<bf:include src="templates/submission.xml#s-load-data"> <xf:send id="load-data-error-handler" bf:action="overwrite" ev:event="xforms-submit-done" submission="s-error-handler"/> </bf:include/>
It should be noted that this inclusion mechanism can be applied at deploy- or runtime. If you want to apply inclusions at runtime you have to configure betterFORM to do so by editing the betterform-config.xml file and setting the property “webprocessor.doIncludes” to “true”.
No question bf:include especially in combination with the XForms subforms mechanism is a powerful technique for form authors when writing maintainable enterprise applications. The bf:action attributes will be available in the upcoming betterFORM 5 release. If you can’t wait simply check out the betterFORM development branch at https://github.com/betterFORM/betterFORM/tree/development and get started.
Note: the inclusion is currently still not yet integrated within the build process of betterFORM. This will follow at a later stage.