If the term "Stitching" is new to you, it refers to server applications that take the content of multiple XDP files and combine them into a whole. While this sounds like fragment resolution, there is a twist in that the content to be combined isn’t known until the document is requested. The most common scenario is where a company has a series of individual forms that can be delivered stand-alone or may be included as sub-forms in a larger package. Package in this context is not a portfolio or PDF package, but rather, a sequence of templates combined serially into one big form.
Historically there have been at least two ways to implement stitching:
- Stitching implemented by professional services
- Solution Accelerator (ODA)
Then in LiveCycle ES2 we delivered fragment stitching in LiveCycle Assembler.
Going forward, the Assembler version is the one customers should be targeting, as it is fully supported and will be the solution that
Building a system where we can stitch templates together requires some careful planning. Random forms cannot be arbitrarily stitched together. Any attempt to
do so will inevitably run into conflicts regarding scripting, master
pages, schemas, submit logic, validations etc. In order for individual
forms to be combined into a stitched package, the individual forms must
follow a design pattern that allows them to participate in the final
In order to explain the stitching process and the necessary design patterns, it helps to start by using some terminology consistently.
- individual form – a template that can be used as a standalone form
or can be combined with other individual forms into a stitched package
- stitched package – a collection of individual forms combined into a
single, large XDP/PDF. Not to be confused with portfolios or PDF
- host template – the XDP that forms the root of the stitched
package. Individual forms are inserted into the host template to form
the stitched package
- root subform – the subform that appears under the template element in an XDP definition.
- stitched subform – the subform that will be extracted from individual forms to be included in a stitched package
Some of the common requirements that we see in customer implementations of stitching:
- Individual forms must retain their own master page associations
- Shared script objects must not be duplicated when individual forms are combined
- Individual forms must be able to retain their own form-specific logic
- Submit logic for individual forms must collapse into a global
submit capability in the resulting stitched package. i.e. submit
buttons from individual forms must be hidden when part of the larger
- We must be able to include multiple copies of any individual form into a stitched result
- The number of individual forms included in the final package needs to be arbitrary – no pre-defined limits
The Form Design Pattern
The host template will form the root of the stitched package. It
will define all properties that are global to the form. e.g. default
locale, target Reader version, Server PDF render format, form state
setting, meta data etc.
Each individual form must have compatible settings to the host
template, especially: same target Reader version, same
All individual forms to be combined into a stitched package must be
based on the same XML schema (or must all be designed without a schema). The host template will include the
connectionSet for this shared schema. If an organization has multiple
schemas, they must either combine them into a single uber-schema or they
must maintain one host template for each schema that is in use.
Shared WSDL definitions
Since we do not stitch together connectionSets, the host
template must also include the aggregate set of WSDL definitions used by
individual forms. It is necessary that individual forms use consistent names when
referencing XML schemas and WSDL definitions. This is especially true
for WSDL definitions where the names are used in script and in template
Individual Form Hierarchy
Individual forms must be designed in such a way that so that all
content to be included in the package resides under a single subform
included under the root subform. This second-level subform is the
stiched subform – the content that will be extracted from the individual
form and included in the stitched package.
For reference, here is a sample hierarchy of an individual form:
In this example, the subform named “PO_Portrait” is the stitched subform that will be included in the final stitched package.
Any logic that is common to multiple individual forms should be
included in the individual forms as a child of the root subform (as a
sibling to the stitched subform). The host template must include a copy
of this shared script. In the example above, the “countryScript”
script object would not be included with the content of the individual
form, but since it is present in the host document, the logic inside
PO_Portrait will continue to work in the package context.
If there is logic that is unique to an individual form, it must be
included as a descendant of the stitched subform. This way, it will be
extracted with the stitched subform into the stitched package.
Stitched subforms must define master page definitions as descendants
As long as the master pages used by a stitched subform are
descendants of that subform, they will be included in the final stitched
package. Details at nested master pages.
Note as well that for multiple master page collections to work in the
stitched package, all individual forms should use a consistent printing
option. One of: Print on Front Side Only/Print on Both Sides/Page
The stitched subform must explicitly target its nested master page.
In the example, the pagination option for PO_Portrait is to place: ‘On
Page “PO_PortraitPage” ‘.
The stitched subform must be a fragment
From the context menu in Designer, Fragments/Create Fragment…
Choose “Create New Fragment in Current Document”. The Name you choose
will be the name that is referenced by Assembler. It can be either a
name that is unique to the individual form, or you can use the same name
for all individual forms. re-using the same name will make the
Assembler DDX syntax simpler.
The host document needs an insertion point
Create a nameless subform directly below the root subform. Use this subform to define a named insertion point:
Note that the insertion point subform must not specify any properties –
name, width, height etc, or else these will override the properties of
the fragment that will be inserted. In the sample, the XML for the
insertion point subform is very simple:
Note that because of the way Assembler processes insertion points, a
single insertion point can be used to insert an arbitrary number of
Control the presence of submit buttons
In the form properties of the host template, create a variable to
indicate the document is a stitched package. The example uses
“IsPackageDoc” and gives it a value: “1”. In the individual forms, put
logic on the submit button initialize event that looks like:
This logic will ensure that the button is visible when the form is an individual form, but hidden when part of a package.
Make sure your schema can repeat
If you want to include more than one copy of any individual form, you
need to make sure that the schema element the stitched subform binds to
is allowed to repeat. This might require wrapping the root element of
your schema in an aggregating subform.
A starter template
For customers who have the luxury of designing these solutions from
scratch, it is wise to create a starter skeleton individual form
template that includes the shared logic, second level subform, nested
master pages, corporate schema, WSDL definition(s) and submit button.
This reduces the need for form authors to remember all the necessary
requirements that are part of the design pattern.
The Assembler Step
In assembler we use the XDPContent command to insert individual forms
into the host template. e.g. our sample below uses this DDX:
Here is an example an that follows the design pattern described in this note. An explanation of the included files:
- Purchase Order.xdp – an individual form
- ExtraComments.xdp – An individual form
- Purchase Order Landscape – An individual form
- Purchase Order.tif – A referenced image
- Purchase Order Dim.tif – referenced image
- Purchase Order Group.xsd – the uber schema
- Purchase Order Host.xdp – the host template
- stitch.ddx.txt – the Assembler DDX definition used to stitch
- result.pdf – what it looks like when assembled.
The Deep End
If you’re interested in understanding the details on how insertion points work, here’s some copy/paste from the specification:
- The stitching capability will allow us to “push” fragments into
specific locations (insertion points) within a host document based on
logic that exists outside the document.
- In cases where the number of inserted fragments is not known in
advance, we need to be able to push an arbitrary number of fragments
into a single stitch point.
- The host template may have placeholder content that needs to be removed
In preparation for stitching, these grammar rules will be defined:
- Add “insertion points” in the host template – places where external content may be inserted
- Add “placeholder content” in the host template so that it is visible in Designer, but excluded from the final stitched result
- The LiveCycle assembler component grammar (DDX) will have a command (XDPContent) for inserting a fragment to a insertion point
A insertion point will be a mnemonic defined using <extras> named: “insertionPoint“. E.g.:
When Assembler executes a stitch, it will:
- Find all insertion points that match the target attribute of the XDPContent command
- For each insertion point, clone the XFA element containing insertion point
- Replace the insertion point syntax with the syntax of a fragment
reference. If the element already has a fragment reference, over-write
the existing reference.
- Remove any content marked as being a placeholder
When Assembler has completed it will execute a post-process:
- Remove any elements that still have a remnant insertionPoint extras element.
- Resolve all fragments
The assembler DDX definition would include an XDPContent command to inject a fragment reference at this subform:
The result after processing the XDPContent command: