I don’t know about you, but I find it frustrating to try and get complex JSON or d right when trying to build it “by hand”. There are just too many things that can go wrong: forgotten commas, unbalanced brackets, and so forth. Fortunately, JSON (we’ll focus on JSON here) is a fundamentally simple format. Objects consist of key/value pairs where the keys are always strings, and the values are one of:
- a string
- a number
- the special values true, false or null
- another object
- an array consisting of items of any of these types (including this one)
This translates very naturally into Python, where dictionaries and lists are basic data types. To illustrate, let’s take a relatively simple FHIR resource, a condition:
{ "resourceType": "Condition", "id": "example", "patient": { "reference": "Patient/1234" }, "encounter": { "reference": "Encounter/67890" }, "dateRecorded": "2016-04-01T13:00", "code": { "coding": [ { "display": "Type 1 Diabetes Mellitus with Hyperglycemia", "code": "E10.65", "system": "http://hl7.org/fhir/sid/icd-10-us" } ] }, "clinicalStatus": "active", "verificationStatus": "provisional" }
This can be represented in Python easily enough:
problem['resourceType'] = 'Condition' problem['id'] = 'example' problem['patient'] = {'reference': 'Patient/1234'} problem['encounter'] = {'reference': 'Encounter/67890'} problem['dateRecorded'] = '2016-04-01T13:00' problem['code'] = {'coding': [{'system': 'http://hl7.org/fhir/sid/icd-10-us', 'code': 'E10.65', 'display': 'Type 1 Diabetes Mellitus with Hyperglycemia'}]} problem['clinicalStatus'] = "active" problem['verificationStatus'] = 'provisional'
(The choice of diabetes mellitus is purely arbitrary. I needed an example of an ICD-10 code for this example, and that’s what I chose.)
Now, how can we turn this into JSON? As you might expect, there is a json module we can use. All we have to do is pass the problem dictionary to json.dump
json.dump(problem, io, indent=2)
Of course, we have to get our hands on io somehow. We might want to write to an external file, but for the sake of simplicity, let’s write to a string
io = StringIO() json.dump(problem, io, indent=2) print(io.getvalue())
Of course, we need to import StringIO to do this!
So far so good. When we run the program we have so far, we get
{ "id": "example", "patient": { "reference": "Patient/1234" }, "clinicalStatus": "active", "encounter": { "reference": "Encounter/67890" }, "code": { "coding": [ { "system": "http://hl7.org/fhir/sid/icd-10-us", "code": "E10.65", "display": "Type 1 Diabetes Mellitus with Hyperglycemia" } ] }, "dateRecorded": "2016-04-01T13:00", "resourceType": "Condition", "verificationStatus": "provisional" }
Notice that the output order is all mixed up. This is to be expected, because there is no inherent ordering in dictionaries under iteration. Not only is this hard to read, it is actually contrary to the ITS specification, which requires that they be kept in order. What we need is a dictionary that follows its insertion order.Fortunately, such a thing exists: OrderedDict in the collection module. Puttting this all together, we have
import json from collections import OrderedDict from io import StringIO problem = OrderedDict() problem['resourceType'] = 'Condition' problem['id'] = 'example' problem['patient'] = {'reference': 'Patient/1234'} problem['encounter'] = {'reference': 'Encounter/67890'} problem['dateRecorded'] = '2016-04-01T13:00' problem['code'] = {'coding': [{'system': 'http://hl7.org/fhir/sid/icd-10-us', 'code': 'E10.65', 'display': 'Type 1 Diabetes Mellitus with Hyperglycemia'}]} problem['clinicalStatus'] = "active" problem['verificationStatus'] = 'provisional' io = StringIO() json.dump(problem, io, indent=2) print(io.getvalue())
And the output is (unfortunately, the indentation was lost when I pasted it into the editor):
{ "resourceType": "Condition", "id": "example", "patient": { "reference": "Patient/1234" }, "encounter": { "reference": "Encounter/67890" }, "dateRecorded": "2016-04-01T13:00", "code": { "coding": [ { "system": "http://hl7.org/fhir/sid/icd-10-us", "code": "E10.65", "display": "Type 1 Diabetes Mellitus with Hyperglycemia" } ] }, "clinicalStatus": "active", "verificationStatus": "provisional" }
Much better.