Nordens historia (poster, in Swedish) · Source check · Identifiers · SPARQL

The linked data behind the poster

A poster is a picture. The facts behind it should be possible to look up, check and reuse. This page explains how the timeline Nordens historia is published as linked data, what we learned on the way, and what comes next. The poster and the other pages are in Swedish; this page is in English.

102periods, events and milestones, each with its own identifier
207checked statements, each with a source
66period boundaries as stated by a source
72items linked to Wikidata

Background

The poster is a Nordic version of Timeline of World History by Chart Origin, shared on LinkedIn. The idea and the form are theirs. The content is my own selection: 70 periods, 6 cross-border events and 26 milestones in six columns, Iceland, Denmark, Norway, Sweden, Finland and Sápmi.

I made it together with Claude. The first version was written from general knowledge, without sources. Then every statement on the poster was checked against a reference source by AI agents with web search. After that, every item got a persistent identifier and was described as linked data.

What the data showed

The source check gave 166 confirmed and 41 disputed statements, and no statement that was simply wrong. The disputed ones are almost all period boundaries: 34 of the 65 checked boundaries do not match what the source says. The Swedish, Danish and Norwegian reference works do not draw the lines in the same places. The Viking Age ends in 1066 in English convention, but around 1050 in the Nordic reference works. Finnish prehistory has its own chronology, where the Iron Age continues through the Viking and Crusade periods.

This is a typical linked data experience. When the data has to be explicit, the fine details come up early, at the data level, instead of being handled later in software or hidden in footnotes. A period boundary is not a fact. It is a choice made by someone, in a source.

So the model now says exactly that. The poster has its own boundaries, as one choice among others. Each source's boundary is a separate definition: 66 definitions for 66 of the 70 periods. 39 of them agree with the poster and 27 differ. Three boundaries were confirmed by the source and then moved by me afterwards, to make the poster consistent. The data shows this openly:

Identifiers

Every item has an identifier under https://kerfors.github.io/sidospar/nordens-historia/id/.

The model

The model reuses existing vocabularies. Each one does the job it was made for.

WhatVocabularyWhy
Periods and eventsCIDOC-CRM: E4_Period, E5_Event, time-span with P82a/P82b, place with P7_took_place_at The cultural heritage standard for things that happen in time and space.
The poster's periodisationSKOS: each period is a concept in the poster's own scheme A periodisation is a classification of time. The scheme carries the poster's choice and its creator.
Sources' boundariesSKOS in the style of PeriodO: one definition per source, in a scheme per source, matched to the poster's period with skos:exactMatch or skos:closeMatch PeriodO's insight: a period is a definition made by an authority, not a fact. Conflicting boundaries are data.
Checked statementsschema.org: Claim and ClaimReview with verdict, evidence and source. Each claim has a kind (dcterms:type), a concept in a small SKOS scheme: a period's name and boundaries, a detail in a period's description, an event, or a milestone The vocabulary made for fact checking. Readable by search engines too.
ProvenancePROV-O: each review is generated by the source check (an activity by AI agents on my behalf) and derived from its source. Each definition is derived from its review. The chain from source to data is explicit and can be followed.
Relations between itemsOWL-Time intervalMeets (71) and CIDOC-CRM P10_falls_within (39) Derived from the poster at build time: which period follows which in the same column, and which events happen during which period.
Links outWikidata: skos:exactMatch, skos:closeMatch, and schema:about for milestones A milestone is an event, for example the founding of Uppsala University in 1477. Wikidata has the university, not the founding, so the link says "about", not "same as".

The chain for one period boundary:

SourceStatens historiska museerderived from → ReviewClaimReview: "omdiskuterad"derived from → DefinitionVikingatid 793–1050, per the museumexactMatch → PeriodVikingatid, Sverige, on the posterexactMatch → WikidataViking Age Sweden

As it is in the data (JSON-LD, shortened to these three nodes):

