Working with Dataset-JSON v1.1

odmlib provides a spec-conformant Dataset-JSON v1.1 implementation using the same ODMElement/descriptor pattern as all other odmlib models.

Creating a Dataset-JSON File

Build a dataset programmatically and write it to JSON:

from odmlib.dataset_json_1_1.model import DatasetJSON, Column, SourceSystem

ds = DatasetJSON(
    datasetJSONCreationDateTime="2024-01-15T12:00:00Z",
    datasetJSONVersion="1.1.0",
    fileOID="FILE.AE.001",
    originator="ACME Pharma",
    sourceSystem=SourceSystem(name="SAS", version="9.4"),
    studyOID="CDISC01",
    metaDataVersionOID="MDV.001",
    itemGroupOID="IG.AE",
    records=0,
    name="AE",
    label="Adverse Events",
)

# Add columns
ds.add_column(Column(itemOID="IT.STUDYID", name="STUDYID",
                     label="Study Identifier", dataType="string",
                     keySequence=1))
ds.add_column(Column(itemOID="IT.AETERM", name="AETERM",
                     label="Reported Term", dataType="string"))

# Add rows (auto-increments records)
ds.add_row(["CDISC01", "Headache"])
ds.add_row(["CDISC01", "Nausea"])

# Write to JSON file
ds.write_json("ae.json")

# Or write NDJSON (streaming format)
ds.write_ndjson("ae.ndjson")

Reading a Dataset-JSON File

from odmlib.dataset_json_1_1 import DatasetJSON

# From JSON
ds = DatasetJSON.read_json("ae.json")
print(f"Dataset: {ds.name}, Records: {ds.records}")
print(f"Columns: {ds.column_names}")
for row in ds.rows:
    print(row)

# From NDJSON
ds = DatasetJSON.read_ndjson("ae.ndjson")

# From a JSON string
ds = DatasetJSON.from_json('{"datasetJSONVersion": "1.1.0", ...}')

Converting from Dataset-XML

Convert Dataset-XML 1.0.1 files to Dataset-JSON v1.1 (one file per dataset):

import odmlib.odm_loader as OL
import odmlib.loader as LD
import odmlib.ns_registry as NS
from odmlib.dataset_json_1_1.converter import dataset_xml_to_dataset_json

NS.NamespaceRegistry(prefix="odm", uri="http://www.cdisc.org/ns/odm/v1.3",
                     is_default=True, is_reset=True)
NS.NamespaceRegistry(prefix="data",
                     uri="http://www.cdisc.org/ns/Dataset-XML/v1.0")

loader = LD.ODMLoader(OL.XMLODMLoader(model_package="dataset_1_0_1",
                      ns_uri="http://www.cdisc.org/ns/Dataset-XML/v1.0"))
loader.open_odm_document("ae.xml")
odm = loader.root()

# Returns dict[str, DatasetJSON] — one per ItemGroupOID
datasets = dataset_xml_to_dataset_json(odm)
for name, ds in datasets.items():
    ds.write_json(f"{name.lower()}.json")

Flattening Define-XML v2.1 Metadata

Convert Define-XML v2.1 metadata into tabular Dataset-JSON datasets for analysis or round-tripping:

import odmlib.define_loader as DL
import odmlib.loader as LD
from odmlib.dataset_json_1_1.define_flattener import DefineFlattener

loader = LD.ODMLoader(DL.XMLDefineLoader(model_package='define_2_1'))
loader.open_odm_document('define.xml')
odm = loader.root()

flattener = DefineFlattener(odm)
datasets = flattener.flatten_all()  # dict of 11 metadata tables

# Write all to individual JSON files
flattener.write_all('/output/dir')

# Or work with individual datasets
variables = datasets['variables']
print(f"Total variables: {variables.records}")

The flattener produces 11 metadata tables:

  • study — Study-level metadata (1 row)

  • standards — Standard references

  • datasets — ItemGroupDef definitions

  • variables — Variable definitions (ItemRef + ItemDef)

  • value_level — Value-level metadata (ValueListDef)

  • where_clauses — Where clause conditions

  • methods — Computation methods

  • comments — Comment definitions

  • documents — External document references

  • codelists — CodeList definitions

  • codelist_terms — Individual coded values

Pandas Integration

Convert between DataFrames and Dataset-JSON (requires pandas):

from odmlib.dataframe import (
    dataset_json_to_dataframe,
    dataframe_to_dataset_json,
    define_metadata_to_dataframes,
)

# DatasetJSON → DataFrame
from odmlib.dataset_json_1_1 import DatasetJSON
ds = DatasetJSON.read_json("dm.json")
df = dataset_json_to_dataframe(ds)

# DataFrame → DatasetJSON
import pandas as pd
df = pd.DataFrame({"STUDYID": ["CDISC01"], "AGE": [65]})
ds = dataframe_to_dataset_json(df, "DM", "Demographics", "IG.DM")
ds.write_json("dm.json")

# Define-XML → DataFrames (11 metadata tables)
import odmlib.define_loader as DL
import odmlib.loader as LD
loader = LD.ODMLoader(DL.XMLDefineLoader(model_package='define_2_1'))
loader.open_odm_document('define.xml')
dfs = define_metadata_to_dataframes(loader.root())
print(dfs['variables'][['DatasetOID', 'Name', 'DataType']].head())