In this tutorial, we will a create a simple data snippet, which represents a building, in accordance with the OSLO Application Profile (AP) "Building registry". In the next tutorial, We will ingest this snippet in a context broker.
On https://data.vlaanderen.be, all available vocabularies and APs that are governed by the Flemish government are listed:
The Building registry AP (Dutch: Gebouwenregister) is used to describe a building. In the UML diagram we see that "Building" (Dutch: Gebouw) is the core class and contains a list of attributes, and relations to other classes. For our data snippet, we will only provide two properties: geometry (Dutch: geometrie) and buildingName (Dutch: gebouwNaam):
Our data snippet will not be compliant with the AP, because we will not provide the mandatory property "status".
Every AP has a dedicated JSON-LD context, which we can reuse. You can find the context at the bottom of the AP specification: http://data.vlaanderen.be/context/gebouwenregister.jsonld This is the starting point of our JSON-LD snippet:
{
"@context": "http://data.vlaanderen.be/context/gebouwenregister.jsonld"
}
As example, we will publish data about the public library of Ghent "De Krook". First, following the principles of Linked Data, we must reuse an existing identifier of this building. We will use its Wikidata identifier, which can be found by copying the link at "Concept URI":
{
"@context": "http://data.vlaanderen.be/context/gebouwenregister.jsonld",
"@id": "http://www.wikidata.org/entity/Q28962266"
}
To describe that this is a building, we need to look in the OSLO specification for "Building" (Gebouw). When you hover over it, you can see the URI that is linked with this term:
Make sure to check in the context what the correct term is to use in your snippet:
We can now safely add the '@type' property:
{
"@context": "http://data.vlaanderen.be/context/gebouwenregister.jsonld",
"@id": "http://www.wikidata.org/entity/Q28962266",
"@type": "Gebouw"
}
Of course, we can add a translation in the context if English is preferred:
{
"@context": [ "http://data.vlaanderen.be/context/gebouwenregister.jsonld", {
"Building": "Gebouw"
},
"@id": "http://www.wikidata.org/entity/Q28962266",
"@type": "Building"
}
For the geometry property, we need to create a 2D-Gebouwgeometrie object. This an intermediary object and also contains a geometry property that will contain a WKT literal for the exact coordinates. Again, it is important to hover in the specification for every property what its URI is and then use this to find out the correct term in the JSON-LD context. For "geometrie" of a building, the URI is "https://data.vlaanderen.be/ns/gebouw#Gebouw.geometrie". In the context, we see that we need to use "Gebouw.geometrie" as term in our snippet. Note that not all terms are mapped in the context, such as "2DGebouwgeomtrie". These terms need to be added manually to the context of the snippet.
{
"@context": ["http://data.vlaanderen.be/context/gebouwenregister.jsonld", {
"2DGebouwgeometrie": "https://data.vlaanderen.be/ns/gebouw#2DGebouwgeometrie",
"Geometry": "http://www.w3.org/ns/locn#Geometry"
}],
"@id": "http://www.wikidata.org/entity/Q28962266",
"@type": "Gebouw",
"Gebouw.geometrie": {
"@type": "2DGebouwgeometrie",
"geometrie": {
"@type": "Geometry",
"wkt": {
"@value": "POINT(3.7288391590118404, 51.04909701806207)",
"@type": "http://www.opengis.net/ont/geosparql#wktLiteral"
}
}
},
"gebouwnaam": {
"@value": "De Krook",
"@lang": "nl"
}
}
We used the WKT playground to determine the WKT location of De Krook.
The building name expects a Geografic name (GeografischeNaam). When you hover it, you see that this is a language-tagged string. This is solved in JSON-LD with the @lang property.
Finally, use the JSON-LD playground to check if all triples are correctly returned:
Our data snippet is conform with OSLO. However, to ingest this in an NGSI-LD context broker, we need to apply the NGSI-LD metamodel to our data snippet. The snippet will not have the semantic meaning it is intended by OSLO, but we will be able to process it in a context broker and fix this later on with 1) the keyValues option or 2) NGSI-LDF.
NGSI-LDifying means that we will add an intermediary ngsi:Property object when a triple's object is a Literal, and an intermediary ngsi:Relationship object when the triple's object is another resource. We added the NGSI core context for these terms.
The NGSI-LD data snippet looks as follows:
{
"@context": ["http://data.vlaanderen.be/context/gebouwenregister.jsonld",
"https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld", {
"2DGebouwgeometrie": "https://data.vlaanderen.be/ns/gebouw#2DGebouwgeometrie",
"Geometry": "http://www.w3.org/ns/locn#Geometry"
}],
"@id": "http://www.wikidata.org/entity/Q28962266",
"@type": "Gebouw",
"Gebouw.geometrie": {
"@type": "Relationship",
"object": {
"@type": "2DGebouwgeometrie",
"geometrie": {
"@type": "Relationship",
"object": {
"@type": "Geometry",
"wkt": {
"@type": "Property",
"value": {
"@value": "POINT(3.7288391590118404, 51.04909701806207)",
"@type": "http://www.opengis.net/ont/geosparql#wktLiteral"
}
}
}
}
}
},
"gebouwnaam": {
"@type": "Property",
"value": {
"@value": "De Krook",
"@lang": "nl"
}
}
}
If we want our building to be retrievable with geographic queries using the temporal query API, we need to add the ngsi:location property to the building. This location requires a GeoJSON-LD value, so we also add the GeoJSON-LD context to add context to "Point" and "coordinates" :
curl --location --request POST 'localhost:9090/ngsi-ld/v1/entities' \
--header 'Content-Type: application/ld+json' \
--data-raw '{
"@context": ["http://data.vlaanderen.be/context/gebouwenregister.jsonld",
"https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld",
"https://geojson.org/geojson-ld/geojson-context.jsonld", {
"2DGebouwgeometrie": "https://data.vlaanderen.be/ns/gebouw#2DGebouwgeometrie",
"Geometry": "http://www.w3.org/ns/locn#Geometry"
}],
"@id": "http://www.wikidata.org/entity/Q28962266",
"@type": "https://data.vlaanderen.be/ns/gebouw#Gebouw",
"Gebouw.geometrie": {
"@type": "Relationship",
"object": {
"@id": "http://localhost:9090/ngsi-ld/v1/entities/http%3A%2F%2Fwww.wikidata.org%2Fentity%2FQ28962266#2DGebouwgeometrie",
"@type": "2DGebouwgeometrie",
"geometrie": {
"@type": "Relationship",
"object": {
"@id": "http://localhost:9090/ngsi-ld/v1/entities/http%3A%2F%2Fwww.wikidata.org%2Fentity%2FQ28962266#geometrieClass",
"@type": "Geometry",
"wkt": {
"@type": "Property",
"value": {
"@value": "POINT(3.7288391590118404, 51.04909701806207)",
"@type": "http://www.opengis.net/ont/geosparql#wktLiteral"
}
}
}
}
}
},
"gebouwnaam": {
"@type": "Property",
"value": {
"@value": "De Krook",
"@language": "nl"
}
},
"location": {
"type": "GeoProperty",
"value": {
"type": "Point",
"coordinates": [3.7288391590118404, 51.04909701806207]
}
}
}'
Note that we removed the language tag from gebouwnaam due to a bug. Also make sure to add an identifier for objects in a Relationship. This is necessary to make your entity findable through the Temporal query API (see next tutorial).
Use the JSON-LD playground to check whether everything parses correctly.