1111package org .eclipse .rdf4j .sail .shacl .ast ;
1212
1313import java .util .ArrayList ;
14+ import java .util .Collections ;
1415import java .util .HashSet ;
16+ import java .util .LinkedHashSet ;
1517import java .util .List ;
1618import java .util .Objects ;
1719import java .util .Set ;
@@ -31,10 +33,10 @@ public class StatementMatcher {
3133 private final Variable <IRI > predicate ;
3234 private final Variable <? extends Value > object ;
3335
34- // private final Set<String> varNames;
36+ // private final Set<String> varNames;
3537 private final Targetable origin ;
3638
37- private final Set <String > inheritedVarNames ;
39+ private Set <String > inheritedVarNames ;
3840
3941 private List <StatementMatcher > subset = List .of ();
4042
@@ -216,37 +218,47 @@ private static String formatForToString(String field, String name, Value value)
216218
217219 private StatementMatcher swap (Variable <?> existingVariable , Variable <?> newVariable ) {
218220 String subjectName = getSubjectName ();
221+ String subjectBasename = getSubjectBasename ();
219222 Resource subjectValue = getSubjectValue ();
223+
220224 String predicateName = getPredicateName ();
225+ String predicateBasename = getPredicateBasename ();
221226 IRI predicateValue = getPredicateValue ();
227+
222228 String objectName = getObjectName ();
229+ String objectBasename = getObjectBasename ();
223230 Value objectValue = getObjectValue ();
231+
224232 boolean changed = false ;
225233
226234 if (Objects .equals (existingVariable .name , subjectName )
227235 && Objects .equals (existingVariable .value , subjectValue )) {
228236 changed = true ;
229237 subjectName = newVariable .name ;
230238 subjectValue = (Resource ) newVariable .value ;
239+ subjectBasename = newVariable .baseName ;
231240 }
232241
233242 if (Objects .equals (existingVariable .name , predicateName )
234243 && Objects .equals (existingVariable .value , predicateValue )) {
235244 changed = true ;
236245 predicateName = newVariable .name ;
237246 predicateValue = (IRI ) newVariable .value ;
247+ predicateBasename = newVariable .baseName ;
238248 }
239249
240250 if (Objects .equals (existingVariable .name , objectName ) && Objects .equals (existingVariable .value , objectValue )) {
241251 changed = true ;
242252 objectName = newVariable .name ;
243253 objectValue = newVariable .value ;
254+ objectBasename = newVariable .baseName ;
244255 }
245256
246257 if (changed ) {
247258 assert subset .isEmpty ();
248- return new StatementMatcher (new Variable <>(subjectName , subjectValue ),
249- new Variable <>(predicateName , predicateValue ), new Variable <>(objectName , objectValue ), origin ,
259+ return new StatementMatcher (new Variable <>(subjectName , subjectValue , subjectBasename ),
260+ new Variable <>(predicateName , predicateValue , predicateBasename ),
261+ new Variable <>(objectName , objectValue , objectBasename ), origin ,
250262 inheritedVarNames );
251263 }
252264 return this ;
@@ -268,6 +280,10 @@ public String getSubjectName() {
268280 return subject .name ;
269281 }
270282
283+ public String getSubjectBasename () {
284+ return subject .baseName ;
285+ }
286+
271287 public Resource getSubjectValue () {
272288 return subject .value ;
273289 }
@@ -280,6 +296,10 @@ public String getPredicateName() {
280296 return predicate .name ;
281297 }
282298
299+ public String getPredicateBasename () {
300+ return predicate .baseName ;
301+ }
302+
283303 public IRI getPredicateValue () {
284304 return predicate .value ;
285305 }
@@ -292,6 +312,10 @@ public String getObjectName() {
292312 return object .name ;
293313 }
294314
315+ public String getObjectBasename () {
316+ return object .baseName ;
317+ }
318+
295319 public Value getObjectValue () {
296320 return object .value ;
297321 }
@@ -376,13 +400,13 @@ public String getSparqlValuesDecl(Set<String> varNamesRestriction, boolean addIn
376400 return sb .toString ();
377401 }
378402
379- public Set <String > getVarNames (Set <String > varNamesRestriction , boolean addInheritedVarNames ,
403+ public LinkedHashSet <String > getVarNames (Set <String > varNamesRestriction , boolean addInheritedVarNames ,
380404 Set <String > varNamesInQueryFragment ) {
381405 if (varNamesRestriction .isEmpty ()) {
382- return Set . of ();
406+ return new LinkedHashSet <> ();
383407 }
384408
385- HashSet <String > ret = new HashSet <>();
409+ LinkedHashSet <String > ret = new LinkedHashSet <>();
386410 if (subject .name != null && varNamesRestriction .contains (subject .name )
387411 && varNamesInQueryFragment .contains (subject .name )) {
388412 ret .add (subject .name );
@@ -462,6 +486,26 @@ public boolean hasObject(Variable<Value> variable) {
462486 return variable .name .equals (object .name );
463487 }
464488
489+ public Set <String > getInheritedVarNames () {
490+ return Set .copyOf (inheritedVarNames );
491+ }
492+
493+ public Set <String > getVarNames () {
494+ Set <String > varNames = new HashSet <>();
495+
496+ if (subject .name != null ) {
497+ varNames .add (subject .name );
498+ }
499+ if (predicate .name != null ) {
500+ varNames .add (predicate .name );
501+ }
502+ if (object .name != null ) {
503+ varNames .add (object .name );
504+ }
505+
506+ return Collections .unmodifiableSet (varNames );
507+ }
508+
465509 public static class StableRandomVariableProvider {
466510
467511 // We just need a random base that isn't used elsewhere in the ShaclSail, but we don't want it to be stable so
@@ -485,9 +529,12 @@ public StableRandomVariableProvider(String prefix) {
485529 * increments of one.
486530 *
487531 * @param inputQuery the query string that should be normalized
532+ * @param union
488533 * @return a normalized query string
489534 */
490- public static String normalize (String inputQuery ) {
535+ public static String normalize (String inputQuery , List <? extends Variable > protectedVars ,
536+ List <StatementMatcher > union ) {
537+
491538 if (!inputQuery .contains (BASE )) {
492539 return inputQuery ;
493540 }
@@ -513,18 +560,30 @@ public static String normalize(String inputQuery) {
513560 if (lowest == 0 && incrementsOfOne ) {
514561 return inputQuery ;
515562 }
563+ String joinedProtectedVars = protectedVars .stream ()
564+ .map (Variable ::getName )
565+ .filter (Objects ::nonNull )
566+ .filter (s -> s .contains (BASE ))
567+ .collect (Collectors .joining ());
516568
517- return normalizeRange (inputQuery , lowest , highest );
569+ return normalizeRange (inputQuery , lowest , highest , joinedProtectedVars , union );
518570 }
519571
520- private static String normalizeRange (String inputQuery , int lowest , int highest ) {
572+ private static String normalizeRange (String inputQuery , int lowest , int highest , String joinedProtectedVars ,
573+ List <StatementMatcher > union ) {
521574
522575 String normalizedQuery = inputQuery ;
523576 for (int i = 0 ; i <= highest ; i ++) {
524- if (!normalizedQuery .contains (BASE + i + "_" )) {
577+ String replacement = BASE + i + "_" ;
578+ if (!normalizedQuery .contains (replacement )) {
525579 for (int j = Math .max (i + 1 , lowest ); j <= highest ; j ++) {
526- if (normalizedQuery .contains (BASE + j + "_" )) {
527- normalizedQuery = normalizedQuery .replace (BASE + j + "_" , BASE + i + "_" );
580+ String original = BASE + j + "_" ;
581+ if (normalizedQuery .contains (original )) {
582+ if (joinedProtectedVars .contains (original )) {
583+ continue ;
584+ }
585+ normalizedQuery = normalizedQuery .replace (original , replacement );
586+ replaceInStatementMatcher (union , original , replacement );
528587 break ;
529588 }
530589 }
@@ -534,6 +593,13 @@ private static String normalizeRange(String inputQuery, int lowest, int highest)
534593 return normalizedQuery ;
535594 }
536595
596+ private static void replaceInStatementMatcher (List <StatementMatcher > statementMatchers , String original ,
597+ String replacement ) {
598+ for (StatementMatcher statementMatcher : statementMatchers ) {
599+ statementMatcher .replaceVariableName (original , replacement );
600+ }
601+ }
602+
537603 public Variable <Value > next () {
538604 counter ++;
539605
@@ -552,6 +618,44 @@ public Variable<Value> current() {
552618 }
553619 }
554620
621+ private void replaceVariableName (String original , String replacement ) {
622+
623+ if (subject .name != null && subject .name .contains (original )) {
624+ subject .name = subject .name .replace (original , replacement );
625+ }
626+ if (subject .baseName != null && subject .baseName .contains (original )) {
627+ subject .baseName = subject .baseName .replace (original , replacement );
628+ }
629+ if (predicate .name != null && predicate .name .contains (original )) {
630+ predicate .name = predicate .name .replace (original , replacement );
631+ }
632+ if (predicate .baseName != null && predicate .baseName .contains (original )) {
633+ predicate .baseName = predicate .baseName .replace (original , replacement );
634+ }
635+ if (object .name != null && object .name .contains (original )) {
636+ object .name = object .name .replace (original , replacement );
637+ }
638+ if (object .baseName != null && object .baseName .contains (original )) {
639+ object .baseName = object .baseName .replace (original , replacement );
640+ }
641+
642+ boolean contains = false ;
643+ for (String inheritedVarName : inheritedVarNames ) {
644+ if (inheritedVarName .contains (original )) {
645+ contains = true ;
646+ break ;
647+ }
648+ }
649+ if (contains ) {
650+ HashSet <String > newInheritedVarNames = new HashSet <>();
651+ for (String inheritedVarName : inheritedVarNames ) {
652+ newInheritedVarNames .add (inheritedVarName .replace (original , replacement ));
653+ }
654+ inheritedVarNames = newInheritedVarNames ;
655+ }
656+
657+ }
658+
555659 public static class Variable <T extends Value > {
556660 public static final Variable <Value > VALUE = new Variable <>("value" );
557661 public static final Variable <Value > THIS = new Variable <>("this" );
@@ -576,6 +680,12 @@ public Variable(Variable<?> baseVariable, String name) {
576680 this .baseName = baseVariable .name ;
577681 }
578682
683+ public Variable (String name , T value , String baseName ) {
684+ this .name = name ;
685+ this .value = value ;
686+ this .baseName = baseName ;
687+ }
688+
579689 public Variable (T value ) {
580690 this .value = value ;
581691 }
0 commit comments