Skip to content

Commit

Permalink
Add subComponentRelationship type to entity file
Browse files Browse the repository at this point in the history
In the datamodel the entity.ttl file describes the "static" knowledge
about attributes. For instance the domain and range of attributes. In this PR, the
Relationships will be typed as subcomponents and peer relationships.

Related Epics: IndustryFusion#514
Related User-stories: IndustryFusion#555

Signed-off-by: marcel <[email protected]>
  • Loading branch information
wagmarcel committed Jul 11, 2024
1 parent 6963887 commit 78c9961
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 5 deletions.
54 changes: 52 additions & 2 deletions semantic-model/datamodel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ In order to validate it with a JSON-Schema, first the base object must be descri
}
```
This specifies the mandatory `id` and `type` field of every NGSI-LD object. `id` must be an *URN* and `type` must contain a *compacted* form.
The "$schema" field must be "https://json-schema.org/draft/2020-12/schema", the $id of the schema must be a valid URL with the additional constraint that all '#' fields **must be URL-Encoded**. An example for a schema and related data can be seen in the following:
The `$schema` field must be https://json-schema.org/draft/2020-12/schema, the `$id` of the schema must be a valid URL with the additional constraint that all '#' fields **must be URL-Encoded**. An example for a schema and related data can be seen in the following:

```json
# JSON-Schema:
Expand Down Expand Up @@ -445,7 +445,8 @@ The following JSON-Schema Keywords from the standard are forbidded:
## Added JSON-Schmea Keywords:
The following JSON-Schema Keywords are added to the standard:

* **relationship:** Contains the *compacted* type for a NGSI-LD relationship.
* **relationship:** Contains the *compacted* type for a NGSI-LD relationship.
* **relationship_type** is further detailing the relationship type. There are two values allowed: `subcomponent` or `peer`