[
 {
  "@id": "nh:nh-p0030",
  "@type": [
   "crm:E4_Period",
   "skos:Concept"
  ],
  "name": "Vikingatid",
  "skos:inScheme": "nh:#perioder",
  "crm:P4_has_time-span": {
   "@type": "crm:E52_Time-Span",
   "crm:P82a_begin_of_the_begin": "0793",
   "crm:P82b_end_of_the_end": "1050"
  },
  "crm:P7_took_place_at": [
   "wd:Q34"
  ],
  "skos:exactMatch": "wd:Q10685826",
  "time:intervalMeets": [
   "nh:nh-p0031"
  ],
  "time:intervalMetBy": [
   "nh:nh-p0059"
  ]
 },
 {
  "@id": "nh:nh-p0030#def-029",
  "@type": [
   "crm:E4_Period",
   "skos:Concept"
  ],
  "dcterms:identifier": "def-029",
  "skos:prefLabel": {
   "sv": "Vikingatid enligt Statens historiska museer"
  },
  "skos:inScheme": "nh:#kalla-historiska",
  "skos:exactMatch": "nh:nh-p0030",
  "crm:P4_has_time-span": {
   "@type": "crm:E52_Time-Span",
   "crm:P82a_begin_of_the_begin": "0793",
   "crm:P82b_end_of_the_end": "1050"
  },
  "dcterms:spatial": [
   "wd:Q34"
  ],
  "dcterms:source": "https://historiska.se/utforska-historien/tidsaldrar/",
  "prov:wasDerivedFrom": "nh:nh-c0073#granskning",
  "skos:scopeNote": {
   "sv": "Källans formulering: vikingatid 793–1050"
  }
 },
 {
  "@id": "nh:nh-c0073#granskning",
  "@type": [
   "ClaimReview",
   "prov:Entity"
  ],
  "itemReviewed": "nh:nh-c0073",
  "reviewRating": {
   "@type": "Rating",
   "alternateName": "omdiskuterad"
  },
  "reviewBody": "Historiska museet anger vikingatid 793–1050; NE anger ca 800–1050. Ingen svensk källa använder 1066 som slut.",
  "datePublished": "2026-10-18",
  "prov:wasGeneratedBy": "nh:#kontroll-2026-10-18",
  "citation": {
   "@id": "https://historiska.se/utforska-historien/tidsaldrar/",
   "name": "Statens historiska museer – Tidsåldrar"
  },
  "prov:wasDerivedFrom": "https://historiska.se/utforska-historien/tidsaldrar/",
  "schema:correction": "793 – 1050",
  "schema:comment": {
   "@type": "Comment",
   "text": "Åtgärd på affischen: Slut ändrat till 1050."
  }
 }
]

A second check, against the archives

The first check used reference works: encyclopaedias and museum pages, sources that summarise other sources. For 15 statements about Swedish persons and medieval documents, a second check went one step closer to the sources, to two registers at Riksarkivet, the Swedish National Archives: Svenskt biografiskt lexikon (SBL) and Diplomatarium Suecanum (SDHK), the register of medieval Swedish charters. They were reached through Riksarkivet's MCP service (beta), which lets an AI agent search the registers directly. The check cites 12 SBL articles and 9 SDHK charters.

12 statements were confirmed and 3 could not be checked, because the service gives SBL's summary and bibliography, not the full biography. No statement was contradicted. But the registers add details the reference works leave out:

It is the same lesson as with the period boundaries, one level down: a date can also be a choice, made by an editor. In the data, the second check is its own ClaimReview next to the first, generated by its own PROV activity that used (prov:used) the MCP service, and derived from the register entries it cites. The first review is unchanged.

Turtle and SPARQL

The same graph is published in two serialisations. JSON-LD is the source: the build writes it, and it is embedded in every page. Turtle is generated from the JSON-LD with rdflib, and the build checks that the two give the same graph. The check is graph isomorphism, not text comparison, because the time-spans and ratings are blank nodes. Every item page shows both formats side by side.

The SPARQL page loads id/index.ttl into Oxigraph, a SPARQL engine compiled to WebAssembly, in the browser. There is no server. The page has 9 example queries, for example the disputed boundaries in Finland, periods without a Wikidata link, and the sources' boundaries for the Viking Age. The build runs every example query with rdflib and fails if one returns no rows.

How it was made, and the limits

Data and code

Next steps

Kerstin Forsberg, October 2026.