Summary
This article covers the XML Export Principle, configuring your study for XML Exports, recipe XML structure, available iterators and filters, and extending functionality.
Table of Contents
- Concepts Covered
- The XML Export Principle
- Configuring your Study for XML Exports
- Recipe XML Structure
- Recipe Element apply
- Recipe Element applyTemplate
- Recipe Element attribute
- Recipe Element content
- Recipe Element defineKey
- Recipe Element defineTemplate
- Recipe Element “document”
- Recipe Element element
- Recipe Element “eval”
- Recipe Element “filter”
- Recipe Element “instruction”
- Recipe Element “iterator”
- Recipe Element processingInstruction
- Available Iterators
- Available Filters
- Extending Functionality
An XML export allows the creation of XML documents from Fountayn; data. The XML export is configured with an XML transformation document. As multiple XML documents are participating in the process, we define the following terms:
A Recipe XML is an XML document that describes how Fountayn; data needs to be transformed to create XML documents.
An Artifact XML is an XML document that is created from the XML export processing.
You can think of the XML export as the process of cooking one or more artifact XML documents with the help of one recipe XML document.
Defining an XML export means creating a recipe XML document. Thus some knowledge of XML is required for the configuration step.
Concepts Covered
This tutorial covers the following topics:
- The XML Export Principle
- Configuring your Study for XML Exports
- Recipe XML Structure
- Available Iterators
- Available Filters
- Extending Functionality
The XML Export Principle
An XML export always starts at the patient level. The patient is the root to which the recipe XML is applied.
There is no native way to support subset exports for a visit selection. If your XML artifacts are visit specific, then you can create multiple visit specific XML artifacts with one suitable recipe XML. However, all of these XML documents will be included in the XML export archive and you might need to copy the desired documents from your export archive as final step. For more information on subset exports you may want to evaluate page Subset Exports.
Configuring your Study for XML Exports
Let us assume that you are already in possession of the recipe XML file that configures the XML export for your study. There are two things required to get your export to work:
- Configure your export in the Exports tab of the DataArchitect file.
- Use Trial Manager to add the recipe XML as data file to your study.
Configure your export in the Exports tab of the DataArchitect file
Beside the usual export configuration like export id, name and description you need to set the following:
- Writer Type needs to be set to xml.
- Formatter Type needs to be set to xml.
- A formatter parameter named recipeFileName needs to be set to the file name of the recipe XML file. This parameter requires a plain file name without path and without extension.
- Optional: If your recipe XML file uses a different extension than “xml”, then you need a formatter parameter named recipeExt, which needs to be set to the extension of the recipe XML file without the dot.
Examples:
When your recipe file is named “safety.xml“, then the recipeFileName parameter needs to be set to “safety“.
When your recipe file is named “safety.rcp“, then the recipeExt parameter needs to be set to “rcp“.
Use Trial Manager to add the recipe XML as data file to your study.
The recipe XML file needs to be added to your study. This is done in the same way as other data files are added.
Recipe XML Structure
This section describes the recipe XML structure.
Recipe XML documents use a simple structure that does not contain any namespace definitions. We do not expect using recipe XMLs for other than XML export configuration purposes. This simple structure should make recipe XML files more readable.
Recipe Element apply
The apply recipe element needs to be a direct child under an eval recipe element. The contained node list will be evaluated in the current context. Inside of the apply recipe element, the (previously) defined keys and defined templates of the eval recipe element can be resolved and applied. As soon as the apply recipe processing has ended, defined keys and template are not valid anymore. Be aware that the apply recipe element should be the last child of the eval recipe element.
The apply recipe element does not support any attributes.
Recipe Element applyTemplate
The applyTemplate recipe element can used anywhere, but under of an apply recipe element for which a template with the required name is defined with defineTemplate recipe element. The node list stores for the template name is applied in this situation. Be aware that applying templates can be done recursively. While this is a powerful tool to build your artifact XML document it included the possibility to build endless loop of template applications. EClinical will abort the XML export if such an endless loop is suspected. An endless loop is suspected, when a predefined number of nested applyTemplate steps is reached. If the XML export is aborted because of this restriction, then your recipe XML probably contains a problem and needs to be changed.
Attribute name
This attribute needs to be the name of an existing template defined with defineTemplate recipe element. The XML export will abort, when the specified name is not identified as valid template.
Recipe Element attribute
The attribute recipe element can be used as direct child of an element recipe element only. It creates an attribute for the element under construction.
Attribute name
This attribute defines the name of the attribute to generate.
Attribute value
This attribute defines the value of the attribute to generate.
Attribute namespaceURI
This attribute can be used, when the artifact attribute’s name should belong to a special namespace. In this case the plain name attribute needs to be a qualified name.
Example
<element name="myElement"> <attribute name="myAttribute" value="myValue" /> </element>
This recipe would be cooked to:
<myElement myAttribute="myValue"/>
Recipe Element content
The content recipe element can only be used as direct child of an element recipe element. It defines what text content the artifact element should have.
In general there are two ways to define the text content for an artifact element. If it is a constant text, the element’s attribute content should be used. If the text is not constant and you want to use instructions to build the text, then this content recipe element is the one to use.
A content recipe element can have multiple instruction recipe elements. All the instructions are chained to build the text content of the artifact element. Please see page Custom Export Formatter Instructions for a description what chaining instructions means. Just a warning: chaining does not mean that the instruction results are concatenated.
The content recipe element is equivalent to following: use an eval recipe element with a defineKey recipe element, which binds a key name to the result of an instruction evaluation, then – in the apply recipe element – use the key’s value from the element’s content attribute. This content recipe element is a help to avoid the more complex structure. It allows using instructions exactly where you need them.
The content recipe element does not support attributes.
Example
<element name="myElement"> <attribute name="myAttribute" value="myValue" /> <content> <instruction name="const" value="My text content" /> </content> </element>
This recipe would be cooked to:
<myElement myAttribute="myValue">My text content</myElement>
Recipe Element defineKey
The defineKey recipe can be used as direct child under an eval recipe element only. It is used to create a (key, value) pair. While the key is an ordinary string, the value is constructed with instructions. All children of the defineKey recipe element need to be instruction recipe elements. These instructions are chained to create the value of the pair.
When you define a key, then this can be used with the question mark operator for any attribute in the following apply recipe element. Example for key myFileName and usage with ?myFileName:
<eval> <defineKey name="myFileName"> <instruction name="const" value="myRecipe" /> </defineKey> <apply> <document fileName="?myFileName" /> <element name="root" /> </document> </apply> </eval>
Furthermore it is possible to use these keys in a special filter recipe elements. Example for key namespaceURI and filter keyValueNotEmpty:
<eval> <defineKey name="namespaceURI"> <instruction name="qst" questionId="attribNamespaceURI" /> </defineKey> <apply> <attribute name="name" value="myAttribute" /> <filter name="keyValueNotEmpty" key="namespaceURI"> <attribute name="namespaceURI" value="?namespaceURI" /> </filter> <attribute name="value" value="myValue" /> </apply> </eval>
Recipe Element defineTemplate
The defineTemplate recipe element can only be used as direct child under an eval recipe element. It is used to store a recipe node list under the template name. This node list can be used inside of the associated apply recipe element with a applyTemplate recipe element. Everywhere, the applyTemplate element is used the stored node list for the template is used as recipe.
Attribute name
This attribute specifies the name of the template. The same name needs to be used in the applyTemplate recipe element.
Example
<eval> <defineTemplate name="anything"> <iterator label="all" name="form" parent="1" path="*" context="true"> <applyTemplate name="filterOnEval" /> <applyTemplate name="filterOnDocument" /> <applyTemplate name="filterOnProcessingInstruction" /> <applyTemplate name="filterOnElement" /> <applyTemplate name="filterOnIterator" /> <applyTemplate name="filterOnFilter" /> </iterator> </defineTemplate> <!-- more template definitions --> <apply> <document fileName="myRecipe" fileExt="xml"> <applyTemplate name="anything" /> </document> </apply> </eval>
Recipe Element “document”
The document recipe element is used to create a document. Within one recipe many document recipe elements can be used, but it is not allowed to nest document recipe elements within each other. Thus there can be only one active document recipe element at any time of the processing. Within each document recipe element you need to use an element recipe element, which will generate the document element or root of the XML file.
Attribute fileName
This attribute specifies the plain file name without path and extension for the file to generate. If you omit this attribute then files will be named xmlDoc1, xmlDoc2 and so on.
Attribute fileExt
This attribute specifies the file extension of the generated XML file. If you omit this attribute, then the default “xml” will be used.
Example
<iterator name="form" path="aeSummary.ae[n]"> <document> <element name="adverseEvent"/> </document> </iterator>
This recipe will iterate over all adverse events and create one simple document per adverse event. Files will be named xmlDoc1.xml, xmlDoc2.xml and so on.
Recipe Element element
The element recipe element will generate one element under the current artifact node. You can use this element only as descendant under an document recipe element.
Attribute name
This attribute defines the name of the element to generate.
Attribute namespaceURI
This attribute can be used, when the artifact element’s name should belong to a special namespace. In this case the plain name attribute needs to be a qualified name.
Attribute content
This attribute defines the text content of the element to generate. As alternative to this attribute it is possible to use a content recipe element, which can use instruction recipe elements to calculate the element’s text content.
Example
<element name="myElement" content="My text content" />
This recipe would generate this artifact:
<myElement>My text content</myElement>
Recipe Element “eval”
An eval recipe element requires one apply child recipe element. In general the recipe node list under the apply recipe child is used for the eval recipe processing. The eval recipe element allows defining keys and defining templates that can be used from the apply recipe content.
The eval recipe element does not support any attributes.
Example
<eval> <defineKey name="myFileName"> <instruction name="const" value="myRecipe" /> </defineKey> <defineTemplate name="root"> <element name="rootElement" /> </defineTemplate> <apply> <document fileName="?myFileName"> <applyTemplate name="root" /> </document> </apply> </eval>
Recipe Element “filter”
The filter recipe element is used to determine whether the recipe processing with the filter’s child node list is continued or not. In general the filter will evaluate to a Boolean value. The processing continues, if and only if the filter evaluated to true.
Attribute name
This is the name of the filter that should be used. There is a number of predefined available filters and more can be added on a custom code basis.
Attribute logic
The filter logic can easily be reversed with this attribute. Set it to “not” or “inverse” and the filter will behave exactly the other way around to its description.
Example
The following two examples are equivalent:
<iterator name="form" path="*"> <filter name="keyValueEmpty" key="someKey" logic="inverse"> <element name="?someKey" /> </filter> </iterator>
and this:
<iterator name="form" path="*"> <filter name="keyValueNotEmpty" key="someKey"> <element name="?someKey" /> </filter> </iterator>
The logic attribute can be applied to any filter.
Additional Attributes
There can be more attributes that are required or optional for an filter. This is dependent on the filter itself and documented in the description of the filters.
Example
<iterator name="form" parent="#" path="cmSummary.cm[n]" context="true"> <filter name="formExpression" value="cmterm EQUALS_RX M.*"> <element name="cm"> </filter> </iterator>
With this sample recipe, only concomitant medications, where the value for the question “cmterm” starts with the letter M will be processed.
Recipe Element “instruction”
The instruction recipe element is used to define an instruction that should be evaluated in a special context. An instruction can be used as child of a content recipe element or a defineKey recipe element.
The benefit of instructions is that there is a bunch of available instruction that is intended to format output in a special way. Example: there is an instruction that combines the values of a date and a time question and returns a single date in ISO8601 format. Please see page Custom Export Formatter Instructions for a description of what instructions can do for you.
Attribute name
This is the name of the instruction to use.
Attribute value
Optional. This is the value that is passed to the instruction. It is called value for historical reasons. Think of this as a parameter value that can hold anything which makes sense for an individual instruction.
Attribute questionId
Optional. This is the questionId value that is passed to the instruction. In general the value of the questionId is a question path within the currently active form or patient. However, some instructions do influence the way how questionId values are evaluated.
Recipe Element “iterator”
An iterator recipe element is used to iterate over a list of objects.
Attribute name
This is the name of the iterator that should be used. There is a number of predefined available iterators and more can be added on a custom code basis.
Attribute label
This attribute allows the specification of a label that is attached to the selected object. This allows to reference an object by label. For example, the iterator form uses a parent attribute. This could name the level of an iterator that was previously registered.
Attribute context
This needs to be a Boolean value that specifies whether the object is registered in the instruction context for instructions that works on the selected (registered) elements. In rare situations there might be a requirement to not register an iterator object to the context. If this attribute is missing, the default true is used.
Additional Attributes
There can be more attributes that are required or optional for an iterator. This is dependent on the iterator itself and documented in the description of the iterators.
Example
<iterator name="form" path="aeSummary.ae[n]"> <document> <element name="adverseEvent"/> </document> <iterator>
For this sample recipe the cooking will iterate over all adverse event forms before one document per adverse event is created.
Recipe Element processingInstruction
The processingInstruction recipe element will create a processing instruction for the artifact.
Remark: The xml processing instruction with the version and the encoding will automatically be written to the artifact xml file. It does not need to be created with an explicit processing instruction recipe element, see the example below.
Attribute target
This is the target string for the processing instruction to generate.
Attribute data
This is the data string for the processing instruction to generate.
Example
<document> <processingInstruction target="myTarget" data="myData" /> <element name="myRoot" /> </document>
This recipe will generate a document with the following content:
<?xml version="1.0" encoding="UTF-8" ?> <?myTarget myData?> <myRoot />
Available Iterators
Iterator form
The form iterator allows iteration over forms. From the specified parent element, which can be a patient or a form object, the specified path is resolved and all matching elements are returned from the iterator.
Attribute parent
This attribute specifies the parent object from which the the matching forms are searched from. It can be either a label that was given to any predecessor iterator, or it might be a positive integer number, defining the level of iterator in front of the current one. When this has the value “1″, then the last registered iterator object is use as source for the form resolution. A value of “2″ identifies the iterator that was registered before the last one and so on. The patient from which the XML exporting is started is registered under label “#”.
Attribute path
This attribute describes how to find forms starting from the parent location. A path can consist of multiple path items, which are separated by a dot. Processing will iterate over all path items sequentially. There are two special constants. The constant * means that all child forms of the previous level are included in the results. The constant suffix [n] means that all sub forms with the specified type name are included in the result.
Example
<iterator name="form" parent="#" path="aeSummary.ae[n].*"> <element name="adverseEvent"/> </iterator>
This recipe sample will iterate from the root (registered under “#”) over form “aeSummary”, then over all forms of type “ae”, and then over any sub form of these forms.
Iterator referencedForms
The referencedForms iterator iterates over the selected forms of a reference question. If the reference question references questions, then the iteration is done on the forms that contain the referenced questions.
Attribute parent
This attribute specifies the parent object from which the the matching forms are searched from. It can be either a label that was given to any predecessor iterator, or it might be a positive integer number, defining the level of iterator in front of the current one. When this has the value “1″, then the last registered iterator object is use as source for the form resolution. A value of “2″ identifies the iterator that was registered before the last one and so on. The patient from which the XML exporting is started is registered under label “#”.
Attribute questionId
This attribute specifies the questionId, which needs to be a reference question. It can be a single or multiple selection question.
Example
<iterator name="referencedForms" parent="1" questionId="cmref" > <element name="concMed"/> </iterator>
This recipe will generate a concMed element for each selected value in question cmref on the previously selected form.
Iterator singleStep
The singleStep iterator iterates a single execution of its sub elements.
Example
<iterator name="singleStep" > <element name="adverseEvent"/> </iterator>
This recipe will generate a single adverseEvent element.
The singleStep iterator is great for the usage in templates, where it can easily be substituted with a different real iterator. It behaves like a “predetermined breaking point”. In productive recipes this iterator should not be used. The reason for this is that it does not register a form and prevents the usage of nested form iterators this way, which might be detected as a surprise later on.
If you create an xml recipe from a template that includes singleStep iterators, then you should do one of the following with each one:
- Exchange the singleStep iterator with a real iterator – like on that iterates over dynamic forms or selects a static form.
- Remove the singleStep iterator start and end tag, if you need the content exactly once.
- Remove the complete block – either delete it or comment it, when it is not applicable for your xml export.
Available Filters
Filter formExpression
This filter evaluates a Boolean expression on the currently registered form.
Attribute value
This attribute specifies the Boolean expression that should be evaluated on the currently selected form.
Example
<iterator name="form" parent="#" path="cmSummary.cm[n]" context="true"> <filter name="formExpression" value="cmterm EQUALS_RX M.*"> <element name="cm"> </filter> </iterator>
This filter will only allow forms whose “cmterm” question value begins with the letter M.
Filter formHasData
This filter can be used to check whether any question of the selected form holds non-empty data. If the selected form holds data, it can pass the filter. If the selected form is empty, the filter holds it back.
Filter formOrSubformHasData
This filter can be used to check whether any question of the selected form or all of its sub forms hold non-empty data. If the selected form or any of the sub forms holds data, it can pass the filter. If the selected form and all sub forms are empty, the filter holds it back.
Filter hasPosition
This filter checks whether a dynamic form is located at a specified position. Only the form with the correct position passes the filter. This filter only handles sibling forms with the same type ID as the specified parent form. Should there be a summary form that can hold both adverse event forms and concomitant medication forms, then only the matching form types are checked.
Attribute position
This attribute specifies an Integer value for the position to test. There are two ways to specify the position. A position with value 0 or greater will check the position from the front. The first position has index “0″. It is however possible to check the position from the end. Use negative values for this. The last position has index “-1″. The one before the last has index “-2″. This allows easy testing for the end of the dynamic forms too.
Attribute parent
This attribute specifies the parent level that for which an object was registered. Usually this corresponds to the label attribute value of a iterator. It can however be a numeric value specifying which previous level is desired. A value of “1″ identifies the last registered level. This is also the default, if you do not specify a parent level.
Example
<iterator name="form" parent="#" path="aeSummary.ae[n]" label="ae"> <filter name="hasPosition" parent="ae" position="-1"> <element name="lastAE" /> </filter> </iterator>
This filter will only let the last adverse event form pass. Please note that the filter names the parent level “ae” that was registered with the iterator. When you do not specify the level in this example then the previous level is used. It would not make a difference in this example.
Filter isLastDynamicForm
This filter checks whether a dynamic form is the last dynamic form within the parent container. This filter only handles sibling forms with the same type ID as the specified level form (see parent attribute). Should there be a summary form that can hold both adverse event forms and concomitant medication forms, then only the matching form types are checked.
Attribute parent
This attribute specifies the parent level that for which an object was registered. Usually this corresponds to the label attribute value of a iterator. It can however be a numeric value specifying which previous level is desired. A value of “1″ identifies the last registered level. This is also the default, if you do not specify a parent level.
Example
<iterator name="form" parent="#" path="aeSummary.ae[n]"> <filter name="isLastDynamicForm"> <element name="lastAE" /> </filter> </iterator>
This filter will only let the last adverse event form pass. This filter is a specialization of the “hasPosition” filter making things more explicit, when you are only interested in the last dynamic form.
Filter keyValueEmpty
This filter can be used to check whether a key value is empty. A key means a (key, value) pair that was defined with a defineKey recipe element.
Attribute key
This attribute specifies a key, for which the filter checks whether the key value is empty.
Filter keyValueNotEmpty
This filter can be used to check whether a key value is not empty. A key means a (key, value) pair that was defined with a defineKey recipe element.
Attribute key
This attribute specifies a key, for which the filter checks whether the key value is not empty.
Example
<eval> <defineKey name="namespaceURI"> <instruction name="qst" questionId="attribNamespaceURI" /> </defineKey> <apply> <attribute name="name" value="myAttribute" /> <filter name="keyValueNotEmpty" key="namespaceURI"> <attribute name="namespaceURI" value="?namespaceURI" /> </filter> <attribute name="value" value="myValue" /> </apply> </eval>
Extending Functionality
If you cannot build the XML artifacts that you need, there is a possibility to extend eClinical to possibly support your requirements.
The software architecture allows the addition of custom code iterators, filters and instructions. These can be implemented with a custom code request. Here is an example for special functionality that could be required. Assume you need an XML structure that depends on the available SDV (source data verification) audits for a question. Per custom code request an iterator for the SDV audits could be created, possibly supported by some instructions that allow accessing each audit. With these tools you should be able to generate the XML artifact you want.
Need more help?
Please visit the Fountayn Contact Information page.