## Integrating ECLASS Properties
`ECLASS` provides additional data for every `IRDI` which can be added/mapped to `JSON-Schema`:
Expand Down Expand Up @@ -584,6 +585,55 @@ node tools/jsonschema2shacl.js -s examples/plasmacutter_schema.json -i https://
```

### Create OWL Entities descriptions

The `entities.ttl` description contains all non validation relevant information about entities. It defines **domain** and **range** of attributes and more details, e.g. whether a NGSI-LD Relationship is a subcomponent or a peer relationship. The description is created in [OWL](https://www.w3.org/OWL/).

#### Install

```
npm install
```

#### Usage

```
jsonschema2owl.js
Converting an IFF Schema file for NGSI-LD objects into an OWL entity file.
Options:
--version Show version number [boolean]
-s, --schema Schema File containing array of Schemas [string] [required]
-i, --schemaid Schma-id of object to generate SHACL for [string] [required]
-c, --context JSON-LD-Context [string] [required]
-n, --namespace default namespace (if not derived by context) [string]
-h, --help Show help [boolean]
```

#### Examples
```
node ./tools/jsonschema2owl.js -s ./examples/filter_and_cartridge_subcomponent_schema.json -c file:$PWD/./examples/context.jsonld -i https://industry-fusion.org/eclass#0173-1#01-ACK991#016
```
```
@prefix owl: <http://www.w3.org/2002/07/owl#>.
@prefix iffb: <https://industry-fusion.org/base/v0.1/>.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix ngsi-ld: <https://uri.etsi.org/ngsi-ld/>.
@prefix b: <https://industryfusion.github.io/contexts/ontology/v0/base/>.
iffb:hasCartridge
a owl:Property, b:SubComponentRelationship;
rdfs:domain <https://industry-fusion.org/eclass%230173-1%2301-ACK991%23016>;
rdfs:range ngsi-ld:Relationship.
iffb:machine_state
a owl:Property;
rdfs:domain <https://industry-fusion.org/eclass%230173-1%2301-ACK991%23016>;
rdfs:range ngsi-ld:Property.
<https://industry-fusion.org/eclass#0173-1#01-ACK991#016> a owl:Class.
```

### Convert NGSI-LD forms

#### Install
Expand Down
4 changes: 4 additions & 0 deletions semantic-model/datamodel/examples/context.jsonld
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
"sh": {
"@id": "http://www.w3.org/ns/shacl#",
"@prefix": true
},
"base": {
"@id": "https://industryfusion.github.io/contexts/ontology/v0/base/",
"@prefix": true
}
}
]
20 changes: 20 additions & 0 deletions semantic-model/datamodel/tools/lib/owlUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const RDF = $rdf.Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#');
const RDFS = $rdf.Namespace('http://www.w3.org/2000/01/rdf-schema#');
const OWL = $rdf.Namespace('http://www.w3.org/2002/07/owl#');
const NGSILD = $rdf.Namespace('https://uri.etsi.org/ngsi-ld/');
const BASE = $rdf.Namespace('https://industryfusion.github.io/contexts/ontology/v0/base/');

const globalAttributes = [];
const globalEntities = [];
Expand All @@ -40,6 +41,7 @@ class Attribute {
this._entities = [];
this._attributeName = attributeName;
this._isProperty = true;
this._isSubcomponent = false;
}

addEntity (entity) {
Expand All @@ -61,6 +63,14 @@ class Attribute {
get entities () {
return this._entities;
}

get isSubcomponent () {
return this._isSubcomponent;
}

set isSubcomponent (isSc) {
this._isSubcomponent = isSc;
}
}

function dumpAttribute (attribute, entity, store) {
Expand All @@ -71,6 +81,11 @@ function dumpAttribute (attribute, entity, store) {
store.add($rdf.sym(attribute.attributeName), RDFS('range'), NGSILD('Property'));
} else {
store.add($rdf.sym(attribute.attributeName), RDFS('range'), NGSILD('Relationship'));
if (attribute.isSubcomponent) {
store.add($rdf.sym(attribute.attributeName), RDF('type'), BASE('SubComponentRelationship'));
} else {
store.add($rdf.sym(attribute.attributeName), RDF('type'), BASE('PeerRelationship'));
}
}
}
}
Expand Down Expand Up @@ -103,6 +118,10 @@ function scanProperties (entity, typeschema, contextManager) {
if ('relationship' in typeschema.properties[property]) {
isProperty = false;
}
let isSubcomponent = false;
if ('relationship_type' in typeschema.properties[property] && typeschema.properties[property].relationship_type === 'subcomponent') {
isSubcomponent = true;
}
let path = property;
if (!contextManager.isValidIri(path)) {
path = contextManager.expandTerm(path);
Expand All @@ -111,6 +130,7 @@ function scanProperties (entity, typeschema, contextManager) {
const attribute = new Attribute(path);
attribute.addEntity(entity);
attribute.isProperty = isProperty;
attribute.isSubcomponent = isSubcomponent;
globalAttributes.push(attribute);
});
}
Expand Down
4 changes: 4 additions & 0 deletions semantic-model/datamodel/tools/tests/schema2owl/c0
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
"sh": {
"@id": "http://www.w3.org/ns/shacl#",
"@prefix": true
},
"base": {
"@id": "https://industryfusion.github.io/contexts/ontology/v0/base/",
"@prefix": true
}
}
]
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
@prefix owl: <http://www.w3.org/2002/07/owl#>.
@prefix iffb: <https://industry-fusion.org/base/v0.1/>.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix base: <https://industryfusion.github.io/contexts/ontology/v0/base/>.
@prefix ngsi-ld: <https://uri.etsi.org/ngsi-ld/>.

iffb:hasFilter
a owl:Property;
a owl:Property, base:PeerRelationship;
rdfs:domain <https://industry-fusion.org/eclass%230173-1%2301-AKJ975%23017>;
rdfs:range ngsi-ld:Relationship.
iffb:machine_state
Expand Down
125 changes: 125 additions & 0 deletions semantic-model/datamodel/tools/tests/schema2owl/schema4_c0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
[
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://industry-fusion.org/eclass%230173-1%2301-ACK991%23016",
"title": "Filter",
"description": "Schweissrauchabsauger",
"type": "object",
"properties": {
"type": {
"const": "eclass:0173-1#01-ACK991#016"
},
"id": {
"type": "string",
"pattern": "^urn:[a-zA-Z0-9][a-zA-Z0-9-]{1,31}:([a-zA-Z0-9()+,.:=@;$_!*'-]|%[0-9a-fA-F]{2})*$"
}
},
"required": ["type", "id"],
"allOf": [
{
"$ref": "https://industry-fusion.org/base-objects/v0.1/machine/properties"
},
{
"$ref": "https://industry-fusion.org/base-objects/v0.1/filter/relationships"
}
]
},
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://industry-fusion.org/base-objects/v0.1/filter/relationships",
"title": "IFF template for filter relationship",
"description": "Cutter template for IFF",
"type": "object",
"properties": {
"hasCartridge": {
"relationship": "eclass:0173-1#01-AKE795#017",
"relationship_type": "subcomponent",
"$ref": "https://industry-fusion.org/base-objects/v0.1/link"
}
}
},
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://industry-fusion.org/base-objects/v0.1/machine/properties",
"title": "Cutter properties",
"description": "Properties for class cutter",
"type": "object",
"properties": {
"machine_state": {
"type": "string",
"title": "Machine Status",
"description": "Current status of the machine (Online_Idle, Run, Online_Error, Online_Maintenance, Setup, Testing)",
"enum": [
"Online_Idle",
"Run",
"Online_Error",
"Online_Maintenance",
"Setup",
"Testing"
]
}
},
"required": [
"machine_state"
]
},
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://industry-fusion.org/eclass%230173-1%2301-AKE795%23017",
"title": "Filterpatrone",
"description": "Filterpatrone",
"type": "object",
"properties": {
"type": {
"const": "eclass:0173-1#01-AKE795#017"
},
"id": {
"type": "string",
"pattern": "^urn:[a-zA-Z0-9][a-zA-Z0-9-]{1,31}:([a-zA-Z0-9()+,.:=@;$_!*'-]|%[0-9a-fA-F]{2})*$"
}
},
"required": ["type", "id"],
"allOf": [
{
"$ref": "https://industry-fusion.org/base-objects/v0.1/cartridge/properties"
}
]
},
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://industry-fusion.org/base-objects/v0.1/cartridge/properties",
"title": "Cartridge properties",
"description": "Properties for class cutter",
"type": "object",
"properties": {
"waste_class": {
"type": "string",
"title": "Waste Class",
"description": "Current wasteclass of the cartridge (WC0, WC1, WC2, WC3)",
"enum": [
"WC0",
"WC1",
"WC2",
"WC3"
]
}
},
"required": [
"waste_class"
]
},
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://industry-fusion.org/base-objects/v0.1/link",
"title": "IFF template for cutter relationship",
"description": "Cutter template for IFF",
"type": "object",
"properties": {
"object": {
"type": "string",
"pattern": "^urn:[a-zA-Z0-9][a-zA-Z0-9-]{0,31}:[a-zA-Z0-9()+,\\-.:=@;$_!*']*[a-zA-Z0-9()+,\\-.:=@;$_!*']$"
}
},
"required": ["object"]
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://industry-fusion.org/eclass#0173-1#01-ACK991#016
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@prefix owl: <http://www.w3.org/2002/07/owl#>.
@prefix iffb: <https://industry-fusion.org/base/v0.1/>.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix base: <https://industryfusion.github.io/contexts/ontology/v0/base/>.
@prefix ngsi-ld: <https://uri.etsi.org/ngsi-ld/>.

iffb:hasCartridge
a owl:Property, base:SubComponentRelationship;
rdfs:domain <https://industry-fusion.org/eclass%230173-1%2301-ACK991%23016>;
rdfs:range ngsi-ld:Relationship.
iffb:machine_state
a owl:Property;
rdfs:domain <https://industry-fusion.org/eclass%230173-1%2301-ACK991%23016>;
rdfs:range ngsi-ld:Property.
<https://industry-fusion.org/eclass#0173-1#01-ACK991#016> a owl:Class.


4 changes: 3 additions & 1 deletion semantic-model/datamodel/tools/tests/testOwlUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const RDF = $rdf.Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#');
const RDFS = $rdf.Namespace('http://www.w3.org/2000/01/rdf-schema#');
const OWL = $rdf.Namespace('http://www.w3.org/2002/07/owl#');
const NGSILD = $rdf.Namespace('https://uri.etsi.org/ngsi-ld/');
const BASE = $rdf.Namespace('https://industryfusion.github.io/contexts/ontology/v0/base/');

describe('Test class Entity', function () {
it('Should create Entity with IRI', function () {
Expand Down Expand Up @@ -75,7 +76,8 @@ describe('Test dumpAttribute', function () {
const expected = [
[$rdf.namedNode(attributeName), RDF('type'), OWL('Property')],
[$rdf.namedNode(attributeName), RDFS('domain'), $rdf.namedNode(entityName)],
[$rdf.namedNode(attributeName), RDFS('range'), NGSILD('Relationship')]
[$rdf.namedNode(attributeName), RDFS('range'), NGSILD('Relationship')],
[$rdf.namedNode(attributeName), RDF('type'), BASE('PeerRelationship')]
];
const store = {
add: (s, p, o) => { added.push([s, p, o]); }
Expand Down
2 changes: 1 addition & 1 deletion semantic-model/datamodel/tools/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const removedKeywords = [
'valid', 'error', 'annotation', 'additionalProperties', 'propertyNames',
'$vocabulary', '$defs', 'multipleOf', 'uniqueItems', 'maxContains',
'minContains', 'maxProperties', 'minPropeties', 'dependentRequired'];
const addedKeywords = ['relationship', 'datatype', 'unit'];
const addedKeywords = ['relationship', 'relationship_type', 'datatype', 'unit'];

const argv = yargs
.command('$0', 'Validate a JSON-LD object with IFF Schema.')
Expand Down

0 comments on commit 78c9961

Please sign in to comment.