10
10
import org .apache .jena .graph .Triple ;
11
11
import org .apache .jena .graph .compose .Dyadic ;
12
12
import org .apache .jena .graph .compose .Polyadic ;
13
+ import org .apache .jena .graph .impl .WrappedGraph ;
13
14
import org .apache .jena .mem .GraphMem ;
14
15
import org .apache .jena .reasoner .InfGraph ;
15
16
import org .apache .jena .shared .PrefixMapping ;
17
+ import org .apache .jena .sparql .graph .GraphWrapper ;
16
18
import org .apache .jena .sparql .util .graph .GraphUtils ;
17
19
import org .apache .jena .util .iterator .ExtendedIterator ;
18
20
import org .apache .jena .util .iterator .NullIterator ;
@@ -58,7 +60,7 @@ public class Graphs {
58
60
*
59
61
* @param graph {@link Graph}
60
62
* @return {@code Stream} of {@link Graph}s
61
- * @see Graphs#getBase (Graph)
63
+ * @see Graphs#getPrimary (Graph)
62
64
* @see UnionGraph
63
65
* @see Polyadic
64
66
* @see Dyadic
@@ -77,12 +79,9 @@ public static Stream<Graph> directSubGraphs(Graph graph) {
77
79
}
78
80
79
81
/**
80
- * Extracts the base (primary) base graph from a composite or wrapper graph if it is possible
82
+ * Gets the base (primary) base graph from a composite or wrapper graph if it is possible
81
83
* otherwise returns the same graph.
82
84
* If the specified graph is {@link Dyadic}, the left part is considered as base graph.
83
- * Note: wrappers ({@link org.apache.jena.graph.impl.WrappedGraph} and {@link org.apache.jena.sparql.graph.GraphWrapper})
84
- * are intentionally not included in the consideration:
85
- * any sub-instances of that class are considered as indivisible.
86
85
*
87
86
* @param graph {@link Graph}
88
87
* @return {@link Graph}
@@ -91,9 +90,37 @@ public static Stream<Graph> directSubGraphs(Graph graph) {
91
90
* @see org.apache.jena.graph.compose.MultiUnion
92
91
* @see Polyadic
93
92
* @see Dyadic
93
+ */
94
+ public static Graph getPrimary (Graph graph ) {
95
+ if (graph instanceof UnionGraph ) {
96
+ return ((UnionGraph ) graph ).getBaseGraph ();
97
+ }
98
+ if (graph instanceof Polyadic ) {
99
+ return ((Polyadic ) graph ).getBaseGraph ();
100
+ }
101
+ if (graph instanceof Dyadic ) {
102
+ return ((Dyadic ) graph ).getL ();
103
+ }
104
+ return graph ;
105
+ }
106
+
107
+ /**
108
+ * Unwraps the base (primary) base graph from a composite or wrapper graph if it is possible
109
+ * otherwise returns the same graph.
110
+ * If the specified graph is {@link Dyadic}, the left part is considered as base graph.
111
+ *
112
+ * @param graph {@link Graph}
113
+ * @return {@link Graph}
114
+ * @see #isWrapper(Graph)
115
+ * @see UnionGraph
116
+ * @see org.apache.jena.graph.compose.MultiUnion
117
+ * @see Polyadic
118
+ * @see Dyadic
94
119
* @see InfGraph
120
+ * @see GraphWrapper
121
+ * @see WrappedGraph
95
122
*/
96
- public static Graph getBase (Graph graph ) {
123
+ public static Graph unwrap (Graph graph ) {
97
124
if (isGraphMem (graph )) {
98
125
return graph ;
99
126
}
@@ -105,6 +132,14 @@ public static Graph getBase(Graph graph) {
105
132
if (!seen .add (g )) {
106
133
continue ;
107
134
}
135
+ if (g instanceof GraphWrapper ) {
136
+ candidates .add (((GraphWrapper ) g ).get ());
137
+ continue ;
138
+ }
139
+ if (g instanceof WrappedGraph ) {
140
+ candidates .add (((WrappedGraph ) g ).getWrapped ());
141
+ continue ;
142
+ }
108
143
if (g instanceof UnionGraph ) {
109
144
candidates .add (((UnionGraph ) g ).getBaseGraph ());
110
145
continue ;
@@ -125,6 +160,22 @@ public static Graph getBase(Graph graph) {
125
160
return graph ;
126
161
}
127
162
163
+ /**
164
+ * Answers {@code true} if the given graph can be unwrapped.
165
+ *
166
+ * @param g {@link Graph}
167
+ * @return boolean
168
+ * @see #unwrap(Graph)
169
+ */
170
+ public static boolean isWrapper (Graph g ) {
171
+ return g instanceof GraphWrapper ||
172
+ g instanceof WrappedGraph ||
173
+ g instanceof UnionGraph ||
174
+ g instanceof Polyadic ||
175
+ g instanceof Dyadic ||
176
+ g instanceof InfGraph ;
177
+ }
178
+
128
179
/**
129
180
* Answers {@code true} if the graph specified is {@code GraphMem}.
130
181
*
@@ -154,6 +205,20 @@ public static boolean isGraphInf(Graph graph) {
154
205
* @return {@code Stream} of {@link Graph}s
155
206
*/
156
207
public static Stream <Graph > dataGraphs (Graph graph ) {
208
+ return flatTree (graph , Graphs ::unwrap , Graphs ::directSubGraphs );
209
+ }
210
+
211
+ /**
212
+ * Lists all indivisible data graphs extracted from the composite or wrapper graph;
213
+ *
214
+ * @param graph {@link Graph}
215
+ * @param getBase a {@link Function} to extract primary graph
216
+ * @param listSubGraphs a {@link Function} to extract subgraphs
217
+ * @return {@code Stream} of {@link Graph}s
218
+ */
219
+ public static Stream <Graph > flatTree (Graph graph ,
220
+ Function <Graph , Graph > getBase ,
221
+ Function <Graph , Stream <Graph >> listSubGraphs ) {
157
222
if (graph == null ) {
158
223
return Stream .empty ();
159
224
}
@@ -169,9 +234,9 @@ public static Stream<Graph> dataGraphs(Graph graph) {
169
234
if (!seen .add (g )) {
170
235
continue ;
171
236
}
172
- Graph bg = getBase (g );
237
+ Graph bg = getBase . apply (g );
173
238
res .add (bg );
174
- directSubGraphs (g ).forEach (queue ::add );
239
+ listSubGraphs . apply (g ).forEach (queue ::add );
175
240
}
176
241
return res .stream ();
177
242
}
@@ -184,7 +249,7 @@ public static Stream<Graph> dataGraphs(Graph graph) {
184
249
* @return {@code boolean}
185
250
*/
186
251
public static boolean isSameBase (Graph left , Graph right ) {
187
- return Objects .equals (getBase (left ), getBase (right ));
252
+ return Objects .equals (unwrap (left ), unwrap (right ));
188
253
}
189
254
190
255
/**
@@ -203,7 +268,7 @@ public static boolean isDistinct(Graph graph) {
203
268
}
204
269
if (graph instanceof UnionGraph ) {
205
270
UnionGraph u = (UnionGraph ) graph ;
206
- return u .isDistinct () || !u .hasSubGraph () && isDistinct (getBase (u ));
271
+ return u .isDistinct () || !u .hasSubGraph () && isDistinct (getPrimary (u ));
207
272
}
208
273
return false ;
209
274
}
@@ -226,7 +291,7 @@ public static boolean isSized(Graph graph) {
226
291
if (directSubGraphs (graph ).findFirst ().isPresent ()) {
227
292
return false ;
228
293
}
229
- return isGraphMem (getBase (graph ));
294
+ return isGraphMem (getPrimary (graph ));
230
295
}
231
296
232
297
/**
@@ -243,7 +308,7 @@ public static long size(Graph graph) {
243
308
if (directSubGraphs (graph ).findFirst ().isPresent ()) {
244
309
return Iterators .count (graph .find ());
245
310
}
246
- return getBase (graph ).size ();
311
+ return getPrimary (graph ).size ();
247
312
}
248
313
249
314
/**
@@ -262,7 +327,7 @@ public static UnionGraph makeOntUnionFrom(Graph graph, Function<Graph, UnionGrap
262
327
if (isGraphMem (graph )) {
263
328
return wrapAsUnion .apply (graph );
264
329
}
265
- return makeOntUnion (getBase (graph ), dataGraphs (graph ).collect (Collectors .toSet ()), wrapAsUnion );
330
+ return makeOntUnion (getPrimary (graph ), dataGraphs (graph ).collect (Collectors .toSet ()), wrapAsUnion );
266
331
}
267
332
268
333
/**
@@ -314,14 +379,14 @@ public static UnionGraph makeOntUnion(Graph graph,
314
379
}
315
380
316
381
/**
317
- * Lists all graphs in the tree which is specified as {@code UnionGraph}.
382
+ * Lists all graphs in the tree that is specified as {@code UnionGraph}.
318
383
*
319
384
* @param graph {@link UnionGraph}
320
385
* @return {@code Stream} of {@link UnionGraph}s
321
386
* @see UnionGraph#superGraphs()
322
387
* @see UnionGraph#subGraphs()
323
388
*/
324
- public static Stream <UnionGraph > flatTree (UnionGraph graph ) {
389
+ public static Stream <UnionGraph > flatHierarchy (UnionGraph graph ) {
325
390
Objects .requireNonNull (graph );
326
391
Set <UnionGraph > res = new LinkedHashSet <>();
327
392
Deque <UnionGraph > queue = new ArrayDeque <>();
@@ -415,21 +480,40 @@ public static Node createOntologyHeaderNode(Graph graph, String uriOrNull) {
415
480
}
416
481
417
482
/**
418
- * Creates a new ontology header ({@code node rdf:type owl:Ontology}) for the specified node,
483
+ * Creates (if absents) a new ontology header ({@code node rdf:type owl:Ontology}) for the specified node,
419
484
* removing existing ontology headers (if any) and moving their contents to the new header.
485
+ * Note that a valid ontology must have a single header,
486
+ * but there could be multiple headers in imports closure.
420
487
*
421
488
* @param graph {@link Graph}
422
489
* @param newOntology {@link Node} the new ontology header (iri or blank)
423
490
* @return {@code newOntology}
424
491
*/
425
492
public static Node makeOntologyHeaderNode (Graph graph , Node newOntology ) {
426
- List <Triple > prev = Iterators .addAll (Iterators .flatMap (
493
+ Objects .requireNonNull (graph , "graph is null" );
494
+ Objects .requireNonNull (newOntology , "ontology node is null" );
495
+ Set <Triple > prev = Iterators .addAll (Iterators .flatMap (
427
496
graph .find (Node .ANY , RDF .type .asNode (), OWL .Ontology .asNode ()),
428
- it -> graph .find (it .getSubject (), Node .ANY , Node .ANY )), new ArrayList <>());
429
-
430
- prev .forEach (graph ::delete );
431
- graph .add (newOntology , RDF .type .asNode (), OWL .Ontology .asNode ());
432
- prev .forEach (triple -> graph .add (newOntology , triple .getPredicate (), triple .getObject ()));
497
+ it -> graph .find (it .getSubject (), Node .ANY , Node .ANY )), new HashSet <>());
498
+ Set <Node > subjects = prev .stream ().map (Triple ::getSubject ).collect (Collectors .toSet ());
499
+ if (subjects .contains (newOntology )) {
500
+ if (subjects .size () == 1 ) {
501
+ // nothing to do
502
+ return newOntology ;
503
+ }
504
+ } else {
505
+ graph .add (newOntology , RDF .type .asNode (), OWL .Ontology .asNode ());
506
+ }
507
+ prev .forEach (t -> {
508
+ if (!newOntology .equals (t .getSubject ())) {
509
+ graph .delete (t );
510
+ }
511
+ });
512
+ prev .forEach (t -> {
513
+ if (!newOntology .equals (t .getSubject ())) {
514
+ graph .add (newOntology , t .getPredicate (), t .getObject ());
515
+ }
516
+ });
433
517
return newOntology ;
434
518
}
435
519
@@ -713,7 +797,7 @@ public static Node createNode(String iri) {
713
797
}
714
798
715
799
/**
716
- * Answers {@code true} if all parts of the given RDF triple are URIs (i.e. not blank nodes or literals).
800
+ * Answers {@code true} if all parts of the given RDF triple are URIs (i.e., not blank nodes or literals).
717
801
*
718
802
* @param triple a regular graph {@link Triple}, not {@code null}
719
803
* @return {@code boolean}
0 commit comments