OWL2VOWL_work

feat: expose object property assertions as instances on relation

6/17/2026 8:14:38 AM

Details

diff --git a/src/main/java/de/uni_stuttgart/vis/vowl/owl2vowl/converter/AbstractConverter.java b/src/main/java/de/uni_stuttgart/vis/vowl/owl2vowl/converter/AbstractConverter.java
index 590e79b..35ad112 100644
--- a/src/main/java/de/uni_stuttgart/vis/vowl/owl2vowl/converter/AbstractConverter.java
+++ b/src/main/java/de/uni_stuttgart/vis/vowl/owl2vowl/converter/AbstractConverter.java
@@ -23,6 +23,7 @@ import de.uni_stuttgart.vis.vowl.owl2vowl.parser.vowl.property.VowlSubclassPrope
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.semanticweb.owlapi.model.IRI;
+import org.semanticweb.owlapi.model.AxiomType;
 import org.semanticweb.owlapi.model.OWLAnnotationAssertionAxiom;
 import org.semanticweb.owlapi.model.OWLAnnotationAxiom;
 import org.semanticweb.owlapi.model.OWLAnnotationProperty;
@@ -33,9 +34,12 @@ import org.semanticweb.owlapi.model.OWLClass;
 import org.semanticweb.owlapi.model.OWLClassAxiom;
 import org.semanticweb.owlapi.model.OWLDataProperty;
 import org.semanticweb.owlapi.model.OWLDataPropertyAxiom;
+import org.semanticweb.owlapi.model.OWLIndividual;
 import org.semanticweb.owlapi.model.OWLLiteral;
 import org.semanticweb.owlapi.model.OWLObjectProperty;
+import org.semanticweb.owlapi.model.OWLObjectPropertyAssertionAxiom;
 import org.semanticweb.owlapi.model.OWLObjectPropertyAxiom;
+import org.semanticweb.owlapi.model.OWLObjectPropertyExpression;
 import org.semanticweb.owlapi.model.OWLOntology;
 import org.semanticweb.owlapi.model.OWLOntologyCreationException;
 import org.semanticweb.owlapi.model.OWLOntologyManager;
@@ -229,10 +233,31 @@ public abstract class AbstractConverter implements Converter {
 		processObjectProperties(ontology, vowlData);
 		processDataProperties(ontology, vowlData);
 		processIndividuals(ontology, vowlData, manager);
+		processObjectPropertyAssertions(ontology, vowlData);
 
 		processGenericAxioms();
 	}
 
