11package model .conversion .ttl ;
22
3+ import javafx .util .Pair ;
34import model .conceptual .Edge ;
45import 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