De PDOK JSON-aanleverstandaard is het voorkeursformaat voor aanleveringen van datasets aan PDOK.

De belangrijkste concepten van deze standaard zijn als volgt:

  • Basis van alles is een feature: een object uit de dataset, gecombineerd met velden die het proces aansturen.

  • De objectvelden in het feature, waaronder de geometrie, worden attributen genoemd. In de ideale situatie hebben features precies één geometrie en platte attributen. Nul of meerdere geometrieën en complexe attributen worden ondersteund, maar leiden zoals verderop beschreven mogelijk tot ander gedrag.

  • Een collection is een verzameling features van hetzelfde objecttype (bijv. pand). Over het algemeen zullen features van één collection dezelfde attribuutnamen hebben, maar hier zitten vooralsnog geen beperkingen op.

  • Van features wordt historie bijgehouden: ze kunnen niet alleen worden toegevoegd, maar ook gewijzigd, beëindigd of verwijderd.

Important
collection-namen en attribuutnamen zijn hoofdlettergevoelig, maar gebruik van twee collection-namen die zich enkel in hoofdlettergebruik onderscheiden, is momenteel nog niet mogelijk.

Aanlevering

De aanlevering geschiedt in één bestand:

{
    "_meta": {
        // Header met metadata. Voor toekomstig gebruik, momenteel niet gevuld.
    },
    "dataset": "dataset-identifier",
    "features" : [ feature objects ]
}
Important
De volgorde is hier belangrijk! features moet het laatste attribuut zijn.

Features

Features hebben een aantal verplichte velden, die herkenbaar zijn aan de voorloop-underscore (_):

Verplichte velden
_action

string: new, change, close of delete

_collection

string

_id

string, uniek in collection

_validity

date-time-string, mutatietijdstip: yyyy-MM-ddTHH:mm:ss.SSSZ (enkel bij new, change en close)

_current_validity

date-time-string, validity van vorige mutatie: yyyy-MM-ddTHH:mm:ss.SSSZ (enkel bij change, close en delete)

Daarnaast zijn er vrije velden (attributen).

Acties en historieopbouw

Zoals hierboven al vermeld, ondersteunt het aanleverformaat niet alleen het eenmalig aanmaken van features, maar ook het wijzigen, beëindigen en verwijderen ervan. Hierbij wordt historie opgebouwd, die voor gebruikers te raadplegen is via downloadservices. Elke mutatie (uitgevoerde actie op een feature) is voorzien van een mutatietijdstip (validity). Zo ontstaat per feature een tijdlijn, waarbij elke periode tussen twee mutatietijdstippen overeenkomt met één versie van het feature.

Na het initiële opvoeren van een feature wordt ter controle steeds het tijdstip van de voorafgaande mutatie meegestuurd (current validity). Zo kan gevalideerd worden dat er geen mutaties op het feature zijn gemist.

Voor het muteren van features zijn de volgende acties gedefinieerd:

  • new voegt de eerste versie van een feature toe. Er wordt gevalideerd dat er geen eerdere versie van dit feature bestaat.

  • change wijzigt een feature. Hierbij kan gekozen worden of er wel of geen historie opgebouwd dient te worden. Wordt een validity meegegeven die later is dan de current validity, dan wordt de momenteel actuele versie bewaard als historie en een nieuwe versie aan de tijdlijn toegevoegd. Dit kan gebruikt worden als er een vanaf een bepaalde ingangsdatum een nieuwe werkelijkheid is. De validity wordt gebruikt als overgangsdatum tussen de twee versies. Wordt een validity meegegeven die gelijk is aan de current validity, dan wordt de momenteel actuele versie overschreven zonder dat deze in de historie bewaard blijft. Dit kan gebruikt worden als er een technische correctie op het feature dient plaats te vinden, terwijl de werkelijkheid ongewijzigd is.

  • close beëindigt een feature. Dit houdt in dat de momenteel actuele versie bewaard wordt als historie, zonder dat er een nieuwe versie voor in de plaats komt. Dit kan gebruikt worden als het object in de werkelijkheid met een bepaalde ingangsdatum komt te vervallen.

  • delete verwijdert een feature volledig, inclusief alle historie. Dit kan gebruikt worden als er in de aanleveringen een fout gemaakt is die niet op een andere manier hersteld kan worden. Hierna kan hetzelfde feature indien gewenst opnieuw worden aangeboden middels een new.

Een voorbeeld om de acties te illustreren:

