TriplesMap Reference Page — Bidirectional JSON Schema ↔ Ontology Resource Browsing
Context and Problem Statement
ADR-0059
gave the RML mapping a website presence (/mapping), but at the level of
aggregate counts and prose (158 rr:TriplesMap rules, a coverage
percentage, the engineering approach). It does not let a reader inspect
the actual rules, nor browse the correspondence in either direction —
“what does this ontology term map to in the schema” or “what does this
schema path map to in the ontology” both require opening
mapping/opda-pdtf.rml.ttl directly (3,314 lines) and reading Turtle.
This ADR records the design for a TriplesMap reference page that documents the 158 rules themselves and exposes the bidirectional correspondence as two browsable indices, plus the concrete data-extraction approach and a real data-quality finding surfaced while building it.
A data-quality finding that shapes the design: the mapping file
contains 526 total rr:predicateObjectMap triples, but only 438 of them
belong to subjects actually asserted a rr:TriplesMap — the remaining 88
are nested inside 31 fnml:functionValue blocks (the FNML function-call
pattern ADR-0057 documents for enum→SKOS slugification and date
truncation). These 88 bind a function’s name and parameters, not a
JSON-Schema↔ontology correspondence, and must not be counted as
mapping rules. The live count on the existing /mapping overview page
(added under ADR-0059) currently reports a flat “526 predicateObjectMap
entries,” which conflates the two — this ADR also corrects that.
Decision Drivers
- Toolchain purity: RDF parsing must go through Apache Jena
(
arq/riot), neverrdfliborpyshacl, per ADR-0037 — this is binding even though the pre-existingharness/build_provenance_index.py(which builds the other tracked index,provenance-index.json) itself usesrdflibdirectly, a pre-existing inconsistency this ADR does not fix but also must not repeat. - Never wire a live build-time Astro read to a gitignored path — the
source/03-standards/rml/build/directory is.gitignored harness output (established the hard way in ADR-0059’s own drafting); any new generated artefact this feature needs must be committed to git, not left to regenerate silently missing in CI. - Reuse over reinvent: the site already has a proven, generic client-side
table component (
OPDA.DataBrowser,public/ui/data-browser.js) doing search/facet/sort/paginate at data-dictionary’s 8,458-row scale — a new bespoke table widget would be unjustified duplication. - Honesty about what a number counts — the FNML-vs-real-TriplesMap distinction above must be visible in the new content, not smoothed over.
Considered Options
- Option A (chosen) — One new page,
/mapping/triplesmaps, with three views over one committed, Jena-arq-generated JSON index: a static, M-section-grouped reference of all 158 TriplesMaps (the primary “document the triplesmaps” ask), plus twoOPDA.DataBrowser-powered flat indices — by ontology resource and by JSON Schema path — giving both directions of lookup. - Option B — Three separate pages (
/mapping/triplesmaps,/mapping/by-resource,/mapping/by-schema-path). Rejected: the three views share one dataset and one sidebar group (“The RML mapping”, currently 3 items); a 4th nav entry fits that group’s shape better than 6, and the existing/ontology//schema//modellingpages already establish the convention of one page with multiple<h2>sections and shared right-hand page navigation for related content at this scale. - Option C — Parse the raw
.rml.ttltext directly in Astro frontmatter (regex over the file), no generated JSON artefact. Rejected: 158 nested Turtle blocks with bracket/quote-containing JSONPath filters (e.g.[?(@.role=="Buyer")]) are not reliably regex-parseable; a real RDF parse (Jena) is required for correctness, and Astro frontmatter is the wrong place to shell out to a JVM on every dev-server request — the extraction belongs in a committed, versioned artefact regenerated deliberately, matching every other generated dataset in this codebase (ontology-model.json,provenance-index.json, the ADR/ODR registries). - Option D — Use
rdflibfor the new extractor, matchingbuild_provenance_index.py’s existing (if non-compliant) precedent. Rejected: that script’srdflibusage is itself a pre-existing violation of ADR-0037, not a sanctioned pattern to extend. The authoritative precedent is the ADR plus the other three harness scripts (jena_query.py,validate_provenance.py,audit_dct_source.py) that already comply — confirmed directly via a live SPARQL probe that Jenaarqextracts every field needed (iterator, subject template, asserted class, predicate, reference/template/constant) without rdflib.
Decision Outcome
Chosen option: “One new page, three views, one Jena-arq-generated committed index” (Option A), because it satisfies both parts of the request (document the rules; browse both directions) without fragmenting navigation, reuses proven components/toolchain rather than inventing new ones, and corrects a real, verified data-conflation issue found while designing it.
New generated artefact — source/03-standards/rml/harness/build_triplesmap_index.py:
- Uses the same Jena
arqsubprocess pattern asharness/jena_query.py(sparql_select()), queryingmapping/opda-pdtf.rml.ttlfor everyrr:TriplesMap’srml:iterator,rr:subjectMaptemplate and assertedrr:class(es), and everyrr:predicateObjectMapwhose owning subject is itself asserteda rr:TriplesMap(excluding the 88 FNML-internal ones) —rr:predicateplusrml:reference/rr:template/rr:constanton the object map. - A separate, lightweight text scan (not an RDF parse — Turtle
comments are invisible to any RDF parser, so this is necessarily
string-based) attaches each TriplesMap’s nearest preceding
# M<N>section-comment label, verified against the file’s actual structure (every<#Name> a rr:TriplesMapline is preceded by exactly one such banner, confirmed by direct inspection of the M1/M2 regions). - FNML call sites (31, accounting for the 88 excluded predicateObjectMaps) are counted and recorded separately, not folded into the main rows.
- Output:
source/03-standards/rml/triplesmap-index.json— committed to git (sibling to the already-trackedprovenance-index.json, not under the gitignoredbuild/). A newmake triplesmap-indextarget regenerates it.
New page — src/pages/mapping/triplesmaps.astro, added as the 2nd
item (after “How it works”) in the existing “The RML mapping” sidebar
group in src/lib/site.ts:
- By TriplesMap (primary reference, static/server-rendered) — all 158 rules grouped by M-section, each showing its iterator, asserted class(es), and predicate→JSON-path rows. A callout states the 438-vs-526 distinction and the 31 FNML call sites plainly, rather than a bare aggregate count.
- By ontology resource (
OPDA.DataBrowser) — one row per distinct class/property touched, with its kind, the TriplesMap(s) asserting or populating it, and the JSON path(s) reached. - By JSON Schema path (
OPDA.DataBrowser) — one row per distinct JSON path referenced, with the TriplesMap(s) and ontology term(s) it feeds.
Both derived indices (2 and 3) are computed from the one committed JSON in Astro frontmatter at build time (plain array grouping, no new generator logic needed) — the generated artefact stays minimal and canonical; the two “views” are pure, deterministic projections.
Correction to the existing /mapping overview — its stat table’s
flat “526 rr:predicateObjectMap entries” row is split into the
438-real / 88-FNML breakdown, with a link into the new page.
Consequences
- Good, because a reader can now inspect any of the 158 rules directly, and look up the mapping correspondence starting from either side (an ontology term or a schema path) without opening the raw Turtle file.
- Good, because the FNML/real-TriplesMap conflation is caught and corrected before it propagates into more pages, rather than being silently repeated.
- Good, because the new extractor stays within the binding Jena-only toolchain rule, rather than extending the one non-compliant precedent already in the codebase.
- Bad, because this adds a second generated, committed JSON artefact
under
source/03-standards/rml/(alongsideprovenance-index.json) that a future contributor must remember to regenerate (make triplesmap-index) after editing the mapping file — no drift-check CI gate is added for it in this pass (scope-limited to documentation, matchingprovenance-index.json’s own un-gated precedent). - Neutral, because the M-section label attachment is a text-scan convenience layer, not part of the RDF graph — it is documentary only, same status as the mapping file’s own inline comments.
Confirmation
make triplesmap-indexregeneratestriplesmap-index.jsonfrom the current mapping file; the JSON’s owngenerated_from.sha256pins the source file’s hash, mirroringprovenance-index.json’s existing convention.make build-datasucceeds with the new/mapping/triplesmapsroute;make teststays green.- The rendered page shows all 158 TriplesMaps grouped by M-section, and
both
OPDA.DataBrowserinstances load, search, and paginate correctly. /mapping’s stat table shows the 438/88 breakdown, not a bare 526.
More Information
- ADR-0059 —
the parent decision this page extends (the
/mappingsection itself). - ADR-0057 — the RML mapping’s own engineering record, including the FNML function-value pattern this ADR’s extractor must exclude from its primary rule count.
- ADR-0037 —
the binding Jena-only toolchain rule this ADR’s extractor follows (and
harness/build_provenance_index.pydoes not — a pre-existing gap noted here, not remediated by this ADR). - ODR-0035 — the policy decision establishing RML as the bidirectional trace this page makes browsable.
public/ui/data-browser.js— the reused table component, already proven at 8,458-row scale on/modelling/data-dictionary.
Comments
Loading comments…
Sign in to post a comment