Accessing nested property in json-ld frame - json

So, this is my json-ld data:
[
{
"#id": "http://example.com/id2",
"http://www.w3.org/2008/05/skos-xl#literalForm": [
{
"#value": "Secondary entity"
}
]
},
{
"#id": "http://example.com/id1",
"http://example.com/describedBy": [
{
"#id": "http://example.com/id2"
}
],
"http://www.w3.org/2000/01/rdf-schema#label": [
{
"#value": "Main entity"
}
]
}
]
And this is the frame I'm using:
{
"#context" :
{
"label": {
"#id":"http://www.w3.org/2000/01/rdf-schema#label"
},
"describedBy": {
"#id":"http://example.com/describedBy"
},
"id": "#id",
"#vocab" : "http://example.com/",
"#base" : "http://example.com/"
},
"#graph" : {
"describedBy": {}
}
}
The result I'm getting looks like this:
{
"#context": {
"label": {
"#id": "http://www.w3.org/2000/01/rdf-schema#label"
},
"describedBy": {
"#id": "http://example.com/describedBy"
},
"id": "#id",
"#vocab": "http://example.com/",
"#base": "http://example.com/"
},
"id": "id1",
"describedBy": {
"id": "id2",
"http://www.w3.org/2008/05/skos-xl#literalForm": "Secondary entity"
},
"label": "Main entity"
}
Is it possible to frame that data to look like this:
{
"#context": {
"label": {
"#id": "http://www.w3.org/2000/01/rdf-schema#label"
},
"describedBy": {
"#id": "http://example.com/describedBy"
},
"id": "#id",
"#vocab": "http://example.com/",
"#base": "http://example.com/"
},
"id": "id1",
"describedById": "id2",
"describedByLabel": "Secondary entity",
"label": "Main entity"
}
Which is basically creating two new properties: describedById and describedByLabel based on previous describedBy one.

Can't really do this with framing, as "Secondary entity" is a property of the node for "id2", and this would require promoting it to be a property of the "id1" node.
You could do this with a SPARQL CONSTRUCT, but JSON-LD doesn't allow you to really create new data.

Related

Converting JSON data to JSON-LD and creating an RDF graph using pyld and rdflib - issues with defining the context

