Capturing, managing and exchanging data
How data gets in, how it is selected and managed, and how systems swap it as CSV, JSON and XML. The robot exports its own readings.
Do this lesson in the simulatorA database is only as good as the data that goes into it, and data rarely stays in one system. The class's run times are typed in by students, the robot's sensor readings arrive by themselves, the scoreboard reads them, and the competition organisers want the results in their own system. This lesson follows data through its life: how it is captured, selected, managed and exchanged. At GCSE (F7.1) you read and wrote CSV files; at A level you compare the standard formats and choose between them.
Capturing data
| Method | How the data gets in | Example |
|---|---|---|
| Manual entry from a form | a person types it, on paper or on screen | a student enters a run time |
| Optical character recognition (OCR) | software reads printed or handwritten text from an image | scanning a paper score sheet |
| Optical mark recognition (OMR) | a scanner detects marks in fixed positions | multiple-choice answer sheets |
| Barcodes and QR codes | a scanner reads a printed code | a label on each robot kit |
| RFID and NFC tags | a reader picks up a radio tag nearby, no line of sight needed | a robot's tag read as it enters the arena |
| Sensors and data loggers | readings taken automatically at intervals | the robot's distance sensor, ten times a second |
| Automatic capture from other systems | data produced as a side effect of another job | card payments, web server logs |
Choosing a method is a trade-off between accuracy, speed, cost and volume. Manual entry is cheap to set up but slow and error-prone; sensors capture huge volumes accurately but only of what they can measure.
Captured data should be checked on the way in. Validation checks that data is reasonable and follows the rules (a run time between 0 and 60 seconds, a date in the right format); it cannot tell whether the data is actually true. Verification checks that data matches its source, for example by typing it twice (double entry) or by reading it back to the person who gave it.
Selecting data
Selecting means choosing only the data that is relevant. At capture, a system should collect only what it needs: the less personal data it holds, the less there is to protect, and data protection law requires personal data to be limited to what is necessary for its purpose (F12.2). Later, queries select the records and fields a job needs, and a very large data set may be sampled, a smaller selection that represents the whole.
Managing data
A database management system (DBMS) is the software that manages the data for every program and user that needs it. It:
- stores, retrieves and updates data, hiding how it is physically stored, so programs do not depend on the file layout (data independence);
- keeps a data dictionary: data about the data, such as each table's fields, types, lengths, keys and validation rules;
- controls access, giving each user permission to see or change only certain tables or fields;
- enforces integrity: keys, referential integrity and constraints;
- controls concurrent access and transactions (lessons A11.6 and A11.7);
- takes backups and recovers the database after a failure.
Exchanging data
When two systems exchange data, both must agree on a format. There are three common text formats. Here are the same three sensor readings in each:
import csv, io, json
import xml.etree.ElementTree as ET
readings = [{"step": 0, "y": 0.0, "cm": 61.0},
{"step": 1, "y": 10.0, "cm": 51.0},
{"step": 2, "y": 20.0, "cm": 41.0}]
out = io.StringIO()
writer = csv.DictWriter(out, fieldnames=["step", "y", "cm"], lineterminator="\n")
writer.writeheader()
writer.writerows(readings)
as_csv = out.getvalue()
as_json = json.dumps(readings)
root = ET.Element("readings")
for r in readings:
ET.SubElement(root, "reading", {k: str(v) for k, v in r.items()})
as_xml = ET.tostring(root, encoding="unicode")
for name, text in [("CSV", as_csv), ("JSON", as_json), ("XML", as_xml)]:
print(f"{name}, {len(text)} characters:")
print(text)
print()
CSV (comma-separated values) is a table: a header line, then one line per record, fields separated by commas. It is compact and every spreadsheet opens it. But it has no data types (every value is text until the receiver converts it), no nesting, and a comma inside a value must be quoted.
JSON (JavaScript Object Notation) writes objects in braces, as name and value pairs, and arrays in square brackets. Values can be strings, numbers, true, false, null, or further objects and arrays, so data can be nested. It maps directly onto Python dictionaries and lists, which is why web APIs mostly use it.
XML (Extensible Markup Language) marks data up with named tags, <reading> and </reading>, which may carry attributes and contain further elements. It is self-describing and very widely supported, and an XML document can be checked against a schema that sets out exactly which elements and types are allowed. It is also the most verbose of the three.
The receiving side parses the text back into data:
import csv, io, json
import xml.etree.ElementTree as ET
as_csv = "step,y,cm\n0,0.0,61.0\n1,10.0,51.0\n"
as_json = '[{"step": 0, "y": 0.0, "cm": 61.0}, {"step": 1, "y": 10.0, "cm": 51.0}]'
as_xml = '<readings><reading step="0" y="0.0" cm="61.0" /><reading step="1" y="10.0" cm="51.0" /></readings>'
rows = list(csv.DictReader(io.StringIO(as_csv)))
print("CSV: ", rows[1], "cm is", type(rows[1]["cm"]).__name__)
data = json.loads(as_json)
print("JSON:", data[1], "cm is", type(data[1]["cm"]).__name__)
root = ET.fromstring(as_xml)
second = root.findall("reading")[1]
print("XML: ", second.attrib, "cm is", type(second.get("cm")).__name__)
Only JSON brings back a number as a number; CSV and XML attributes hand back text that the receiver must convert.
| CSV | JSON | XML | |
|---|---|---|---|
| Shape | one flat table | nested objects and arrays | nested elements with attributes |
| Data types | none, all text | strings, numbers, true/false, null | text, unless a schema defines types |
| Size | smallest | small | largest, every value is wrapped in tags |
| Human readability | easy for simple tables | easy | harder, because of the tags |
| Validation | none built in | JSON Schema exists, less used | schemas (XSD, DTD) widely used |
| Typical use | spreadsheets, data exports | web APIs, configuration | documents, older enterprise systems, office file formats |
Businesses exchanging orders and invoices between their systems also use EDI (electronic data interchange): agreed, standard formats for business documents, sent automatically from one organisation's system to another's with no person retyping them.
Task: three formats, one set of readings
The robot starts facing a wall. Take four readings, numbered step 0 to 3. For each: record step (a whole number), y (the second value of position(), rounded to 1 decimal place) and cm (the value of distance()), then drive forward 10 cm at speed 40 before the next reading (no drive after step 3).
Then, from that one list of readings:
- Write
readings.csv: the header linestep,y,cm, then one line per reading, such as1,10.0,51.0. - Write
readings.jsonwithjson.dump: a list of four objects, each with the keysstep,yandcm. - Read
readings.jsonback withjson.loadand printjson readings: <n>, the number of objects in it. - Print the readings as XML: a line
<readings>, then one line per reading exactly in the form<reading step="1" y="10.0" cm="51.0"/>(indenting is allowed), then</readings>.
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
import json
readings = []
Challenges
- Add a
secondsfield, the time of each reading fromclock(). Which of your three outputs needed changing, and how? - Nest the readings inside a JSON object that also records the robot's name and the date. Could CSV hold the same thing?
- A robot's name is
Ada, the second. What goes wrong in a CSV file written by hand, and how does thecsvmodule deal with it?