ARTIFACTS / Software / OCML to OWL translator
This is a little side-project I did while at the Knowledge Media Institute. The purpose was to maintain interoperability between the OCML-based environment of the application I was working on (PhiloSURFical) and the wider semantic web world, which uses the W3C-standard OWL language.
The translator consists of a few lisp functions and it runs from within OCML. It's been developed and tested on Lispworks (last tested and updated on 11-06-2007). It's just a quick hack, but in case you need to export data from OCML it may get you started..
The translator consists of a few lisp functions and it runs from within OCML. It's been developed and tested on Lispworks (last tested and updated on 11-06-2007). It's just a quick hack, but in case you need to export data from OCML it may get you started..
;; OCML--> OWL translator
;; written by Michele Pasin
;; the translator at the moment is just a major help to port an ocml ontology to owl
;; you will probably have to manually review the ontology - see below for detail
#|
HOWTO:
1) load your ontology into OCML (translator works from within OCML)
2) compile&load the translator functions (this file)
3) call the translator with the appropriate arguments, e.g.
(create-owl-onto 'top-class-to-translate-from 'a-prefix "http://my-onto-namespace.owl" "local-path")
For example, in my case I used:
(create-owl-onto 'philosurfical-entity 'phil "http://philosurfical.open.ac.uk/ontology/philosurfical.owl" "/Users/michelepasin/Desktop/-last-translation.owl")
What it does:
- it can properly translate the TAXONOMY
- it creates a Protege'-compliant owl file
- it transforms all the ocml-classes slots into owl-OBJECT-PROPERTIES + owl-CLASS-RESTRICTIONS
...(interesting side-effect --> it helps checking the consistency of an OCML ontology!..typos, wrong args etc..)
What it doesn't do (for now):
- check for DATATYPEs, and translate them to XML-types
- translate complex restrictions
- translate contraints
- translate fixed values on ocml slots (in this case it outputs the same class as the property range)
- tanslate instances
- we are not translating the RANGE of a property, for now, as the OWL semantics differs a lot
- ....from OCML, in this respect // (the html code was: ~% <rdfs:range rdf:resource=\"#~a\" /> )
|#
(in-package ocml)
;; creates the header, the top class definition and the closing stuff
(defun create-owl-onto (topclass prefix namespace your-path)
"Start function: sets up the translation constraints and creates the owl-headers"
(let* ((contents (calcont topclass))
(owl-onto
(format nil "~%<!DOCTYPE rdf:RDF [~% <!ENTITY ~a \"~a\" > ]> ~2% <rdf:RDF ~% xmlns =\"&~a;\"~% xmlns:~a =\"&~a;\"~% xml:base =\"&~a;\" ~% xmlns:owl =\"http://www.w3.org/2002/07/owl#\" ~% xmlns:rdf =\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" ~% xmlns:rdfs =\"http://www.w3.org/2000/01/rdf-schema#\" ~% xmlns:xsd =\"http://www.w3.org/2001/XMLSchema#\"> ~2%<owl:Ontology rdf:about=\"\"> ~% <rdfs:comment>A translated ontology from OCML to OWL</rdfs:comment> ~% <owl:priorVersion rdf:resource=\"\"/> ~%</owl:Ontology> ~2%<owl:Class rdf:ID=\"~a\">~% <rdfs:comment>~a~% </rdfs:comment>~%</owl:Class>~%~a~2%</rdf:RDF>~%"
prefix namespace prefix prefix prefix prefix topclass (ocml-documentation (get-ocml-class topclass)) contents)))
(with-open-file
(s your-path :direction :output :if-exists :supersede)
(format s owl-onto))))
(defun calcont (top-class)
"Main function that explores the tree"
(let ((result ""))
(if top-class
(loop for class in
(direct-subclasses (get-ocml-class top-class))
do
(setq result (format nil "~a~%<owl:Class rdf:ID=\"~a\">~% <rdfs:subClassOf rdf:resource=\"#~a\" />~%~a~% <rdfs:comment>~a~% </rdfs:comment>~%</owl:Class>~%~a~a"
result
(name class)
top-class
(format nil "~a~%" (build-class-restrictions (name class)))
(ocml-documentation class)
(format nil "~a~%" (build-owl-properties (name class)))
(calcont (name class))))))
result))
(defun build-class-restrictions (classname)
"Function that gets all the slots of a class, and transforms them into Owl-class-restrictions"
(let ((result ""))
(if classname
(loop for rel in
(ocml-eval-gen `(local-class-slots ,classname))
do
(setq result (format nil "~a~% <rdfs:subClassOf>~% <owl:Restriction>~% <owl:onProperty rdf:resource=\"#~a\"/>~% <owl:allValuesFrom>~% <owl:Class rdf:ID=\"~a\"/>~% </owl:allValuesFrom>~% </owl:Restriction>~% </rdfs:subClassOf>"
result
rel
(if ;; for now
(first (get-slot-type (get-ocml-class classname) rel))
(first (get-slot-type (get-ocml-class classname) rel))
classname) ;;if values an instance, puts back the class
))))
result))
(defun build-owl-properties (classname)
"Function that gets all the slots of a class, and transforms them into Owl-ObjectProperties"
(let ((result ""))
(if classname
(loop for rel in
(ocml-eval-gen `(local-class-slots ,classname))
do
(setq result (format nil "~a~%<owl:ObjectProperty rdf:ID=\"~a\">~% <rdfs:domain rdf:resource=\"#~a\" />~%</owl:ObjectProperty>"
result
rel
classname
;; (if ;; for now *
;; (first (get-slot-type (get-ocml-class classname) rel))
;; (first (get-slot-type (get-ocml-class classname) rel))
;; classname)
))))
result))
;; written by Michele Pasin
;; the translator at the moment is just a major help to port an ocml ontology to owl
;; you will probably have to manually review the ontology - see below for detail
#|
HOWTO:
1) load your ontology into OCML (translator works from within OCML)
2) compile&load the translator functions (this file)
3) call the translator with the appropriate arguments, e.g.
(create-owl-onto 'top-class-to-translate-from 'a-prefix "http://my-onto-namespace.owl" "local-path")
For example, in my case I used:
(create-owl-onto 'philosurfical-entity 'phil "http://philosurfical.open.ac.uk/ontology/philosurfical.owl" "/Users/michelepasin/Desktop/-last-translation.owl")
What it does:
- it can properly translate the TAXONOMY
- it creates a Protege'-compliant owl file
- it transforms all the ocml-classes slots into owl-OBJECT-PROPERTIES + owl-CLASS-RESTRICTIONS
...(interesting side-effect --> it helps checking the consistency of an OCML ontology!..typos, wrong args etc..)
What it doesn't do (for now):
- check for DATATYPEs, and translate them to XML-types
- translate complex restrictions
- translate contraints
- translate fixed values on ocml slots (in this case it outputs the same class as the property range)
- tanslate instances
- we are not translating the RANGE of a property, for now, as the OWL semantics differs a lot
- ....from OCML, in this respect // (the html code was: ~% <rdfs:range rdf:resource=\"#~a\" /> )
|#
(in-package ocml)
;; creates the header, the top class definition and the closing stuff
(defun create-owl-onto (topclass prefix namespace your-path)
"Start function: sets up the translation constraints and creates the owl-headers"
(let* ((contents (calcont topclass))
(owl-onto
(format nil "~%<!DOCTYPE rdf:RDF [~% <!ENTITY ~a \"~a\" > ]> ~2% <rdf:RDF ~% xmlns =\"&~a;\"~% xmlns:~a =\"&~a;\"~% xml:base =\"&~a;\" ~% xmlns:owl =\"http://www.w3.org/2002/07/owl#\" ~% xmlns:rdf =\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" ~% xmlns:rdfs =\"http://www.w3.org/2000/01/rdf-schema#\" ~% xmlns:xsd =\"http://www.w3.org/2001/XMLSchema#\"> ~2%<owl:Ontology rdf:about=\"\"> ~% <rdfs:comment>A translated ontology from OCML to OWL</rdfs:comment> ~% <owl:priorVersion rdf:resource=\"\"/> ~%</owl:Ontology> ~2%<owl:Class rdf:ID=\"~a\">~% <rdfs:comment>~a~% </rdfs:comment>~%</owl:Class>~%~a~2%</rdf:RDF>~%"
prefix namespace prefix prefix prefix prefix topclass (ocml-documentation (get-ocml-class topclass)) contents)))
(with-open-file
(s your-path :direction :output :if-exists :supersede)
(format s owl-onto))))
(defun calcont (top-class)
"Main function that explores the tree"
(let ((result ""))
(if top-class
(loop for class in
(direct-subclasses (get-ocml-class top-class))
do
(setq result (format nil "~a~%<owl:Class rdf:ID=\"~a\">~% <rdfs:subClassOf rdf:resource=\"#~a\" />~%~a~% <rdfs:comment>~a~% </rdfs:comment>~%</owl:Class>~%~a~a"
result
(name class)
top-class
(format nil "~a~%" (build-class-restrictions (name class)))
(ocml-documentation class)
(format nil "~a~%" (build-owl-properties (name class)))
(calcont (name class))))))
result))
(defun build-class-restrictions (classname)
"Function that gets all the slots of a class, and transforms them into Owl-class-restrictions"
(let ((result ""))
(if classname
(loop for rel in
(ocml-eval-gen `(local-class-slots ,classname))
do
(setq result (format nil "~a~% <rdfs:subClassOf>~% <owl:Restriction>~% <owl:onProperty rdf:resource=\"#~a\"/>~% <owl:allValuesFrom>~% <owl:Class rdf:ID=\"~a\"/>~% </owl:allValuesFrom>~% </owl:Restriction>~% </rdfs:subClassOf>"
result
rel
(if ;; for now
(first (get-slot-type (get-ocml-class classname) rel))
(first (get-slot-type (get-ocml-class classname) rel))
classname) ;;if values an instance, puts back the class
))))
result))
(defun build-owl-properties (classname)
"Function that gets all the slots of a class, and transforms them into Owl-ObjectProperties"
(let ((result ""))
(if classname
(loop for rel in
(ocml-eval-gen `(local-class-slots ,classname))
do
(setq result (format nil "~a~%<owl:ObjectProperty rdf:ID=\"~a\">~% <rdfs:domain rdf:resource=\"#~a\" />~%</owl:ObjectProperty>"
result
rel
classname
;; (if ;; for now *
;; (first (get-slot-type (get-ocml-class classname) rel))
;; (first (get-slot-type (get-ocml-class classname) rel))
;; classname)
))))
result))