OCR to XML: parsing is only the first check
- Python
- XML
- data-quality
- research
Three different kinds of correctness
My research work at the University of Münster included processing and validating more than 1,700 pages of OCR output into conformant XML. The interesting part was not only generating XML, but knowing what each validation step actually proved. A useful way to reason about this kind of work is to separate three checks:
- Well-formedness: can an XML parser read the document?
- Conformance: does the document satisfy the required schema and project rules?
- Fidelity: does the text still represent the source material accurately?
Passing the first check does not imply passing the other two.
Let a serializer handle XML escaping
Building XML with string concatenation makes characters such as & and < easy to mishandle. A serializer handles their representation in XML text nodes.
This standalone illustration uses Python’s standard library; it is not code from the university project:
from xml.etree.ElementTree import Element, SubElement, tostring
document = Element("document")
page = SubElement(document, "page", {"number": "1"})
page.text = "Research & archives <catalogue>"
xml_bytes = tostring(
document,
encoding="utf-8",
xml_declaration=True,
)
print(xml_bytes.decode("utf-8"))
ElementTree provides parsing and serialization. It is not an XSD validation engine. If a project requires schema validation, use a validator appropriate to that schema as an additional step.
Preserve provenance
Keep a stable connection between an output document and its source page. Record transformations that materially change the text, and make ambiguous OCR corrections reviewable rather than silently guessing.
For example, a syntactically valid date can still be the wrong date because OCR confused a character. Structural validation helps define the allowed form; comparison with source material answers a different question.
Separate data checks from publication
For research publishing, Quarto distinguishes rendering from executing computations. Its freeze option can reuse prior computation results, so a successful site build should not be interpreted as proof that source data was reprocessed or revalidated.
Make it explicit which stage validates data, which stage renders it, and which artifacts are reused. That separation gives a reviewer a clearer account of what a successful build actually proves. In research tooling, the safest workflow is one where structural checks and source fidelity are visible as separate responsibilities.
Sources
- Python ElementTree for parsing, building, and serializing XML.
- Python XML security for handling untrusted XML.
- Quarto GitHub Pages publishing for rendering, CI, and frozen computations.
Technical references reviewed on 13 September 2026.
Related articles
LearningsData Engineering & Quality
Data tests should capture assumptions, not just failures
Write data quality checks around explicit assumptions so failures explain what changed and which downstream output is at risk.