I have a problem with handling JSON data from different sources. So, my plan was to use JSON-LD, and store the data from a source in RDF so that I can do some analysis work on them. But I don't know how to turn a regular JSON in a JSON-LD correctly. For example, I don't know how to get the correct context for the JSON-LD object.
In my project, each of the sources contain information about the infra configs. This information can be extracted in JSON format, but each source has a different structure.
In the following example you can see how I try to use "pyld" and "rdflib" to turn a JSON object in a Graph, but you can see that the output is not as expected:
Side note, my question was reported as spam by stackoverflow when I used an URL as IRI, even the example URL used most examples. So if you want to run this example you have to replace the <unique_iri> for a real URL to make it work.
Example
import json
from pyld import jsonld
from rdflib import Graph
# JSON data
nodes = [
{
"sysid": "vm_remote",
"type": "vm",
"name": "remote",
"config": {
"id": "worker_1",
"cpu": "2",
},
"connect": [
"db_users"
]
},
{
"sysid": "db_users",
"type": "db",
"name": "users",
"config": {
"id": "database_1",
"location": "eu_west",
}
}
]
# Define the context for the JSON-LD object
context = {
"#version": 1.1,
"#base": "<unique_iri>/team_name/",
"#vocab": "<unique_iri>/resources/onprem/",
"sysid": "#id",
"type": "#type",
"config": {
"#id": "config",
"#context": {
"#base": "<unique_iri>/team_name/config/"
}
},
"connect": {"#id": "relation#connect", "#type": "#id", "#container": "#set"}
}
doc = {
"#context": context,
"#graph": nodes,
"#id": "graph",
"#type": "graph"
}
print("\nInput JSON-LD:\n" + json.dumps(doc, indent=2))
expended_data = jsonld.expand(doc)
print("\n\Expanded JSON-LD:\n" + json.dumps(expended_data, indent=2))
graph = Graph().parse(data=json.dumps(expended_data), format='json-ld')
print("\nRDF Graph:\n" + graph.serialize(format='json-ld'))
# Find the type of each entry (a resource)
q = """
PREFIX resources: <<unique_iri>/resources/onprem/>
SELECT DISTINCT ?type
WHERE
{
?s resources:type ?type .
}
"""
print()
for row in graph.query(q):
print("Type: %s" % row)
Output
Input JSON-LD:
{
"#context": {
"#version": 1.1,
"#base": "<unique_iri>/team_name/",
"#vocab": "<unique_iri>/resources/onprem/",
"sysid": "#id",
"type": "#type",
"config": {
"#id": "config",
"#context": {
"#base": "<unique_iri>/team_name/config/"
}
},
"connect": {
"#id": "relation#connect",
"#type": "#id",
"#container": "#set"
}
},
"#graph": [
{
"sysid": "vm_remote",
"type": "vm",
"name": "remote",
"config": {
"id": "worker_1",
"cpu": "2"
},
"connect": [
"db_users"
]
},
{
"sysid": "db_users",
"type": "db",
"name": "users",
"config": {
"id": "database_1",
"location": "eu_west"
}
}
],
"#id": "graph",
"#type": "graph"
}
\Expanded JSON-LD:
[
{
"#graph": [
{
"<unique_iri>/resources/onprem/config": [
{
"<unique_iri>/resources/onprem/cpu": [
{
"#value": "2"
}
],
"<unique_iri>/resources/onprem/id": [
{
"#value": "worker_1"
}
]
}
],
"<unique_iri>/resources/onprem/relation#connect": [
{
"#id": "db_users"
}
],
"<unique_iri>/resources/onprem/name": [
{
"#value": "remote"
}
],
"#id": "vm_remote",
"#type": [
"<unique_iri>/resources/onprem/vm"
]
},
{
"<unique_iri>/resources/onprem/config": [
{
"<unique_iri>/resources/onprem/id": [
{
"#value": "database_1"
}
],
"<unique_iri>/resources/onprem/location": [
{
"#value": "eu_west"
}
]
}
],
"<unique_iri>/resources/onprem/name": [
{
"#value": "users"
}
],
"#id": "db_users",
"#type": [
"<unique_iri>/resources/onprem/db"
]
}
],
"#id": "graph",
"#type": [
"<unique_iri>/resources/onprem/graph"
]
}
]
RDF Graph:
[
{
"#id": "file:///C:...",
"#type": [
"<unique_iri>/resources/onprem/graph"
]
}
]
Type: <unique_iri>/resources/onprem/graph
The graph is missing the nodes and I don't understand what I am doing wrong.
I am also not sure how to deal with the config nodes. These should be nodes with their own unique identifier since other data sources will be pointing to these too.
Also, these python libraries give me other results than the online playground tool from json-ld.
Can somebody please help me?

Selectively get certain arrays from inside an array in JSON using JOLT

I've been trying to get some fields out of a very long and complicated json format but not getting the output I want.
MY current spec obtains all events from the event array and lists them in the output. I'm unsure how to select specific events and only output those. Am not quite sure of the syntax
My JSON:
{
"rootid": "19718",
"clloadm": "2021-06-01T22:40:02",
"clload": "2021-06-01T21:21:39",
"date": "2021-05-25T21:52:30",
"events": [
{
"done": {
"id": "e0",
"value": "2021-05-29T08:08:19"
},
"id": "e0_event",
"started": {
"id": "e0",
"value": "2021-05-29T08:08:19"
},
"status": "complete"
},
{
"done": {
"id": "e1",
"value": "2021-05-27T02:20:25"
},
"id": "e1_event",
"started": {
"id": "e1",
"value": "2021-05-27T02:20:25"
},
"status": "complete"
},
{
"done": {
"id": "e2",
"value": "2021-05-29T08:08:19"
},
"id": "e2_event",
"started": {
"id": "e2",
"value": "2021-05-29T08:08:19"
},
"status": "complete"
},
{
"done": {
"id": "e3",
"value": "2021-05-29T08:08:19"
},
"id": "e3_event",
"started": {
"id": "e3",
"value": "2021-05-29T08:08:19"
},
"status": "complete"
},
{
"done": {
"id": "e4",
"value": "2021-05-29T08:08:19"
},
"id": "e4_event",
"started": {
"id": "e4",
"value": "2021-05-29T08:08:19"
},
"status": "complete"
}
],
"ids": [
{
"id": "id",
"source": "source",
"value": "value"
},
{
"id": "new_id",
"source": "new_source",
"value": "value"
}
]
}
My Jolt Spec that gets all events for now:
[
{
"operation": "shift",
"spec": {
"rootid": "rootid",
"clloadm": "clloadm",
"clload": "clload",
"date": "date",
"events": {
"*": {
"*": {
"#value": "#id"
}
}
},
"ids": {
"*": {
"#value": "#id"
}
}
}
}
]
The output I get:
{
"rootid" : "19718",
"clloadm" : "2021-06-01T22:40:02",
"clload" : "2021-06-01T21:21:39",
"date" : "2021-05-25T21:52:30",
"e0" : [ "2021-05-29T08:08:19", "2021-05-29T08:08:19" ],
"e1" : [ "2021-05-27T02:20:25", "2021-05-27T02:20:25" ],
"e2" : [ "2021-05-29T08:08:19", "2021-05-29T08:08:19" ],
"e3" : [ "2021-05-29T08:08:19", "2021-05-29T08:08:19" ],
"e4" : [ "2021-05-29T08:08:19", "2021-05-29T08:08:19" ],
"id" : "value",
"new_id" : "value"
}
The output I would like
{
"rootid" : "19718",
"clloadm" : "2021-06-01T22:40:02",
"clload" : "2021-06-01T21:21:39",
"date" : "2021-05-25T21:52:30",
"e0" : [ "2021-05-29T08:08:19", "2021-05-29T08:08:19" ],
"e4" : [ "2021-05-29T08:08:19", "2021-05-29T08:08:19" ],
"id" : "value",
"new_id" : "value"
}
You can write the individual keys e0 and e4 as conditional cases for #id key while rewriting the rest of the key-value pairs through "*":"&" representation such as
[
{
"operation": "shift",
"spec": {
"*": "&",
"events": {
"*": {
"*": {
"#id": {
"e0": { "#(2,value)": "&" },
"e4": { "#(2,value)": "&" }
}
}
}
},
"ids": {
"*": {
"#value": "#id"
}
}
}
}
]

