Skip to content

Commit c02bad8

Browse files
committed
Dev: Ontology Properties in .ttl output now squashes equivalent properties and their corresponding subjects/objects to give a common type, or shows all ranges/domains of the property.
2 parents f71c7e3 + 4a23cdc commit c02bad8

3 files changed

Lines changed: 115 additions & 31 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# Created by .ignore support plugin (hsz.mobi)
22
out/
33
.idea/
4-
DrawingTurtles.iml
4+
src/META-INF/

src/model/conceptual/Vertex.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,12 +341,25 @@ public String getRdfsComment() {
341341
* @return the datatype of the Vertex, in angle-brackets if it is a fully-qualified IRI.
342342
*/
343343
public String getDataType() {
344-
if (dataType == null) return null;
344+
if (this.elementType == GraphElemType.GLOBAL_LITERAL){
345+
final String ints = "[+\\-]?\\d";
346+
347+
if (name.matches("\".*\"")) return "xsd:string";
348+
else if (name.matches("true|false")) return "xsd:boolean";
349+
else if (name.matches(ints+"+")) return "xsd:integer";
350+
else if (name.matches(ints+"*\\.\\d+")) return "xsd:decimal";
351+
else if (name.matches("("+ints+"+\\.\\d+|[+\\-]?\\.\\d+|"+ints+")E"+ints+"+")) return "xsd:double";
352+
else if (name.matches(".*\\^\\^.*")) return name.split("\\^\\^")[1];
353+
else return null;
354+
}
345355

356+
if (dataType == null)
357+
return null;
346358
else if (dataType.matches("http(s)?:.*") && elementType != GraphElemType.CLASS)
347359
return "<" + dataType + ">";
348360
else if (this.elementType != GraphElemType.CLASS)
349361
return dataType;
350-
else return null;
362+
else
363+
return null;
351364
}
352365
}

src/model/conversion/ttl/Converter.java

Lines changed: 99 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package model.conversion.ttl;
22

3+
import javafx.util.Pair;
34
import model.conceptual.Edge;
45
import model.conceptual.Vertex;
56

@@ -79,7 +80,6 @@ private static String getFixes() {
7980
fixString.append(".\n");
8081
}
8182

