diff --git a/dtd/check_dtd.py b/dtd/check_dtd.py new file mode 100644 index 0000000..3c1c678 --- /dev/null +++ b/dtd/check_dtd.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python +"""Check mews-0.1.dtd against the XHTML Mobile 1.2 driver and the spec. + +The Mews DTD is maintained by hand. It cannot be generated by stripping +xhtml-mobile12.dtd: that file is a driver which declares no elements (the +declarations live in the W3C and OMA module files it points to), DTD +attribute lists only ever add, a re-declared element is an error rather +than an override, and the rules that define Mews (the head model of +SPEC.md 3.3, the body variant classes of 5.3, the ban on nested tables +of 4.2, and lang and dir) do not exist in XHTML-MP to be kept. + +This script verifies what the driver and the spec can check: + +- the driver is the expected XHTML Mobile 1.2 driver, with event + attributes included and bidi ignored, so lang and dir are Mews + extensions (SPEC.md 3); +- the DTD declares exactly the elements SPEC.md 4.1 permits; +- the DTD keeps the driver's pre content model verbatim; +- the DTD keeps the li value and ol start attributes the driver adds. + +Run with: uv run check_dtd.py +""" + +import re +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parent +DRIVER_PATH = ROOT / "xhtml-mobile12.dtd" +DTD_PATH = ROOT / "mews-0.1.dtd" + +DRIVER_FPI = "-//OMA//DTD XHTML Mobile 1.2//EN" + +# The Mews element set (SPEC.md 4.1). +KEPT_ELEMENTS = ( + "html head title body " + "h1 h2 h3 h4 h5 h6 " + "p blockquote pre address hr " + "em strong b i code kbd samp var q cite abbr dfn br " + "a " + "ul ol li dl dt dd " + "table caption tr th td " + "img " + "form fieldset label input select option optgroup textarea " + "meta link" +).split() + + +def entity(text, name): + match = re.search(r"', text, re.DOTALL) + return re.sub(r"\s+", " ", match.group(1)) if match else None + + +def attlist(text, element): + match = re.search(r"", text, re.DOTALL) + return match.group(1) if match else None + + +def main(): + driver = DRIVER_PATH.read_text(encoding="utf-8") + dtd = DTD_PATH.read_text(encoding="utf-8") + errors = [] + + def check(condition, message): + if not condition: + errors.append(message) + + check(entity(driver, "XHTML.version") == DRIVER_FPI, "driver is not XHTML Mobile 1.2") + check( + entity(driver, "xhtml-events.module") == "INCLUDE", + "driver must include event attributes; Mews drops them", + ) + check( + entity(driver, "XHTML.bidi") == "IGNORE", + "driver must ignore bidi, so dir is a Mews extension", + ) + + declared = set(re.findall(r"