Remove extra parameters from framed JSON-LD

So, lets consider the following data fetched from db:
[
{
"#id": "http://example.com/1",
"http://example.com/label": "Parent",
"http://example.com/status": "Active",
"http://example.com/children": [
{
"#id": "http://example.com/2"
}
]
},
{
"#id": "http://example.com/2",
"http://example.com/label": "Child",
"http://example.com/status": "Active"
}
]
And the frame:
{
"#context": {
"#base": "http://example.com/",
"#vocab": "http://example.com/"
},
"#graph": {
"status":{}
}
}
The result will look like:
{
"#context": {
"#base": "http://example.com/",
"#vocab": "http://example.com/"
},
"#graph": [
{
"#id": "1",
"children": {
"#id": "2",
"label": "Child",
"status": "Active"
},
"label": "Parent",
"status": "Active"
},
{
"#id": "2",
"label": "Child",
"status": "Active"
}
]
}
As you can see in the first object, in the children section I get some extra parameters in addition to id.
Is there a way I could simplify the children list to just contain ids:
"children": [
"2"
]
I tried adding this to my frame:
"children": {
"#id": "http://example.com/children",
"#type": "#id"
}
But it doesn't work as I expect.
Use framing flags: "#embed": "#never" or "#explicit": true.
{
"#context": {
"#base": "http://example.com/",
"#vocab": "http://example.com/"
},
"#graph": {
"status": {},
"#embed": "#never"
}
}
or
{
"#context": {
"#base": "http://example.com/",
"#vocab": "http://example.com/"
},
"#graph": {
"status": {},
"children": {"#explicit": true, "#omitDefault": true}
}
}
But perhaps all you need is compaction.
If you don't want to compact arrays, toggle the respective option. In JSONLD-Java:
final JsonLdOptions options = new JsonLdOptions();
options.setCompactArrays(false);
Playground: 1, 2, 3.

EmberJS JSONAPIAdapter with hasMany + embedded relationships

