# Strukturerede data

## Hvad det er

På en kontaktside står der i en sætning, hvor kontoret ligger. Strukturerede
data siger det samme en gang til som en `PostalAddress` med gade, postnummer og
land, så et program, der læser siden, slipper for at gætte, hvilket ord der er
byen. Det er praksissen at gentage det, en side fortæller i prosa, som typede
udsagn i et ordforråd, som udgivere og modtagere er enige om, så søgemaskiner og
andre programmer kan læse fakta uden at tolke layoutet.

Ordforrådet er som regel schema.org, som Googles dokumentation nævner som det,
de fleste strukturerede data til dens søgning bruger. Google, Microsoft, Yahoo
og Yandex grundlagde det, og siden april 2015 har en W3C-fællesskabsgruppe været
dets vigtigste forum. Det definerer typer som `Organization`, `Person`,
`Service`, `Review` og `DefinedTerm` og de egenskaber, hver type kan have, for
eksempel `name`, `address`, `author` og `price`.

Udsagnene kan skrives i tre syntakser. Microdata og RDFa sætter attributter
direkte på de synlige HTML-elementer. JSON-LD holder udsagnene for sig, som en
blok JSON i et `script`-element af typen `application/ld+json`, og version 1.1
blev en W3C-anbefaling den 16. juli 2020. Google godtager alle tre på lige fod
og anbefaler JSON-LD som den letteste at vedligeholde i stor skala.

```html
<script type="application/ld+json">
    {
        "@context": "https://schema.org",
        "@type": "Organization",
        "@id": "https://example.com/#organization",
        "name": "Example ApS",
        "url": "https://example.com/"
    }
</script>
```

Den vigtigste linje i blokken er `@id`. JSON-LD bruger den til at identificere
en knude, og en knude uden den er anonym, i specifikationens sprog en blank
node, som intet uden for dens egen blok kan pege på. Med en identifikator kan
enhver anden blok på enhver anden side skrive
`"publisher": {"@id": "https://example.com/#organization"}`, og det kalder
specifikationen en knudereference: en henvisning til noget, der er beskrevet et
andet sted, i stedet for en ny beskrivelse af det. Det er identifikatorerne, der
gør en samling spredte blokke til én graf.

Nabobegrebet er metadata. Titlen, beskrivelsen og Open Graph-taggene i sidens
head beskriver siden som dokument, mens strukturerede data beskriver de ting,
siden handler om: virksomheden bag den, personen, der skrev den, ydelsen, den
tilbyder, eller ordet, den forklarer.

## Hvorfor det betyder noget

Beslutningen er, hvor meget der skal siges, og det ærlige svar er som regel
mindre, end ordforrådet tillader, men til gengæld fuldstændigt. Syntaksen
forhindrer ingen udgiver i at udfylde hver eneste egenskab, schema.org tilbyder.
Googles egen vejledning peger den anden vej: hellere færre anbefalede
egenskaber, fuldstændige og korrekte, end alle tænkelige med mangelfulde eller
forkerte data, og ingen markup af noget, læseren ikke kan se på siden, heller
ikke når det er sandt.

Grunden er, at hvert opmærket faktum er en kopi af noget, siden allerede siger,
og en kopi kan glide. En pris, der rettes i den synlige tabel og glemmes i
JSON'en, en bedømmelse, som kun maskiner får at se, en adresse, der er tastet
lidt forskelligt på hver side: alle tre får siden til at sige én ting til
mennesker og en anden til programmer. Omkostningen ved strukturerede data ligger
mindre i at skrive dem end i at holde dem sande, så de nyttige spørgsmål er,
hvilke udsagn siden kan stå inde for, og om de kommer fra samme kilde som den
synlige tekst.

Gevinsten er læselighed. En søgemaskine eller en agent, der kan samle hundrede
omtaler til én virksomhed, ved mere end en, der læser hundrede navne uden
forbindelse. Sider, der følger retningslinjerne, kan blive berettigede til rich
results, visninger med ekstra detaljer, men berettigelsen garanterer dem ikke.
Det, der ændrer sig, er, hvor godt en maskine forstår, hvad siden handler om.

## Sådan ser det ud i praksis

Sitets kolofon
[lover kun at markere det, der er sandt og synligt](/da/credits/), og historien
om dets strukturerede data viser, hvorfor den sætning skulle skrives ned.

Før omlægningen
[gentog 963 blokke virksomheden 1.671 gange uden en stabil identifikator](/da/portfolio/replaced-963-structured-data-blocks-with-one-graph-138/),
så en modtager havde intet grundlag for at regne organisationen på én side for
den samme som på en anden. Grafen hviler nu på tre identifikatorer udstedt ud
fra sitets origin, én til organisationen, én til websitet og én til
grundlæggeren, og alle andre blokke henviser til dem med `@id` i stedet for at
beskrive dem igen. Identifikatorerne er de samme på alle sprog: en kommentar i
skabelonen forklarer, at en særskilt dansk identifikator ville erklære en anden
organisation med samme CVR-nummer. Seksten typer er i brug, og lister nævner
deres elementer alene ved URL, for at skrive de 107 poster på
porteføljeoversigten helt ud ville have gjort den komprimerede side 52 %
tungere.

