sdc-gdr2fhir
Governed Data Records as HL7 FHIR R4 Bundles. A target mapper for sdc-mapper: the core validates the record, resolves every value against its model and reports each one; this package says which FHIR resource and element each value goes in and writes the Bundle. Outbound only. Apache 2.0.
Status: 4.0.1. Models so far, from the FAIR Data Demo:
| Model | ct_id | Resources | Rules |
|---|---|---|---|
| NHANES Participant | xy8upneajsb8vdcmnve01g6g |
Patient, Observation, QuestionnaireResponse | 112 |
| NHANES Medication | epbdfmvxc3gbh5f66hhb3o2m |
Patient, MedicationStatement, QuestionnaireResponse | 18 |
Use
from sdc_mapper import Engine, load_mapping
from sdc_gdr2fhir import FHIRMapper, mapping_path
result = Engine().map_record(xml, FHIRMapper(), load_mapping(mapping_path("xy8upneajsb8vdcmnve01g6g")))
result.files["Bundle.json"] # a FHIR R4 Bundle of type collection
result.report # every value: lookup, declared or not representable; every Exceptional Value
Through sdc-mapper's CLI and MCP server the mapper is the target fhir.
The target
HL7 FHIR Release 4 (4.0.1), JSON. The specification is © HL7 and licensed under Creative Commons "No Rights
Reserved" (CC0); its terms allow redistribution and implementation-related products, so long as no one claims HL7's
endorsement and no altered specification is published as FHIR. HL7® and FHIR® are HL7's trademarks. This package
carries the FHIR R4 JSON schema unmodified (see NOTICE) and ships no terminology: LOINC, SNOMED CT, ICD-10-CM and NCI
Thesaurus codes appear only as the models bind them and the records carry them.
Every Bundle this package writes is valid against the FHIR R4 JSON schema, resource by resource and as a Bundle, or is
not written. The schema checks structure, types, required members and code patterns; it does not check FHIR's
invariants or terminology bindings. tests/ runs the HL7 FHIR validator (validator_cli.jar) too, where Java and the
validator are installed (FHIR_VALIDATOR_JAR); it has not been run for this version.
Where values go
Each record is one Bundle of type collection, identified by the record's instance id
(https://semanticdatacharter.com/ns/sdc4/instance). Entry ids and urn:uuid fullUrls are derived from the instance
id, so the same record gives the same bytes.
- Patient: the respondent sequence number as an identifier, and the administrative gender.
- Observation: each blood pressure reading (the vital signs blood pressure panel, LOINC 85354-9, with systolic and diastolic as components, body site and status), the heart rate and each laboratory result, with the LOINC code the model binds and UCUM units; smoking status, with the model's LOINC code and the answer's LOINC answer code; each chronic condition indicator, with the SNOMED CT concept the model names as its subject and the Yes or No answer's LOINC answer code. A condition indicator is the answer to "has a doctor ever told you", so it is an Observation of the answer, not a Condition.
- MedicationStatement: the NHANES generic drug code and name, the ICD-10-CM reasons, and the status from "taken in the past month" (Yes is active, No not-taken).
- QuestionnaireResponse: every other survey answer, an item each, linkId the component's identifier and text its label; a Coding where the model binds each of the answer's values to its own code, else the answer as recorded.
Lookup or declared. Where the model binds the code FHIR needs (a laboratory result's LOINC code, a condition's
SNOMED CT subject, an answer's LOINC answer code, an administrative gender, an observation status), the code written
is the model's own and the value is a lookup; tools/build_mapping.py copies those bindings from the model into
the mapping file, and the mapper checks at run time that the code it writes is one the model binds. Which resource and
element a value goes in is declared, one mapping file per model.
For the 200 sample records of each model:
| Model | lookup | declared | not representable |
|---|---|---|---|
| NHANES Participant | 9,093 (65.8% of the data values) | 4,733 | 5,400 (provenance and audit) |
| NHANES Medication | 0 | 1,591 (100% of the data values) | 5,400 (provenance and audit) |
The medication model binds its ICD-10-CM and drug code components to their code systems, not each value to a code, so its codes are written as the record holds them: declared.
Exceptional Values: every one preserved
FHIR is the target that can say what an Exceptional Value says. Where the data-absent-reason code system
(http://terminology.hl7.org/CodeSystem/data-absent-reason) has the concept, an Observation's (or component's) value
is replaced by dataAbsentReason, and any other element carries the data-absent-reason extension. The null flavors
data-absent-reason has no concept for are written exactly from v3 NullFlavor
(http://terminology.hl7.org/CodeSystem/v3-NullFlavor), as the iso21090-nullFlavor extension on the element or a v3
NullFlavor coding of dataAbsentReason (whose binding is extensible). v3 NullFlavor has no Asked and Refused;
data-absent-reason does.
| ISO 21090 | Written as | Class |
|---|---|---|
| UNK | data-absent-reason unknown |
preserved |
| ASKU | data-absent-reason asked-unknown |
preserved |
| NAV | data-absent-reason temp-unknown |
preserved |
| NASK | data-absent-reason not-asked |
preserved |
| ASKR | data-absent-reason asked-declined |
preserved |
| MSK | data-absent-reason masked |
preserved |
| NA | data-absent-reason not-applicable |
preserved |
| NINF | data-absent-reason negative-infinity |
preserved |
| PINF | data-absent-reason positive-infinity |
preserved |
| NI, INV, DER, OTH, UNC, QS, TRC | v3 NullFlavor, the same code | preserved |
A mapping file cannot change this table.
What FHIR cannot hold here
- The record's provenance and audit. FHIR's Provenance and AuditEvent require a recorded instant with a time zone, and the FAIR Data Demo records' times carry none; the PROV and audit values are reported as not representable, with that reason.
- Times without a time zone. FHIR's dateTime requires a time zone with a time; an observation's date and time is written as its date.
- Validity windows and recording times (act, vtb, vte, tr), and the definitions each component is bound to beyond the codes written.
Tests
pip install -e ".[dev]"
python -m pytest
Every sample record is mapped and each resource validated against the FHIR R4 JSON schema; Bundles are byte-stable; lookups, Exceptional Values and refused mappings are exercised.
Metadata
Release files for sdc-gdr2fhir 4.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| sdc_gdr2fhir-4.0.1.tar.gz | 319.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sdc_gdr2fhir-4.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 641.2 kB
Release files / sdc_gdr2fhir-4.0.1.tar.gz
| Download URL | sdc_gdr2fhir-4.0.1.tar.gz |
|---|---|
| Size | 319.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e30f02a865d3acc3f609c98a4c75c1da0a027b2554d8c7b3aa7bad1470fa76a4
|
|
BLAKE2b-256 checksum How to use checksums |
75dc63345d4132d6fec0d644a0ef7b46a773e8495d2aa0e7b11b9e8eca4808bc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logRelease files / sdc_gdr2fhir-4.0.1-py3-none-any.whl
| Download URL | sdc_gdr2fhir-4.0.1-py3-none-any.whl |
|---|---|
| Size | 322.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
feef11bf91f8965fc450a33012643430280a08c425bd69d217c45065852b6fab
|
|
BLAKE2b-256 checksum How to use checksums |
f2a5b2e433b5152b4f5ae2eb5f30226c7604d18443b6f08b47e07c78a6ee57d8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logSecurity for sdc-gdr2fhir 4.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for sdc_gdr2fhir-4.0.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.