+	private void processObjectPropertyAssertions(OWLOntology ontology, VowlData vowlData) {
+		ontology.axioms(AxiomType.OBJECT_PROPERTY_ASSERTION, Imports.INCLUDED).forEach(axiom -> {
+			try {
+				OWLObjectPropertyExpression pe = axiom.getProperty();
+				if (pe.isAnonymous()) return;
+				VowlObjectProperty prop = vowlData.getObjectPropertyForIri(pe.asOWLObjectProperty().getIRI());
+				if (prop == null) return;
+				OWLIndividual subject = axiom.getSubject();
+				OWLIndividual object = axiom.getObject();
+				if (subject.isAnonymous() || object.isAnonymous()) return;
+				prop.addIndividualAssertion(
+					subject.asOWLNamedIndividual().getIRI(),
+					object.asOWLNamedIndividual().getIRI()
+				);
+			} catch (Exception e) {
+				logger.info("processObjectPropertyAssertions: Failed -> Skipping");
+			}
+		});
+	}
+
 	private void processIndividuals(OWLOntology ontology, VowlData vowlData, OWLOntologyManager manager) {
 		ontology.classesInSignature(Imports.INCLUDED).collect(Collectors.toSet()).forEach(owlClass -> {
 			for (OWLOntology owlOntology : manager.ontologies().collect(Collectors.toSet())) {
diff --git a/src/main/java/de/uni_stuttgart/vis/vowl/owl2vowl/export/JsonGeneratorVisitorImpl.java b/src/main/java/de/uni_stuttgart/vis/vowl/owl2vowl/export/JsonGeneratorVisitorImpl.java
index 7695217..d3719a5 100644
--- a/src/main/java/de/uni_stuttgart/vis/vowl/owl2vowl/export/JsonGeneratorVisitorImpl.java
+++ b/src/main/java/de/uni_stuttgart/vis/vowl/owl2vowl/export/JsonGeneratorVisitorImpl.java
@@ -222,6 +222,8 @@ public class JsonGeneratorVisitorImpl implements JsonGeneratorVisitor {
 		attributes.put("minCardinality", getCardinality(property.getMinCardinality()));
 		attributes.put("maxCardinality", getCardinality(property.getMaxCardinality()));
 		attributes.put("cardinality", getCardinality(property.getExactCardinality()));
+		attributes.put("instances", property.getIndividualAssertions().size());
+		attributes.put("individuals", createPropertyIndividualsJson(property.getIndividualAssertions()));
 		propertyList.add(object);
 		propertyAttributeList.add(attributes);
 	}
@@ -256,11 +258,24 @@ public class JsonGeneratorVisitorImpl implements JsonGeneratorVisitor {
 		attributes.put("minCardinality", getCardinality(property.getMinCardinality()));
 		attributes.put("maxCardinality", getCardinality(property.getMaxCardinality()));
 		attributes.put("cardinality", getCardinality(property.getExactCardinality()));
+		attributes.put("instances", property.getIndividualAssertions().size());
+		attributes.put("individuals", createPropertyIndividualsJson(property.getIndividualAssertions()));
 
 		propertyList.add(object);
 		propertyAttributeList.add(attributes);
 	}
 
+	private List<Object> createPropertyIndividualsJson(List<IRI[]> assertions) {
+		List<Object> list = new ArrayList<>();
+		for (IRI[] pair : assertions) {
+			Map<String, Object> entry = new HashMap<>();
+			entry.put("subject", pair[0].toString());
+			entry.put("object", pair[1].toString());
+			list.add(entry);
+		}
+		return list;
+	}
+
 	@Override
 	public void visit(VowlIndividual vowlIndividual) {
 		// Individuals not needed in json.
diff --git a/src/main/java/de/uni_stuttgart/vis/vowl/owl2vowl/model/entities/properties/AbstractProperty.java b/src/main/java/de/uni_stuttgart/vis/vowl/owl2vowl/model/entities/properties/AbstractProperty.java
index 863b3a1..23fa3b6 100644
--- a/src/main/java/de/uni_stuttgart/vis/vowl/owl2vowl/model/entities/properties/AbstractProperty.java
+++ b/src/main/java/de/uni_stuttgart/vis/vowl/owl2vowl/model/entities/properties/AbstractProperty.java
@@ -10,6 +10,9 @@ import de.uni_stuttgart.vis.vowl.owl2vowl.model.entities.AbstractEntity;
 import de.uni_stuttgart.vis.vowl.owl2vowl.model.visitor.VowlPropertyVisitor;
 import org.semanticweb.owlapi.model.IRI;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -19,6 +22,7 @@ public abstract class AbstractProperty extends AbstractEntity implements HasInve
 	private Set<IRI> domains = new SetWithoutNull<>();
 	private Set<IRI> ranges = new SetWithoutNull<>();
 	private Set<IRI> referencedIris = new SetWithoutNull<>();
+	private List<IRI[]> individualAssertions = new ArrayList<>();
 
 	// Merged entities used only for json generation!
 	private IRI mergedDomain;
@@ -113,17 +117,25 @@ public abstract class AbstractProperty extends AbstractEntity implements HasInve
 	}
 
 	
+	public void addIndividualAssertion(IRI subject, IRI object) {
+		individualAssertions.add(new IRI[]{subject, object});
+	}
+
+	public List<IRI[]> getIndividualAssertions() {
+		return Collections.unmodifiableList(individualAssertions);
+	}
+
 	@Override
 	public void releaseMemory() {
 		if (domains!=null) domains.clear();
 		if (ranges!=null) ranges.clear();
 		if (referencedIris!=null) referencedIris.clear();
-		
-		
-		domains 		= null;
-		ranges			= null;
-		referencedIris	= null;
-		
+		if (individualAssertions!=null) individualAssertions.clear();
+
+		domains 			= null;
+		ranges				= null;
+		referencedIris		= null;
+		individualAssertions= null;
 	}
 	
 	public abstract void accept(VowlPropertyVisitor visitor);