Flere fakta læses fra samme kilde som den synlige side. Priserne på ydelserne
kommer fra den samme datafil som priserne på skærmen, så en maskine og en læser
får oplyst samme takst. Den periode, et stykke arbejde dækker, kommer fra den
partial, der skriver sætningen om det. Brødkrummerne gengiver den sti, læseren
ser, og placeringerne i lister følger rækkefølgen på skærmen, aldrig en
rangordning, der kun udgives til maskiner. Sidens egen knude bruger samme
adresse som dens kanoniske link, så markuppen og head fremsætter én påstand.

Afvisningerne er lige så bevidste som udsagnene. Virksomhedens egne beskrivelser
af sit arbejde er ikke markeret som anmeldelser, for det ville opfinde en
forfatter til dens egne ord. Udtalelser fra navngivne personer er markeret som
anmeldelser, men uden bedømmelse, eftersom ingen har givet en. Hver side i
ordlisten, også denne, bærer en `DefinedTerm`, hvis beskrivelse er den korte
forklaring, der står i listen, så den definition, en maskine læser, er den
samme, som en læser ser.

Et tjek af det byggede site kræver, at hver blok kan parses, at hver
identifikator kan slås op, og at hver URL, grafen nævner, faktisk blev bygget,
så en graf, der peger på en side, som ikke findes, får gaten til at fejle. Samme
kolofon nævner Schema Markup Validator til at læse dataene og Googles Rich
Results Test til at se, hvad én søgemaskine gør med dem.

## Hvor det går galt

**Rich results udebliver, selv om alle validatorer godkender markuppen.**
Markuppen er gyldig JSON-LD og bruger rigtige schema.org-typer, men siden vises
fortsat som et almindeligt resultat. Dataene beskriver ting, læseren ikke kan
se, for eksempel en bedømmelse, som aldrig blev givet, spørgsmål, der er skjult
på siden, eller en pris, der afviger fra den på skærmen, og Google advarer om,
at markup, der bryder retningslinjerne, kan gøre en side uberettiget, hvor ren
syntaksen end er. Markér kun det, siden viser, og generér begge dele fra én
kilde, så de ikke kan skilles ad.

**Hundredvis af blokke beskriver én virksomhed, og intet binder dem sammen.**
Hver side gentager organisationens navn, logo og adresse, sommetider med små
forskelle, og en rettelse betyder, at alle forekomster skal findes. Knuderne er
anonyme, eller hver side og hvert sprog udsteder sin egen identifikator for den
samme enhed. Giv hver virkelig ting ét `@id` bygget af en stabil URL med et
fragment, beskriv den én gang, og henvis til den alle andre steder.

**Én skabelonændring ødelægger markuppen på alle sider på én gang.** Et
forvildet anførselstegn, et komma for meget eller en tom værdi gør hver blok
ugyldig, og modtagerne kan ikke bruge noget af den. Googles vejledning advarer
om, at skabeloner kan ødelægge markup efter udrulning. JSON'en blev sat sammen
som tekst med værdier klistret ind mellem klammer, så et manglende felt
efterlader en tom streng eller en ødelagt struktur. Byg udsagnet som en
datastruktur og serialisér den, sådan som sitets skabeloner gør med Hugos
`jsonify`, udelad egenskaber uden værdi i stedet for at udsende dem tomme, og
pars hver blok i det byggede output.

**Grafen nævner sider, der mangler.** URL'er i markuppen fører til en 404, en
staging-vært eller en spejlet kopi. Adresserne blev tastet i hånden eller bygget
efter en anden regel end linkene og den kanoniske URL. Udled hver URL i
markuppen fra den samme funktion, der giver sidens kanoniske adresse, og tjek,
at hver af dem blev bygget.

## Læs mere

- [schema.org](https://schema.org/) — det fælles ordforråd af typer og
  egenskaber med en side for hver type.
- [JSON-LD 1.1](https://www.w3.org/TR/json-ld11/) — W3C-anbefalingen for
  syntaksen, herunder knudeidentifikatorer og knudereferencer.
- [schema.org: DefinedTerm](https://schema.org/DefinedTerm) — den type, hver
  side i ordlisten bruger til at beskrive det ord, den forklarer.
- [Google Search Central: introduction to structured data](https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data)
  — de tre syntakser, reglen om synlighed, og hvordan rich results testes.
- [Schema Markup Validator](https://validator.schema.org/) — læser enhver sides
  strukturerede data op mod schema.org-ordforrådet.

<https://engineer.company/da/glossary/structured-data/>