In addition to my last question ember.js JSONAPIAdapter with hasMany a colleague asked if the "kind-of"-sideloaded relationships in the working
JSON:API structure could be embedded like this:
{
"data": [
{
"type": "altersgruppe",
"id": "1",
"attributes": {
"name": "UNTER_21"
},
"relationships": {
"tarifbeitraege": {
"data": [
{
"type": "tarifbeitrag",
"id": "3",
"attributes": {
"name": "ZAHN70",
"beitrag": "3-29,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "25.99"
}
},
{
"type": "tarifbeitrag",
"id": "4",
"attributes": {
"name": "ZAHN90",
"beitrag": "4-28,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "30.99"
}
}
]
}
}
},
{
"type": "altersgruppe",
"id": "2",
"attributes": {
"name": "ALTER_21_24"
},
"relationships":{
"tarifbeitraege": {
"data": [
{
"type": "tarifbeitrag",
"id": "1",
"attributes": {
"name": "ZAHN70",
"beitrag": "1-25,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "25.99"
}
},
{
"type": "tarifbeitrag",
"id": "2",
"attributes": {
"name": "ZAHN90",
"beitrag": "2-25,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "25.99"
}
}]
}
}
}
]
}
The idea behind that: We can use relationships with less problems in the java backend (where sideloaded structures are harder to implement).
But the JSON above structure does not work. The store contains only the first level of data, which is "altersgruppe", but "tarifbeitraege" are empty.
This type of document is referred to as a compound document in the JSON:API specification.
The "relationships" section of a compound document is supposed to have only the relationships - individual objects there are supposed to be resource identifier objects. Putting attributes there doesn't work because that's not where they are supposed to be.
Instead, the full objects are side-loaded in a top-level "included" section. Thus, your response should probably look more like this:
{
"data": [
{
"type": "altersgruppe",
"id": "1",
"attributes": {
"name": "UNTER_21"
},
"relationships": {
"tarifbeitraege": {
"data": [
{ "type": "tarifbeitrag", "id": "3" },
{ "type": "tarifbeitrag", "id": "4" }
]
}
}
},
{
"type": "altersgruppe",
"id": "2",
"attributes": {
"name": "ALTER_21_24"
},
"relationships":{
"tarifbeitraege": {
"data": [
{ "type": "tarifbeitrag", "id": "1" },
{ "type": "tarifbeitrag", "id": "2" }
]
}
}
}
],
"included": [
{
"type": "tarifbeitrag",
"id": "3",
"attributes": {
"name": "ZAHN70",
"beitrag": "3-29,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "25.99"
}
},
{
"type": "tarifbeitrag",
"id": "4",
"attributes": {
"name": "ZAHN90",
"beitrag": "4-28,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "30.99"
}
},
{
"type": "tarifbeitrag",
"id": "1",
"attributes": {
"name": "ZAHN70",
"beitrag": "1-25,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "25.99"
}
},
{
"type": "tarifbeitrag",
"id": "2",
"attributes": {
"name": "ZAHN90",
"beitrag": "2-25,70",
"proergaenzung": "7,00",
"gesamtbeitrag": "25.99"
}
}
]
}
There's an example on the home page of http://jsonapi.org that shows an example that includes a side load, as well as one in the section of the specification describing compound documents.

Frame json-ld document to append children

I'm trying to create a frame to include every children inside an array, so Detail (see the example) must contain all the other nodes inside itself.
This is an example of the data I'm using, in expanded JSON-LD:
[
{
"#id": "A",
"http://ontology.ayvu.net/#Person": [
{
"#value": "101023",
"#type": "http://www.w3.org/2001/XMLSchema#integer"
}
],
"http://ontology.ayvu.net/#Detail": [
{
"#id": "_:g70157685738360"
},
{
"#id": "_:g70157685722960"
}
]
},
{
"#id": "_:g70157685722960",
"http://ontology.ayvu.net/#Deuda": [
{
"#value": "OFICINA"
}
],
"http://ontology.ayvu.net/#Detalle": [
{
"#value": "100"
"#type": "http://www.w3.org/2001/XMLSchema#decimal"
}
]
},
{
"#id": "_:g70157685738360",
"http://ontology.ayvu.net/#Deuda": [
{
"#value": "3573.04",
"#type": "http://www.w3.org/2001/XMLSchema#decimal"
}
],
"http://ontology.ayvu.net/#Detalle": [
{
"#value": "AUTOMOTORES"
}
]
}
]
The following frame does that (and sets the default vocabulary to http://ontology.ayvu.net/# so that those long URLs disappear):
{
"#context": {
"#vocab": "http://ontology.ayvu.net/#"
},
"Detail": {}
}
The frame ensures that the top-level object contains a Detail property so that you get the right root object. The children are then automatically moved down the JSON tree.
The result will look as follows:
{
"#context": {
"#vocab": "http://ontology.ayvu.net/#"
},
"#graph": [
{
"#id": "A",
"Person": {
"#value": "101023"
"#type": "http://www.w3.org/2001/XMLSchema#integer",
},
"Detail": [
{
"#id": "_:b0",
"Detalle": "AUTOMOTORES",
"Deuda": {
"#value": "3573.04"
"#type": "http://www.w3.org/2001/XMLSchema#decimal",
}
},
{
"#id": "_:b1",
"Detalle": {
"#value": "100"
"#type": "http://www.w3.org/2001/XMLSchema#decimal",
},
"Deuda": "OFICINA"
}
]
}
]
}
Or live in the JSON-LD playground: http://tinyurl.com/q844vkd