82-
//
8383
Stream<String> ttlClassPrefixesStream = classes.stream()
8484
.filter(c -> c.getElementType() == Vertex.GraphElemType.CLASS && !c.isIri())
8585
.map(c -> c.getName().split(":")[0]);
@@ -88,6 +88,7 @@ private static String getFixes() {
8888
.map(p -> p.getName().split(":")[0]);
8989
Set<String> ttlPrefixSet = Stream
9090
.concat(ttlClassPrefixesStream, ttlPropPrefixesStream)
91+
.filter(p -> !p.equals("_"))
9192
.collect(Collectors.toCollection(HashSet::new));
9293
Set<String> addedPrefixesSet = prefixes.keySet();
9394

@@ -134,6 +135,7 @@ private static String convertPrefixes() {
134135

135136
/**
136137
* Conversion of graph properties into .ttl representation.
138+
* Finds properties that are common, for example two 'foaf:knows', and determines the common type between them.
137139
* @return the properties as a valid .tll string.
138140
*/
139141
private static String convertGProperties() {
@@ -145,38 +147,107 @@ private static String convertGProperties() {
145147
"##################################################\n\n"
146148
);
147149

150+
// Map from the common property name to the associated subject/object pairs.
151+
HashMap<String, ArrayList<Pair<Vertex, Vertex>>> commonProperties = new HashMap<>();
148152
for (Edge property : properties){
149-
String propStr;
150-
String prop = property.getName();
151-
String obj = property.getObject().getName();
152-
String sub = property.getSubject().getName();
153-
154-
String subType = null;
155-
String objType = null;
156-
String ints = "[+\\-]?\\d";
157-
158-
if (obj.matches("\".*\"")) objType = "xsd:string";
159-
else if (obj.matches("true|false")) objType = "xsd:boolean";
160-
else if (obj.matches(ints+"+")) objType = "xsd:integer";
161-
else if (obj.matches(ints+"*\\.\\d+")) objType = "xsd:decimal";
162-
else if (obj.matches("("+ints+"+\\.\\d+|[+\\-]?\\.\\d+|"+ints+")E"+ints+"+")) objType = "xsd:double";
163-
else if (obj.matches(".*\\^\\^.*")) objType = obj.split("\\^\\^")[1];
164-
165-
if (sub.matches("\".*\"")) subType = "xsd:string";
166-
else if (sub.matches("true|false")) subType = "xsd:boolean";
167-
else if (sub.matches(ints+"+")) subType = "xsd:integer";
168-
else if (sub.matches(ints+"*\\.\\d+")) subType = "xsd:decimal";
169-
else if (sub.matches("("+ints+"+\\.\\d+|[+\\-]?\\.\\d+|"+ints+")E"+ints+"+")) subType = "xsd:double";
170-
else if (sub.matches(".*\\^\\^.*")) subType = sub.split("\\^\\^")[1];
171-
172-
propStr = prop + " rdf:type owl:ObjectProperty ;\n\t" +
173-
"rdfs:domain " + (subType == null ? sub : subType) + " ;\n\t" +
174-
"rdfs:range " + (objType == null ? obj : objType) + " .\n";
175-
propStrs.append(propStr);
153+
Vertex sub = property.getSubject();
154+
Vertex obj = property.getObject();
155+
String propertyName = property.getName();
156+
157+
// rdf:type is explicitly domain rdfs:Resource, range rdfs:Class. No need to constrain.
158+
if (propertyName.equals("a")) continue;
159+
160+
if (commonProperties.containsKey(propertyName))
161+
commonProperties.get(propertyName).add(new Pair<>(sub, obj));
162+
else {
163+
ArrayList<Pair<Vertex, Vertex>> pairs = new ArrayList<>();
164+
165+
pairs.add(new Pair<>(sub, obj));
166+
commonProperties.put(propertyName, pairs);
167+
}
176168
}
169+
170+
commonProperties.forEach((prop, subObjPairs) -> propStrs.append(getDomainAndRange(prop, subObjPairs)));
171+
177172
return propStrs.toString();
178173
}
179174

175+
/**
176+
* Finds the rdfs:domain and rdfs:range of the given propName.
177+
* Squashes all subjects/objects that have the same type together, and attempts to find a common base type.
178+
* For example:
179+
* a:T foaf:knows a:P ;
180+
* foaf:knows a:Q .
181+
* a:P a a:R .
182+
* a:Q a a:R .
183+
* The domain would be a:T, and the range a:R.
184+
* If there is no base type, it lists all of the types.
185+
* For example:
186+
* a:T foaf:knows a:P ;
187+
* foaf:knows a:Q .
188+
* a:P a a:R .
189+
* a:Q a a:S .
190+
* The domain would be a:T, and the range a:R, a:S;
191+
* @param propName the name of the property.
192+
* @param subObjPairs the subject/object pairs of the given property.
193+
* @return the .ttl representation of the domain and range of the property.
194+
*/
195+
private static String getDomainAndRange(String propName, ArrayList<Pair<Vertex, Vertex>> subObjPairs) {
196+
StringBuilder propStr = new StringBuilder(propName + " rdf:type owl:ObjectProperty ;\n\t");
197+
198+
ArrayList<Vertex> subs = new ArrayList<>();
199+
ArrayList<Vertex> objs = new ArrayList<>();
200+
subObjPairs.forEach(p -> {
201+
subs.add(p.getKey());
202+
objs.add(p.getValue());
203+
});
204+
205+
HashSet<String> commonSubTypeDefinitions = subs.stream().map(Vertex::getTypeDefinition).filter(Objects::nonNull).collect(Collectors.toCollection(HashSet::new));
206+
HashSet<String> commonObjTypeDefinitions = objs.stream().map(Vertex::getTypeDefinition).filter(Objects::nonNull).collect(Collectors.toCollection(HashSet::new));
207+
HashSet<String> commonSubDataTypes = subs.stream().map(Vertex::getDataType).filter(Objects::nonNull).collect(Collectors.toCollection(HashSet::new));
208+
HashSet<String> commonObjDataTypes = objs.stream().map(Vertex::getDataType).filter(Objects::nonNull).collect(Collectors.toCollection(HashSet::new));
209+
HashSet<String> commonSubNames = subs.stream().map(Vertex::getName).collect(Collectors.toCollection(HashSet::new));
210+
HashSet<String> commonObjNames = objs.stream().map(Vertex::getName).collect(Collectors.toCollection(HashSet::new));
211+
212+
propStr.append("rdfs:domain ");
213+
if (commonSubTypeDefinitions.size() > 0){
214+
propStr.append(commonSubTypeDefinitions.size() != 1 ? "\n\t\t" : "");
215+
commonSubTypeDefinitions.forEach(typedef -> propStr.append(typedef).append(" ,\n\t\t"));
216+
propStr.delete(propStr.length() - 4, propStr.length());
217+
propStr.append(";\n\t");
218+
} else if (commonSubDataTypes.size() > 0){
219+
propStr.append(commonSubDataTypes.size() != 1 ? "\n\t\t" : "");
220+
commonSubDataTypes.forEach(datatype -> propStr.append(datatype).append(" ,\n\t\t"));
221+
propStr.delete(propStr.length() - 4, propStr.length());
222+
propStr.append(";\n\t");
223+
} else {
224+
propStr.append(commonSubNames.size() != 1 ? "\n\t\t" : "");
225+
commonSubNames.forEach(s -> propStr.append(s).append(" ,\n\t\t"));
226+
propStr.delete(propStr.length() - 4, propStr.length());
227+
propStr.append(";\n\t");
228+
}
229+
230+
propStr.append("rdfs:range ");
231+
if (commonObjTypeDefinitions.size() > 0){
232+
propStr.append(commonObjTypeDefinitions.size() != 1 ? "\n\t\t" : "");
233+
commonObjTypeDefinitions.forEach(typedef -> propStr.append(typedef).append(" ,\n\t\t"));
234+
propStr.delete(propStr.length() - 4, propStr.length());
235+
propStr.append(".\n");
236+
} else if (commonObjDataTypes.size() > 0){
237+
propStr.append(commonObjDataTypes.size() != 1 ? "\n\t\t" : "");
238+
commonObjDataTypes.forEach(datatype -> propStr.append(datatype).append(" ,\n\t\t"));
239+
propStr.delete(propStr.length() - 4, propStr.length());
240+
propStr.append(".\n");
241+
} else {
242+
propStr.append(commonObjNames.size() != 1 ? "\n\t\t" : "");
243+
commonObjNames.forEach(o -> propStr.append(o).append(" ,\n\t\t"));
244+
propStr.delete(propStr.length() - 4, propStr.length());
245+
propStr.append(".\n");
246+
}
247+
248+
return propStr.toString();
249+
}
250+
180251
/**
181252
* Comversion of visual Classes and Literals into their .ttl string equivalent.
182253
* @return the converted Classes and Literals into thier .ttl equivalent.

0 commit comments

Comments
 (0)