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.
Related
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?
I am trying to write Jolt spec for the following input. I need to populate the primaryEmail field based on the condition if primary field is true in the emails array
[
{
"uid": "1234mark",
"name": "mark",
"userName": "markw",
"displayName": "Mark W",
"emails": [
{
"primary": false,
"value": "mark#gmail.com"
},
{
"primary": true,
"value": "mark#hotmail.com"
}
]
},
{
"uid": "9876steve",
"name": "steve",
"userName": "stevew",
"displayName": "Steve W",
"emails": [
{
"primary": false,
"value": "steve#gmail.com"
},
{
"primary": true,
"value": "steve#hotmail.com"
}
]
}
]
The desired output is
[
{
"user": {
"externalId": "1234mark",
"name": "mark",
"userName": "markw",
"displayName": "Mark W",
"primaryEmail": "mark#hotmail.com"
}
},
{
"user": {
"externalId": "9876steve",
"name": "steve",
"userName": "stevew",
"displayName": "Steve W",
"primaryEmail": "steve#hotmail.com"
}
}
]
But I get the following incorrect output since I am not able to populate the primaryEmail field conditionally properly.
[
{
"user": {
"externalId": "1234mark",
"name": "mark",
"userName": "markw",
"displayName": "Mark W"
}
},
{
"user": {
"externalId": "9876steve",
"name": "steve",
"userName": "stevew",
"displayName": "Steve W"
}
}
]
The spec I have created is the following
[
{
"operation": "shift",
"spec": {
"*": {
"uid": "[&1].user.externalId",
"name": "[&1].user.name",
"userName": "[&1].user.userName",
"displayName": "[&1].user.displayName",
"title": "[&1].user.title",
"emails": {
"*": {
"primary": {
"true": {
"#(2,value)": "primaryEmail"
}
}
}
}
}
}
}
]
Could someone please help with this query. Thanks.
What you need is to go 5 levels the three up from the innermost object while adding an extra node called user such as
[
{
"operation": "shift",
"spec": {
"*": {
"uid": "[&1].user.externalId",
"*": "[&1].user.&", // the attributes except for "uid" and "emails" array
"emails": {
"*": {
"primary": {
"true": {
"#(2,value)": "[&5].user.&2Email" // replicate literal "primary" by using &2
}
}
}
}
}
}
}
]
the demo on the site http://jolt-demo.appspot.com/ is
This is my first time to use JoltTransformationJson, so I have limited knowledge and experience on that. Please help me with this complicated project.
Request:
when the payment.code <> "paid", I have to do the following two things for the file.
to change the payment.code ="denied" and payment.text ="denied"
to add a JSON object to item.ADJ
When the payment.code =="paid", don't need to change anything.
Input :
{
"resourceType": "E",
"id": "11",
"identifier": [
{
"type": {
"coding": [
{
"system": "sys1",
"code": "aaa"
}
]
},
"value": "212"
},
{
"type": {
"coding": [
{
"system": "sys2",
"code": "RRR"
}
]
},
"value": "367"
}
],
"status": "active",
"created": "2021-08-05T02:43:48+00:00",
"outcome": "complete",
"item": [
{
"sequence": 1,
"product": {
"coding": [
{
"system": "example",
"code": "abc",
"display": "ABC"
}
],
"text": "ABC"
},
"servicedDate": "2021-08-04",
"quantity": {
"value": 60
},
"ADJ": [
{
"category": {
"coding": [
{
"system": "code1",
"code": "code1",
"display": "CODE1"
}
],
"text": "CODE1"
},
"amount": {
"value": 46.45,
"currency": "USD"
}
},
{
"category": {
"coding": [
{
"system": "code2",
"code": "code2",
"display": "CODE2"
}
],
"text": "CODE2"
},
"amount": {
"value": 12.04,
"currency": "USD"
}
}
]
}
],
"payment": {
"type": {
"coding": [
{
"system": "http://payment.com",
"code": "reversed/cancelled"
}
],
"text": "cancelled"
}
}
}
My Expected Output :
{
"resourceType": "E",
"id": "11",
"identifier": [
{
"type": {
"coding": [
{
"system": "sys1",
"code": "aaa"
}
]
},
"value": "212"
},
{
"type": {
"coding": [
{
"system": "sys2",
"code": "RRR"
}
]
},
"value": "367"
}
],
"status": "active",
"created": "2021-08-05T02:43:48+00:00",
"outcome": "complete",
"item": [
{
"sequence": 1,
"product": {
"coding": [
{
"system": "example",
"code": "abc",
"display": "ABC"
}
],
"text": "ABC"
},
"servicedDate": "2021-08-04",
"quantity": {
"value": 60
},
"ADJ": [
{
"category": {
"coding": [
{
"system": "code1",
"code": "code1",
"display": "CODE1"
}
],
"text": "CODE1"
},
"amount": {
"value": 46.45,
"currency": "USD"
}
},
{
"category": {
"coding": [
{
"system": "code2",
"code": "code2",
"display": "CODE2"
}
],
"text": "CODE2"
},
"amount": {
"value": 12.04,
"currency": "USD"
}
},
{// new object I want to insert into
"category": {
"coding": [
{
"system": "sys_denail",
"code": "denialreason"
}
],
"reason": {
"coding": [
{
"system": "https://example.com",
"code": "A1"
}
],
"text": "unknown"
}}
}
]
}
],
"payment": {
"type": {
"coding": [
{
"system": "http://payment.com",
"code": "denied" //change the value to denied
}
],
"text": "denied" //change the value to denied
}
}
}
Edit : I've tried to answer the second case by myself to be evaluated after the first case is answered
Welcome to SO, please ask minimal and reproducible questions, and show your effort tried for the future.
What you need is to use a conditional logic along with placeholder values with ampersand symbols depending on the levels of each key name within the tree.
I have partially answered, which will handle the bottom part of your question. Indeed the logic for the rest(inserting an object to the array will be similiar)
So, consider having a look at the following solution
[
{
"operation": "shift",
"spec": {
"*": "&",
"payment": {
"type": {
"coding": {
"*": {
"*": "&4.&3.&2[&1].&",
"code": {
"paid": {
"#1": "&6.&5.&4[&3].&2",
"#(4,text)": "&6.text"
},
"*": {
"#denied": "&6.&5.&4[&3].code",
"#(4,text)": {
"#denied": "&6.text"
}
}
}
}
}
}
}
}
}
]
Edit(for your own answer related to adding an object):
your current idea of using shift after default transformation spec is pretty good, you can rephrase like
[
{
"operation": "default",
"spec": {
"temp_deny": {
"denialreason": {
"category": {
"coding": [
{
"system": "sys_denail",
"code": "denialreason"
}
],
"reason": {
"coding": [
{
"system": "https://example.com",
"code": "A1"
}
],
"text": "unknown"
}
}
}
}
}
},
{
"operation": "shift",
"spec": {
"*": "&",
"item": {
"*": {
"*": "&2[&1].&",
"ADJ": {
"#": "&3[&2].&",
"#(4,temp_deny)": "&3[&2].&"
}
}
}
}
}
]
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.
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