[{
    "_action": "new",
    "_collection": "historie-voorbeeld",
    "_id": "feature1",
    "_validity": "[t1]"
    "value": "foo"
},
{
    "_action": "change",
    "_collection": "historie-voorbeeld",
    "_id": "feature1",
    "_current_validity": "[t1]",
    "_validity": "[t2]"
    "value": "bar"
},
{
    "_action": "change",
    "_collection": "historie-voorbeeld",
    "_id": "feature1",
    "_current_validity": "[t2]",
    "_validity": "[t2]"
    "value": "baz"
},
{
    "_action": "change",
    "_collection": "historie-voorbeeld",
    "_id": "feature1",
    "_current_validity": "[t2]",
    "_validity": "[t3]"
    "value": "spam"
},
{
    "_action": "close",
    "_collection": "historie-voorbeeld",
    "_id": "feature1",
    "_current_validity": "[t3]",
    "_validity": "[t4]"
}]

Dit resulteert in de volgende tijdlijn:

       t1              t2              t3               t4
-------|---------------|---------------|----------------|-------->
   X       value=foo       value=baz       value=spam       X

Hierbij staat X voor: er is in deze periode geen versie van dit feature.

Tot slot kan het feature verwijderd worden met:

{
    "_action": "delete",
    "_id": "feature1",
    "_collection": "historie-voorbeeld",
    "_current_validity": "[t4]"
}

Attributen

De attributen (vrije velden) van een feature mogen simple types (string, numeriek, boolean) zijn, complex types (arrays of subobjecten), voorgedefinieerde functies of geometrieobjecten (in een van de ondersteunde formaten, zie verderop). Het type wordt bepaald op basis van het eerste voorkomen van een attribuut.

Complex types

Complex types kunnen bijvoorbeeld gebruikt worden als een feature subobjecten bevat. Een typisch voorbeeld is een pand dat een vlakgeometrie heeft, maar daarnaast één of meer nummeraanduidingen met eigen attributen en een puntgeometrie.

Bij het gebruik van complex types dient er rekening mee gehouden te worden dat deze voor de viewservices afgesplitst worden als aparte lagen. In het bovengenoemde voorbeeld zou een laag pand en een laag pand$nummeraanduiding ontstaan. Om deze reden zijn complex types in sommige delen van de verwerkingspijplijn duurder dan simple types en dienen ze dus alleen gebruikt te worden als ze daadwerkelijk een toegevoegde waarde hebben t.o.v. platte attributen.

Functies

Een functie kan gebruikt worden als een attribuut omgezet dient te worden naar een ander type dan string, numeriek of boolean. Het zijn dus in feite voorgedefinieerde types. Functies worden als volgt aangeroepen:

["~#functienaam", [param1, param2, ...]]

Op dit moment zijn de volgende functies beschikbaar:

Beschikbare functies
~#moment

date-time-string (yyyy-MM-ddTHH:mm:ss.SSSZ) → DateTime

~#date

date-string (yyyy-MM-dd) → LocalDate

~#int

Integer

~#boolean

Boolean

~#double

Double

~#geometry

geometrieobject (zie verderop)

De functies ~#int, ~#boolean en ~#double zijn er als alternatief voor de automatische detectie van het attribuuttype. Ze komen vooral van pas als voor een bepaald attribuut lege (null) waardes kunnen voorkomen, omdat het type dan niet automatisch bepaald kan worden. In het laatste geval kiest de automatische detectie voor string als er geen functie gebruikt wordt.

Voorbeeld:

{
    "getalEen": 15, // Integer
    "getalTwee": null, // String
    "getalDrie": ["~#int", null] // Integer
}

Geometrieën

Voor geometrieën worden de formaten GML en WKT ondersteund. Mogelijk wordt in de toekomst ondersteuning voor GeoJSON toegevoegd.

Dat het bij een attribuut om een geometrie gaat, kan op twee manieren aangegeven worden. Heet het attribuut _geometry, dan wordt dit automatisch als geometrie geïnterpreteerd. Heet het attribuut anders, dan dient bovengenoemde functie ~#geometry gebruikt te worden.

Voorbeelden:

"_geometry":{
    "type": "gml",
    "gml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
            <gml:Point xmlns:gml=\"http://www.opengis.net/gml\" srsName=\"urn:ogc:def:crs:EPSG::28992\">
                <gml:pos srsDimension=\"2\">154676.328 464046.743</gml:pos>
            </gml:Point>"
},
"andereGeometrie": ["~#geometry", [{
    "type": "wkt",
    "wkt": "LINESTRING (154676.328 464046.743, 154676.578 464046.743, 154674.285 464048.372)",
    "srid": 28992
}]]

Het veld srid is optioneel. Als het wordt weggelaten, wordt 28992 (Amersfoort / RD New) gebruikt.

Feature zonder geometrie

Een feature zonder geometrie wordt ook verwerkt. De data kan dan echter niet gevisualiseerd worden. Wel is deze zichtbaar in eventuele downloadservices. Voor de rest is een feature zonder geometrie hetzelfde als een feature met geometrie.