diff --git a/docs/SimpleEmployerExample.png b/docs/SimpleEmployerExample.png
index 4ba5f77..edd7c37 100644
Binary files a/docs/SimpleEmployerExample.png and b/docs/SimpleEmployerExample.png differ
diff --git a/docs/uml2semantics.qea b/docs/uml2semantics.qea
index 376f1ce..fa5c6a7 100644
Binary files a/docs/uml2semantics.qea and b/docs/uml2semantics.qea differ
diff --git a/src/main/scala/org/uml2semantics/model/UMLClassDiagram.scala b/src/main/scala/org/uml2semantics/model/UMLClassDiagram.scala
index 081d4fd..3f56fb3 100644
--- a/src/main/scala/org/uml2semantics/model/UMLClassDiagram.scala
+++ b/src/main/scala/org/uml2semantics/model/UMLClassDiagram.scala
@@ -554,12 +554,9 @@ case class UMLClass(classIdentity: UMLClassIdentity,
case class UMLClassAttributeDefinition(definition: String = "")
sealed trait UMLClassAttributeType
-
case class UMLXMLDataType(attributeType: SupportedDataType) extends UMLClassAttributeType
-
case class UMLClassIdentityType(attributeType: UMLClassIdentity) extends UMLClassAttributeType
-
-
+case class UMLEnumerationIdentityType(attributeType: UMLEnumerationIdentity) extends UMLClassAttributeType
case class CurieBasedUMLClassAttributeType(attributeType: Curie) extends UMLClassAttributeType
//case class UndefinedUMLClassAttributeType() extends UMLClassAttributeType
@@ -571,20 +568,25 @@ object UMLClassAttributeType:
def apply(s: String): UMLClassAttributeType =
logger.debug(s"s=$s ${Code.source}")
- require(UMLClassIdentity.findClassNamedElement(s).nonEmpty || SupportedDataType.unapply(s).nonEmpty
- || Curie.isCurieBasedOnConfiguredPrefix(s) || s.isEmpty,
- s"""A class attribute must have a type that is either a class, that has been specified,
+ require(UMLClassIdentity.findClassNamedElement(s).nonEmpty ||
+ UMLEnumerationIdentity.findEnumerationNamedElement(s).nonEmpty ||
+ SupportedDataType.unapply(s).nonEmpty ||
+ Curie.isCurieBasedOnConfiguredPrefix(s) ||
+ s.isEmpty,
+ s"""A class attribute must have a type that is either a class or enumeration, that has been specified,
or an XML data type or an curie based on a known prefix. Prefixes are specified using the -x option when running uml2semantics.
- "$s" is not recognised as either a class or an XML data type.""")
+ "$s" is not recognised as either a class or an enumeration or an XML data type.""")
UMLClassIdentity.findClassNamedElement(s) match
case Some(classNamedElement) => UMLClassIdentityType(classNamedElement)
- case None => SupportedDataType.unapply(s) match
- case Some(x) => UMLXMLDataType(x)
- case None =>
- val curieOption: Option[Curie] = Curie.unapply(s)
- curieOption match
- case Some(curie) => CurieBasedUMLClassAttributeType(curie)
- case None => UndefinedUMLClassAttributeType
+ case None => UMLEnumerationIdentity.findEnumerationNamedElement(s) match
+ case Some(enumerationNamedElement) => UMLEnumerationIdentityType(enumerationNamedElement)
+ case None => SupportedDataType.unapply(s) match
+ case Some(x) => UMLXMLDataType(x)
+ case None =>
+ val curieOption: Option[Curie] = Curie.unapply(s)
+ curieOption match
+ case Some(curie) => CurieBasedUMLClassAttributeType(curie)
+ case None => UndefinedUMLClassAttributeType
def unapply(s: String): Option[UMLClassAttributeType] =
logger.debug(s"s=$s ${Code.source}")
diff --git a/src/main/scala/org/uml2semantics/owl/UML2OWLWriter.scala b/src/main/scala/org/uml2semantics/owl/UML2OWLWriter.scala
index 53d2823..cf86123 100644
--- a/src/main/scala/org/uml2semantics/owl/UML2OWLWriter.scala
+++ b/src/main/scala/org/uml2semantics/owl/UML2OWLWriter.scala
@@ -87,6 +87,8 @@ class UML2OWLWriter(val umlClassDiagram: UMLClassDiagram):
owlProperty = createOWLDataProperty(umlClassAttribute, errorMessages, domain, attributeType)
case UMLClassIdentityType(attributeType) =>
owlProperty = createOWLObjectProperty(umlClassAttribute, errorMessages, domain, attributeType)
+ case UMLEnumerationIdentityType(attributeType) =>
+ owlProperty = createOWLObjectProperty(umlClassAttribute, errorMessages, domain, attributeType)
case CurieBasedUMLClassAttributeType(attributeType) =>
owlProperty = createOWLObjectPropertyBasedOnConfiguredPrefix(umlClassAttribute, errorMessages, domain, attributeType)
case UndefinedUMLClassAttributeType =>
@@ -157,6 +159,56 @@ class UML2OWLWriter(val umlClassDiagram: UMLClassDiagram):
case UMLMultiplicity(UMLInfiniteCardinality(_), UMLInfiniteCardinality(_)) =>
objectProperty
+ private def createOWLObjectProperty(umlClassAttribute: UMLClassAttribute,
+ errorMessages: mutable.Seq[String],
+ domain: OWLClass,
+ umlEnumerationIdentity: UMLEnumerationIdentity): OWLObjectProperty =
+ logger.debug(s"createOWLObjectProperty: umlClassAttribute=$umlClassAttribute, errorMessages = $errorMessages, " +
+ s"domain=$domain, umlEnumerationIdentity=$umlEnumerationIdentity ${Code.source}")
+ val objectProperty = dataFactory.getOWLObjectProperty(umlClassAttribute.attributeIdentity.attributeIRI.iri)
+ val domainChangeApplied = manager.addAxiom(ontology, dataFactory.getOWLObjectPropertyDomainAxiom(objectProperty, domain))
+ if domainChangeApplied != SUCCESSFULLY then
+ errorMessages :+ s"Domain axiom for object property ${objectProperty.getIRI} could not be added for " +
+ s"${umlClassAttribute.attributeIdentity.attributeIRI.iri}"
+ val rangeChangeApplied = manager.addAxiom(ontology, dataFactory.getOWLObjectPropertyRangeAxiom(objectProperty,
+ dataFactory.getOWLClass(umlEnumerationIdentity.enumerationIRI.iri)))
+ if rangeChangeApplied != SUCCESSFULLY then
+ errorMessages :+ s"Range axiom for data property ${objectProperty.getIRI} could not be added for " +
+ s"${umlClassAttribute.attributeIdentity.attributeIRI.iri}"
+ umlClassAttribute.multiplicity match
+ case UMLMultiplicity(UMLNonNegativeCardinality(minCardinality), UMLNonNegativeCardinality(maxCardinality)) =>
+ logger.trace(s"minCardinality=$minCardinality ${Code.source}")
+ val axiom =
+ if minCardinality == maxCardinality && minCardinality != 0 then
+ dataFactory.getOWLSubClassOfAxiom(domain, dataFactory.getOWLObjectExactCardinality(maxCardinality, objectProperty,
+ dataFactory.getOWLClass(umlEnumerationIdentity.enumerationIRI.iri)))
+ else if minCardinality > 0 then
+ dataFactory.getOWLSubClassOfAxiom(domain,
+ dataFactory.getOWLObjectIntersectionOf(
+ dataFactory.getOWLObjectMinCardinality(minCardinality, objectProperty,
+ dataFactory.getOWLClass(umlEnumerationIdentity.enumerationIRI.iri)),
+ dataFactory.getOWLObjectMaxCardinality(maxCardinality, objectProperty,
+ dataFactory.getOWLClass(umlEnumerationIdentity.enumerationIRI.iri))))
+ else
+ dataFactory.getOWLSubClassOfAxiom(domain, dataFactory.getOWLObjectMaxCardinality(maxCardinality, objectProperty,
+ dataFactory.getOWLClass(umlEnumerationIdentity.enumerationIRI.iri)))
+ if manager.addAxiom(ontology, axiom) != SUCCESSFULLY then
+ errorMessages :+ s"Could not add subclass axiom representing cardinalities [$minCardinality, $maxCardinality] for " +
+ s"${umlClassAttribute.attributeIdentity.attributeLabel}"
+ case UMLMultiplicity(UMLNonNegativeCardinality(minCardinality), UMLInfiniteCardinality(_)) =>
+ if minCardinality > 0 then
+ val axiom = dataFactory.getOWLSubClassOfAxiom(domain,
+ dataFactory.getOWLObjectMinCardinality(minCardinality, objectProperty,
+ dataFactory.getOWLClass(umlEnumerationIdentity.enumerationIRI.iri)))
+ if manager.addAxiom(ontology, axiom) != SUCCESSFULLY then
+ errorMessages :+ s"Could not add subclass axiom representing cardinalities for [$minCardinality, *]" +
+ s"${umlClassAttribute.attributeIdentity.attributeLabel}"
+ case UMLMultiplicity(UMLInfiniteCardinality(_), UMLNonNegativeCardinality(maxCardinality)) =>
+ errorMessages :+ s"Multiplicity error found with multiplicity = [*, $maxCardinality] for attribute = " +
+ s"${umlClassAttribute.attributeIdentity.attributeLabel}."
+ case UMLMultiplicity(UMLInfiniteCardinality(_), UMLInfiniteCardinality(_)) =>
+ objectProperty
+
private def createOWLObjectProperty(umlClassAttribute: UMLClassAttribute,
errorMessages: mutable.Seq[String],
domain: OWLClass): OWLObjectProperty =
diff --git a/src/main/scala/org/uml2semantics/reader/TSVReader.scala b/src/main/scala/org/uml2semantics/reader/TSVReader.scala
index d040b4e..dfc9227 100644
--- a/src/main/scala/org/uml2semantics/reader/TSVReader.scala
+++ b/src/main/scala/org/uml2semantics/reader/TSVReader.scala
@@ -79,8 +79,9 @@ def parseAttributes(maybeTsvFile: Option[File], ontologyPrefix: PrefixNamespace)
logger.trace(s"m = $m")
val classNamedElement = UMLClassIdentity.findClassNamedElement(m(ClassAttributesHeader.ClassName.toString))
+ val enumerationNamedElement = UMLEnumerationIdentity.findEnumerationNamedElement(m(ClassAttributesHeader.ClassName.toString))
logger.trace(s"classNamedElement = $classNamedElement")
- if classNamedElement.isDefined then
+ if classNamedElement.isDefined || enumerationNamedElement.isDefined then
logger.trace(s"mClassOrPrimitiveType.toString = {${m(ClassOrPrimitiveType.toString)}}")
val curieOption: Option[Curie] = if m(Curie.toString).contains(":") then
Some(org.uml2semantics.model.Curie(m(Curie.toString)))
@@ -191,14 +192,19 @@ def parseEnumerationValues(maybeTsvFile: Option[File], ontologyPrefix: PrefixNam
end parseEnumerationValues
def parseUMLClassDiagram(input: InputParameters): UMLClassDiagram =
+ var umlClasses = parseClasses(input.classesTsv, PrefixNamespace(input.ontologyPrefix))
+ var umlEnumerations = parseEnumerations(input.enumerationsTsv, PrefixNamespace(input.ontologyPrefix))
+ var umlAttributes = parseAttributes(input.attributesTsv, PrefixNamespace(input.ontologyPrefix))
+ var umlEnumerationValues = parseEnumerationValues(input.enumerationValuesTsv, PrefixNamespace(input.ontologyPrefix))
+
UMLClassDiagram(
input.owlOntologyFile.get,
OntologyIRI(input.ontologyIRI),
PrefixNamespace(input.ontologyPrefix),
- parseClasses(input.classesTsv, PrefixNamespace(input.ontologyPrefix)),
- parseAttributes(input.attributesTsv, PrefixNamespace(input.ontologyPrefix)),
- parseEnumerations(input.enumerationsTsv, PrefixNamespace(input.ontologyPrefix)),
- parseEnumerationValues(input.enumerationValuesTsv, PrefixNamespace(input.ontologyPrefix)))
+ umlClasses,
+ umlAttributes,
+ umlEnumerations,
+ umlEnumerationValues)
diff --git a/src/test/resources/Employer - Attributes.tsv b/src/test/resources/Employer - Attributes.tsv
index 40c6166..5e71708 100644
--- a/src/test/resources/Employer - Attributes.tsv
+++ b/src/test/resources/Employer - Attributes.tsv
@@ -3,4 +3,7 @@ Person name xsd:string
Person surname xsd:string
Person dateOfBirth xsd:dateTime
Employee employedBy Employer 1 1
-Employer employes Employee 1 *
\ No newline at end of file
+Employee renumeration Renumeration 1 1
+Employer employes Employee 1 *
+Renumeration rate xsd:decimal 1 1
+Renumeration paymentSchedule PaymentSchedule 1 1
\ No newline at end of file
diff --git a/src/test/resources/Employer - Classes.tsv b/src/test/resources/Employer - Classes.tsv
index bc27587..ee08db7 100644
--- a/src/test/resources/Employer - Classes.tsv
+++ b/src/test/resources/Employer - Classes.tsv
@@ -1,4 +1,5 @@
Curie Name Definition ParentNames
Person
Employee Person
- Employer Person
\ No newline at end of file
+ Employer Person
+ Renumeration
\ No newline at end of file
diff --git a/src/test/resources/employer.rdf b/src/test/resources/employer.rdf
index d566dd5..aa7665b 100644
--- a/src/test/resources/employer.rdf
+++ b/src/test/resources/employer.rdf
@@ -33,6 +33,17 @@
+
+
+
+
+
+
+ renumeration
+
+
+
+
@@ -44,6 +55,17 @@
+
+
+
+
+
+
+ paymentSchedule
+
+
+
+
+
+
+
+
+
+ rate
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+ 1
+
+
+
+ Renumeration
+
+
+
+