Skip to content

Commit

Permalink
VSSo: VehicleComponents as instances (#171)
Browse files Browse the repository at this point in the history
* VSSo: VehicleComponents as instances

Currently the VehicleComponents were modelled as
subclasses with `rdfs:subclass`. This change introduces
a variable to choose either way until it's decided.

Additionally introduced documentation improvements and
code cleanups.

Mentioned in: w3c/vsso#22

Signed-off-by: Daniel Wilms <[email protected]>

* Adding `vsso:Vehicle` as an instance of `vsso-core:VehicleComponent`

Change reflecting discussion in:
w3c/vsso#41 (comment)

Signed-off-by: Daniel Wilms <[email protected]>
  • Loading branch information
danielwilms authored Jun 14, 2022
1 parent 3159418 commit e282e9f
Showing 1 changed file with 81 additions and 62 deletions.
143 changes: 81 additions & 62 deletions contrib/vspec2ttl/vspec2ttl.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,21 @@
from enum import Enum


# There are two options of handling branches:
# 1. branches are handled as _subclasses_ of vehicle components
# 2. branches are handled as _instances_ of vehicle components
#
# As it's not decided for now, we can generate both by setting this
# variable to True or False. True means that branches are handled as
# subclasses of vehicle components. False means that branches are handled
# as instances of vehicle components.

COMPONENTS_AS_CLASSES = False

class VssoCoreConcepts (Enum):

###
# Class to define the concepts and their names for later references
###
EMPTY = ""
BELONGS_TO = "belongsToVehicleComponent"
HOLDS_VALUE = "vehiclePropertyValue"
Expand Down Expand Up @@ -63,24 +76,13 @@ def uri_string(self):
return f'{self.ns}{self.value}'


def usage():
print(f"""
Usage: {sys.argv[0]} [options] vspec_file ttl_file
where [options] are:
-I include_dir Add include directory to search for included vspec
files. Can be used multiple timees.
vspec_file The vehicle specification file to parse.
ttl_file The file to output the ttl data to.
""")
sys.exit(255)


def setup_graph():
# create a Graph
###
# function to define the metadata of VSSo,
# to define the used prefixes and namespaces,
# and to crete the basic rdflib graph
###

g = Graph()

ontology_description_ttl = """
Expand All @@ -92,6 +94,7 @@ def setup_graph():
@prefix vann: <http://purl.org/vocab/vann/> .
@prefix vsso-core: <https://github.com/w3c/vsso-core#> .
@prefix vsso: <https://github.com/w3c/vsso#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
vsso: rdf:type owl:Ontology ;
Expand All @@ -117,19 +120,14 @@ def setup_graph():

g.parse(data=ontology_description_ttl, format="turtle")

g.bind ("skos", SKOS)
g.bind ("rdfs", RDFS)
print("--- printing mboxes ---")
print(g.serialize(format='ttl'))
return g

def setUniqueNodeName (name):
if 'Vehicle' != name:
return name.replace('Vehicle','').replace('.','')
else:
return name.replace('.','')

def setTTLName (node):
###
# function to set a unique name of a node
# which is used in the ontology. Sets a combined name of
# the node and its parent, if the parent is not `vehicle`.
###
if node.ttl_name:
return node.ttl_name
if node.parent and node.parent.name != "Vehicle":
Expand All @@ -140,37 +138,40 @@ def setTTLName (node):
return ttl_name

def print_ttl_content(file, tree):
###
# function to create & print the content of the ontology
# in turtle format.
###

tree_node: VSSNode
name_list = []
vsso_name_list = []
duplication = {}
duplication_vsso = {}
datatypes = {}
enums = 0
namespace = "https://github.com/w3c/vsso#"


graph = setup_graph()

for tree_node in PreOrderIter(tree):
data_type_str = tree_node.data_type.value if tree_node.has_data_type() else ""
unit_str = tree_node.unit.value if tree_node.has_unit() else ""
type_str = tree_node.type.value

for tree_node in PreOrderIter(tree): #< iterate over the tree in preorder
# start with setting the unique name of the node
name = setTTLName(tree_node)

# check if the original name is already used
# and store for later analysis
if tree_node.name in name_list:
# print (f"** warning: {tree_node.name}" )
# print (f"** VSSO warning Replaced by: {name}" )
if tree_node.name in duplication.keys():
duplication [tree_node.name] += 1
else:
duplication [tree_node.name] = 2
else:
name_list.append (tree_node.name)


# check if combined name is unique, otherwise
# use the parents unique name and combine with the node name
if name in vsso_name_list:
# print (f"** VSSO warning: {name}" )
name = setTTLName(tree_node.parent) + tree_node.name
# print (f"** VSSO warning Replaced by: {name}" )

if name in duplication_vsso.keys():
duplication_vsso [name] += 1
Expand All @@ -179,24 +180,20 @@ def print_ttl_content(file, tree):
else:
vsso_name_list.append (name)

namespace = "https://github.com/w3c/vsso#"

# set the URI for the node
node = URIRef(namespace + name)

# not needed, in case we use classes
# if VSSType.ATTRIBUTE == tree_node.type:
# node = URIRef(f"{VssoCoreConcepts.EMPTY.uri_string}has{name}")

# basic metadata, independent of node type
graph.add((node, RDFS.label, Literal(name,"en")))
graph.add((node, VssoCoreConcepts.VSS_CLASSIFICATION.uri, Literal(tree_node.qualified_name('.'),"en")))
graph.add((node, SKOS.definition, Literal(tree_node.description,"en")))

# if a comment is set in the VSS node add the comment to the ontology
if tree_node.comment:
graph.add((node, RDFS.comment, Literal(tree_node.comment,"en")))

parent_namespace = "https://github.com/w3c/vsso#"
# branch nodes (incl. instance handling)
if VSSType.BRANCH == tree_node.type:
# branch nodes as vsso:VehicleComponent subclasses if variable is set accordingly
if VSSType.BRANCH == tree_node.type and COMPONENTS_AS_CLASSES:
if tree_node.parent:
graph.add((node, RDF.type, OWL.Class))
graph.add((node, RDFS.subClassOf, VssoCoreConcepts.VEHICLE_COMP.uri))
Expand All @@ -207,46 +204,68 @@ def print_ttl_content(file, tree):
if "Vehicle" == setTTLName(tree_node.parent):
graph.add((b, OWL.allValuesFrom, VssoCoreConcepts.VEHICLE.uri))
else:
graph.add((b, OWL.allValuesFrom, URIRef(parent_namespace + setTTLName(tree_node.parent))))
graph.add((b, OWL.allValuesFrom, URIRef(namespace + setTTLName(tree_node.parent))))

graph.add((node, RDFS.subClassOf, b))
print( [x.name if x.type != VSSType.BRANCH else None for x in tree_node.children])

# branch nodes as vsso:VehicleComponent instances if variable is set accordingly
elif VSSType.BRANCH == tree_node.type and not COMPONENTS_AS_CLASSES:
graph.add ((node, RDF.type, VssoCoreConcepts.VEHICLE_COMP.uri))
if tree_node.parent:
graph.add((node, VssoCoreConcepts.PART_OF_VEH_COMP.uri, URIRef(namespace + setTTLName(tree_node.parent))))


# attributes, sensors & actuators
else:
if VSSType.ATTRIBUTE == tree_node.type:
graph.add((node, RDF.type, OWL.Class))
graph.add((node, RDFS.subClassOf, VssoCoreConcepts.VEHICLE_STAT.uri))
b = BNode()
graph.add((b, RDF.type, OWL.Restriction))
graph.add((b, OWL.onProperty, VssoCoreConcepts.BELONGS_TO.uri))
if "Vehicle" == setTTLName(tree_node.parent):
graph.add((b, OWL.allValuesFrom, VssoCoreConcepts.VEHICLE.uri))
else:
graph.add((b, OWL.allValuesFrom, URIRef(parent_namespace + setTTLName(tree_node.parent))))

graph.add((node, RDFS.subClassOf, b))
if COMPONENTS_AS_CLASSES:
b = BNode()
graph.add((b, RDF.type, OWL.Restriction))
graph.add((b, OWL.onProperty, VssoCoreConcepts.BELONGS_TO.uri))
if "Vehicle" == setTTLName(tree_node.parent):
graph.add((b, OWL.allValuesFrom, VssoCoreConcepts.VEHICLE.uri))
else:
graph.add((b, OWL.allValuesFrom, URIRef(namespace + setTTLName(tree_node.parent))))

graph.add((node, RDFS.subClassOf, b))

else: # < vss actuators & sensors

# check different datatypes in use
if (tree_node.data_type in datatypes.keys()):
datatypes[tree_node.data_type] += 1
else:
datatypes[tree_node.data_type] = 1

graph.add((node, RDF.type, VssoCoreConcepts.VEHICLE_SIGNAL.uri))
graph.add((node, VssoCoreConcepts.BELONGS_TO.uri, URIRef(namespace + setTTLName(tree_node.parent))))

if VSSType.ACTUATOR == tree_node.type:
graph.add((node, RDF.type, VssoCoreConcepts.VEHICLE_ACT.uri))


# write the file and print the metadata.
file.write(graph.serialize(format='ttl'))

for ns, url in graph.namespaces():
print(f"@prefix {ns}: <{url}>")
print (duplication)
print (duplication_vsso)
print (datatypes)

def usage():
print(f"""
Usage: {sys.argv[0]} [options] vspec_file ttl_file
where [options] are:
-I include_dir Add include directory to search for included vspec
files. Can be used multiple timees.
vspec_file The vehicle specification file to parse.
ttl_file The file to output the ttl data to.
""")
sys.exit(255)

if __name__ == "__main__":
#
Expand Down

0 comments on commit e282e9f

Please sign in to comment.