4 min read
Serialize and parse nested telemetry-like records with json vs xml.etree.ElementTree. This lab reports ops/s and payload bytes on Linux localhost — same schema, same record count.
Related links:
Lab honesty (1 Oct 2026 IST): Python 3.13.5. Affiliates: 0. Differentiates from configparser-vs-json (lab 104) and tomllib-vs-json (lab 112) — here the peer is XML ElementTree, not INI/TOML.
Verdict up front (n=2000 records): json.dumps ~673887 ops/s; xml build+tostring ~158580; json.loads ~1520987; xml fromstring+parse ~349700. Bytes: JSON 172948, XML 248299.
| Arm | Pattern |
|---|---|
json.dumps (compact) | encode list[dict] |
ElementTree build + tostring | encode equivalent XML |
json.loads | decode |
ET.fromstring + walk | decode to dicts |
| round-trip each | encode+decode |
Seven rounds, p50. Each record: id, host, latency_ms, ok, three tags.
Script: lab-evidence/124-xml-etree-vs-json/results/run_lab.py.
| Arm | ops/s |
|---|---|
| json.dumps | 673887 |
| xml build+tostring | 158580 |
| json.loads | 1520987 |
| xml fromstring+parse | 349700 |
| json round-trip | 676101 |
| xml round-trip | 106991 |
JSON wins every throughput column on this box. XML also grew the wire: 248299 bytes vs JSON 172948 (~1.44×).
Both paths returned 2000 / 2000 records; first id and last host matched across formats. The XML arm is a fair structural peer, not a toy one-liner.
Vendors, SOAP leftovers, and device configs still ship XML. The cost is real: round-trip XML sat at ~106991 ops/s vs JSON ~676101. Prefer JSON for new internal envelopes; keep ElementTree when the contract is XML and you cannot change it.
Document the chosen envelope in the runbook so on-call does not “normalize everything to XML” under incident pressure.
On this run, decode was the friendlier XML column (~349700 ops/s) but still trailed json.loads (~1520987 ops/s). Encode hurt more: ElementTree element allocation plus tostring sat near ~158580 ops/s against json.dumps ~673887. If your pipeline is write-heavy (agent flush), XML tax shows up first; if it is read-heavy (config ingest), budget the parse arm and the larger 248299-byte blob on the wire.
Prefer measuring your schema — attribute-heavy XML can swing these ratios. This lab keeps a fixed five-field record so ops/s stay comparable across arms.
Evidence: summary.json, summary.txt.
One Linux box, stdlib only (no lxml). Synthetic records, not a vendor WSDL corpus.
On 2000 nested records, json led encode (~673887 ops/s) and decode (~1520987), with a smaller payload (172948 vs 248299 bytes). Use ElementTree when the wire format is XML; prefer JSON for new internal telemetry.
Lab evidence
Lab 1 Oct 2026 IST. Python 3.13.5. n=2000: json.dumps 673887 ops/s; xml build 158580; json.loads 1520987; xml parse 349700. bytes json=172948 xml=248299. Affiliates: 0. Evidence: lab-evidence/124-xml-etree-vs-json/.
Hands-on platform.platform vs os.uname host inventory lab: real ops/s plus cache notes, measured on Linux localhost today in this hands-on lab for SREs.
Summary1 Oct 20264 min read
Hands-on uuid.uuid4 vs uuid.uuid1 ID generation lab: real ops/s plus version/node checks, measured on Linux localhost today in this hands-on lab for SREs.
Summary1 Oct 20263 min read
Hands-on cmath vs math.hypot magnitude ops lab: real ops/s for abs, polar, and phase, measured on Linux localhost today in this hands-on lab for SREs.
Summary1 Oct 20263 min read