.. index:: using_builders
.. _using_builders:
Using Builders
**************
Creating ODM messages by hand can be difficult. The builders package provides a simple API for generating these
ODM documents.
Here is an example of an ODM message to create a subject and update two values in the Enrollment default form for
this study.
.. code-block:: xml
This ODM file can be created using builders with this python code::
>>> from rwslib.builders import *
>>> odm = ODM("test system")(
... ClinicalData("Mediflex","DEV")(
... SubjectData("MDSOL","New Subject", "Insert")(
... StudyEventData("Subject")(
... FormData("EN", transaction_type="Update")(
... ItemGroupData()(
... ItemData("SUBJINIT","AAA"),
... ItemData("SUBJID",001)
... )
... )
... )
... )
... )
... )
>>> # Get an lxml document from the ODM object for further manipulation
>>> root = odm.getroot()
>>>
>>> # Print a string representation of the ODM document
>>> print(str(odm))
Builders also allow you to create the elements in stages and "pipeline" them together to create the document. The
following example creates the same document as above::
>>> from rwslib.builders import *
>>>
>>> # Make a root ODM element with originator system
>>> odm = ODM("test system")
>>>
>>> # Study and environment
>>> clinical_data = ClinicalData("Mediflex", "DEV")
>>>
>>> # Subject Site, Subject Name and the transaction type
>>> subject_data = SubjectData("MDSOL", "New Subject", "Insert")
>>>
>>> # The special "SUBJECT" event represents subject-level forms
>>> event_data = StudyEventData("SUBJECT")
>>>
>>> # We want to update this form that will be created automatically when subject created
>>> form_data = FormData("EN", transaction_type="Update")
>>>
>>> # We need an ItemGroupData element
>>> itemgroup = ItemGroupData()
>>>
>>> # Push itemdata elements into the itemgroup
>>> itemgroup << ItemData("SUBJINIT","AAA")
>>> itemgroup << ItemData("SUBJID",001)
>>>
>>> # Now we put it all together
>>> odm << clinical_data << subject_data << event_data << form_data << itemgroup
>>>
>>> # Get an lxml document from the ODM object for further manipulation
>>> root = odm.getroot()
>>>
>>> # Print a string representation of the ODM document
>>> print(str(odm))
The builder creates a number of ODM properties including CreationDateTime, FileOID (a random identifier), FileType and
all namespace declarations.
Metadata Builders
-----------------
Builders also exist for creating Metadata ODM files::
from rwslib.builders import *
odm = ODM("SYSTEM_NAME", filetype=ODM.FILETYPE_SNAPSHOT)
study_name = 'MyStudy'
draft_name = 'Draft 1'
study = Study(study_name, project_type=Study.PROJECT)
# Push study element into odm
odm << study
# Create global variables and set them into study.
study << GlobalVariables(study_name) # Expected that protocol name will match the Study OID.
# Create some basic definitions
bd = BasicDefinitions()
# Add some measurement units to the basic definitions. This time using the call () syntax:
bd(
MeasurementUnit("KG", "Kilograms")(
Symbol()(TranslatedText("Kilograms"))
),
MeasurementUnit("CM", "Centimeters")(
Symbol()(TranslatedText("Centimeters"))
)
)
# Add basic definitions to study
study << bd
# Now metadata which will contain all our form and field defs eventually
meta = MetaDataVersion('META1', draft_name)
study << meta
# Protocol contains StudyEventRefs
protocol = Protocol()
# Add some StudyEventRefs
protocol << StudyEventRef("FLDR1", 1, True) # Order 1, Mandatory
# protocol << StudyEventRef("FLDR2", 2, False) # Order 2, Not Mandatory
# protocol << StudyEventRef("AE", 3, True)
meta << protocol
# Add Study Event Defs with some child FormRefs
fldr1 = StudyEventDef("FLDR1", "Folder 1", False, StudyEventDef.SCHEDULED)
fldr1 << FormRef("DM", 1, True)
fldr1 << FormRef("VS", 2, True)
meta << fldr1
meta << StudyEventDef("FLDR2", "Folder 2", False, StudyEventDef.UNSCHEDULED)(
FormRef("VS", 1, True)
)
meta << StudyEventDef("AE", "Adverse Events", False, StudyEventDef.COMMON)(
FormRef("AE", 1, False)
)
dm_form = FormDef("DM","Demography")
dm_form << MdsolHelpText("en","Some help text for Demography form")
dm_form << MdsolViewRestriction('Data Manager')
dm_form << MdsolEntryRestriction('Batch Upload')
dm_form << ItemGroupRef("DM_IG1", 1)
dm_form << ItemGroupRef("DM_IG2", 2)
# Add to metadata
meta << dm_form
# Define item group
meta << ItemGroupDef("DM_IG1", "DM Item Group 1")(
MdsolLabelRef("LBL1", 1),
ItemRef("SEX", 2),
ItemRef("RACE", 3),
ItemRef("RACE_OTH", 4),
ItemRef("DOB", 5),
ItemRef("AGE", 6)
)
# Add the ItemDefs
meta << ItemDef("SEX", "Gender", DATATYPE_TEXT, 1, control_type=ItemDef.CONTROLTYPE_RADIOBUTTON
)(
Question()(TranslatedText("Gender at Birth")),
CodeListRef("CL_SEX")
)
meta << ItemDef("RACE", "Race", DATATYPE_TEXT, 2,
control_type=ItemDef.CONTROLTYPE_RADIOBUTTON_VERTICAL
)(
Question()(TranslatedText("Race")),
CodeListRef("CL_RACE")
)
meta << ItemDef("RACE_OTH", "RaceOther", DATATYPE_TEXT, 20) \
<< Question() << TranslatedText("If Race Other, please specify")
meta << ItemDef("DOB", "DateOfBirth", DATATYPE_DATE, 10,
control_type=ItemDef.CONTROLTYPE_DATETIME,
date_time_format="dd/mm/yyyy"
)(
Question()(TranslatedText("Date of Birth")),
MdsolHelpText("en","If month unknown, enter January")
)
meta << ItemDef("AGE", "Age in Years", DATATYPE_INTEGER, 4, significant_digits=3, control_type=ItemDef.CONTROLTYPE_TEXT
)(
Question()(TranslatedText("Age in Years")),
RangeCheck(RangeCheck.GREATER_THAN_EQUAL_TO, RangeCheck.SOFT) (
CheckValue("18")
),
RangeCheck(RangeCheck.LESS_THAN_EQUAL_TO, RangeCheck.SOFT) (
CheckValue("65")
)
)
# Add a Label
meta.add(MdsolLabelDef("LBL1", "Label1")(TranslatedText("Please answer all questions.")))
# As well as () and << you can use add()
meta.add(
CodeList("CL_SEX", "SEX", datatype=DATATYPE_TEXT)(
CodeListItem("M").add(
Decode().add(
TranslatedText("Male"))
),
CodeListItem("F").add(
Decode().add(
TranslatedText("Female"))
),
),
CodeList("CL_RACE", "RACE", datatype=DATATYPE_TEXT)(
CodeListItem("Y")(Decode()(TranslatedText("Yes"))),
CodeListItem("N")(Decode()(TranslatedText("No"))),
)
)
# Get an lxml document from the ODM object for further manipulation
root = odm.getroot()
# Print a string representation of the ODM document
print(str(odm))