From 0077fa3983984b6a9f1951581391ecdd936cbf98 Mon Sep 17 00:00:00 2001 From: Simon Steyskal Date: Tue, 4 Nov 2025 09:20:02 +0100 Subject: [PATCH 01/16] refactor: rename union/minus node expressions to join/remove in node expression spec --- shacl12-node-expr/index.html | 50 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/shacl12-node-expr/index.html b/shacl12-node-expr/index.html index 0178d369..276f9bce 100644 --- a/shacl12-node-expr/index.html +++ b/shacl12-node-expr/index.html @@ -812,10 +812,10 @@

List Expressions

The following example declares a property for instances of rdfs:Class where the values are derived from the values of the path rdfs:subClassOf* but with the constants from the list ( owl:Thing rdfs:Resource ) removed using - shnex:minus. + shnex:remove.

-

@@ -1676,6 +1732,33 @@

Remove Expressions

shnex:remove [ shnex:pathValues ex:authorOnLeave ] ; ] . + +
+

+ Evaluation trace: +

+

+ The evaluation proceeds as follows: +

+
    +
  1. + shnex:nodes [shnex:pathValues ex:author] with focus node ex:PublisherA + produces: [ex:Author1, ex:Author1, ex:Author1, ex:Author2, ex:Author2] +
  2. +
  3. + shnex:remove [shnex:pathValues ex:authorOnLeave] with focus node ex:PublisherA + produces: [ex:Author1, ex:Author1] +
  4. +
  5. + Remove all occurrences of ex:Author1 from the nodes list, preserving order: + [ex:Author2, ex:Author2] +
  6. +
+

+ More abstractly, removing [1, 1] from [1, 1, 1, 2, 2] results in [2, 2] + because all instances of 1 are removed (not just the first occurrence). +

+
@@ -1936,74 +2019,94 @@

OrderBy Expressions

-
-

Advanced Sequence Operations

- -
-

FlatMap Expressions

-

- - A blank node that is the subject of the following properties - is called a flatMap expression, - with the function name shnex:FlatMapExpression: - - - - - - - - - - - - - - - - - - -
PropertyConstraintsDescription
shnex:flatMap - A well-formed node expression. - - The node expression that is applied to each input node. -
shnex:nodes - A well-formed node expression. - - The input nodes. If omitted, defaults to the focus node. -
-
-

-
-
EVALUATION OF FLATMAP EXPRESSIONS
-

- Let flatMap be the value of shnex:flatMap - and nodes be the value of shnex:nodes in a flatMap expression. - If shnex:nodes is not specified, let nodes be the focus node. - Let N be the output nodes of evalExpr(nodes, focusGraph, focusNode, scope). - For each node n in N, let M be the output nodes of - evalExpr(flatMap, focusGraph, n, scope). - The output nodes of the flatMap expression are produced by concatenating all sequences - M_n in the order of the corresponding nodes n in N. -

-
-

The remainder of this section is informative.

-

- The shnex:flatMap operation applies an expression to each input node and flattens the results - into a single sequence. This is particularly useful when combining results from multiple path traversals - or when working with nested structures. -

-

- The following example illustrates the use of shnex:flatMap to derive a property - ex:allSkills that collects all skills from all employees of a company. - The flatMap operation applies a path expression to each employee and flattens the resulting - skill sequences into a single comprehensive list. -

-

-

+
    +
  1. + shnex:nodes [shnex:pathValues ex:employee] with focus node ex:CompanyA + produces: [ex:Employee1, ex:Employee2, ex:Employee3] +
  2. +
  3. + For each employee n, evaluate shnex:flatMap [shnex:pathValues ex:skill] + with focus node n: +
      +
    • ex:Employee1["Java", "Python", "SQL"]
    • +
    • ex:Employee2["Python", "JavaScript"]
    • +
    • ex:Employee3["Java", "DevOps"]
    • +
    +
  4. +
  5. + Combine all results in order: + ["Java", "Python", "SQL", "Python", "JavaScript", "Java", "DevOps"] +
  6. +
  7. Optional: Refine the resulting sequence using for example: +
      +
    • + shnex:distinct to remove duplicates from the flattened result. +
    • +
    • + shnex:filterShape to apply an additional shape constraint to the + flattened nodes. +
    • +
    • + shnex:limit to restrict the flattened result to the first N nodes. +
    • + +
    + +
  8. +
+ + + + + + + +
+

FindFirst Expressions

@@ -2102,12 +2268,12 @@

FindFirst Expressions

sh:class ex:Employee ; sh:maxCount 1 ; sh:name "senior employee" ; - sh:values [ + sh:values [ shnex:nodes [ shnex:pathValues ex:employee ; ] ; shnex:findFirst ex:SeniorEmployeeShape ; - ] . + ] . ex:SeniorEmployeeShape a sh:NodeShape ; @@ -2117,9 +2283,7 @@

FindFirst Expressions

sh:minInclusive 5 ; ] . -
- -
+

@@ -2198,12 +2362,12 @@

MatchAll Expressions

sh:datatype xsd:boolean ; sh:maxCount 1 ; sh:name "all employees active" ; - sh:values [ + sh:values [ shnex:nodes [ shnex:pathValues ex:employee ; ] ; shnex:matchAll ex:ActiveEmployeeShape ; - ] . + ] . ex:ActiveEmployeeShape a sh:NodeShape ; @@ -2212,9 +2376,7 @@

MatchAll Expressions

sh:hasValue true ; ] . -
- -
+

From de6bc3609a27f4c5da87c05507cd6fa6b3b093a2 Mon Sep 17 00:00:00 2001 From: Simon Steyskal Date: Tue, 18 Nov 2025 11:44:43 +0100 Subject: [PATCH 15/16] fix: update deprecation comments for sh:union to reference shnex:concat --- shacl12-vocabularies/shacl.ttl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shacl12-vocabularies/shacl.ttl b/shacl12-vocabularies/shacl.ttl index 7e92bfbf..bf3c7291 100644 --- a/shacl12-vocabularies/shacl.ttl +++ b/shacl12-vocabularies/shacl.ttl @@ -1848,7 +1848,7 @@ sh:intersection rdfs:comment "Deprecated with SHACL 1.2: replaced by shnex:intersection."@en . sh:union - rdfs:comment "Deprecated with SHACL 1.2: replaced by shnex:join."@en . + rdfs:comment "Deprecated with SHACL 1.2: replaced by shnex:concat."@en . sh:minus rdfs:comment "Deprecated with SHACL 1.2: replaced by shnex:remove."@en . From f0a82d39aca3c3aeb912d2175571ecf8ced891b6 Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 1 Dec 2025 06:43:39 +0100 Subject: [PATCH 16/16] Apply suggestions from code review Co-authored-by: Ted Thibodeau Jr Co-authored-by: Holger Knublauch --- shacl12-node-expr/index.html | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/shacl12-node-expr/index.html b/shacl12-node-expr/index.html index 7c43d712..834f97f4 100644 --- a/shacl12-node-expr/index.html +++ b/shacl12-node-expr/index.html @@ -1128,7 +1128,7 @@

List Expressions

] ; # This removes any superclasses that are in the list below shnex:remove ( owl:Thing rdfs:Resource ) ; - ] . + ] . @@ -1708,7 +1708,7 @@

Remove Expressions

The remainder of this section is informative.

- The following example declares a derived property ex:availableAuthors + The following example declares a derived property, ex:availableAuthors, that returns all persons who are authors, except those who are currently on leave. The shnex:remove expression takes the nodes from shnex:nodes (all authors) and removes the nodes returned by the shnex:remove expression (authors on leave). @@ -2027,7 +2027,7 @@

FlatMap Expressions

A blank node that is the subject of the following properties - is called a flatMap expression, + is called a flat map expression, with the function name shnex:FlatMapExpression: @@ -2045,7 +2045,6 @@

FlatMap Expressions

@@ -2062,10 +2061,10 @@

FlatMap Expressions

-
EVALUATION OF FLATMAP EXPRESSIONS
+
EVALUATION OF FLAT MAP EXPRESSIONS

Let flatMap be the value of shnex:flatMap - and nodes be the value of shnex:nodes in a flatMap expression. + and nodes be the value of shnex:nodes in a flat map expression. If shnex:nodes is not specified, let nodes be the focus node.

@@ -2077,7 +2076,7 @@

FlatMap Expressions

evalExpr(flatMap, focusGraph, n, scope).

- The output nodes of the flatMap expression are produced by concatenating all sequences + The output nodes of the flat map expression are produced by concatenating all sequences Mn in the order of the corresponding nodes n in N.

@@ -2201,7 +2200,7 @@

FindFirst Expressions

A blank node that is the subject of the following properties - is called a findFirst expression, + is called a find first expression, with the function name shnex:FindFirstExpression:

The node expression that is applied to each input node. - The node expression that is applied to each input node.
@@ -2233,13 +2232,13 @@

FindFirst Expressions

-
EVALUATION OF FINDFIRST EXPRESSIONS
+
EVALUATION OF FIND FIRST EXPRESSIONS

Let shape be the value of shnex:findFirst - and nodes be the value of shnex:nodes in a findFirst expression. + and nodes be the value of shnex:nodes in a find first expression. If shnex:nodes is not specified, let nodes be the focus node. Let N be the output nodes of evalExpr(nodes, focusGraph, focusNode, scope). - The output nodes of the findFirst expression contain exactly the first node n + The output nodes of the find first expression contain exactly the first node n in N that conforms to the shape shape, or an empty sequence if no such node exists.

@@ -2251,7 +2250,7 @@

FindFirst Expressions

The following example illustrates the use of shnex:findFirst to derive a property ex:seniorEmployee that finds the first employee with more than five years of experience. - The findFirst operation tests each employee against a shape that validates their years of service. + The shnex:findFirst operation tests each employee against a shape that validates their years of service.

@@ -2326,13 +2325,13 @@

MatchAll Expressions

-
EVALUATION OF MATCHALL EXPRESSIONS
+
EVALUATION OF MATCH ALL EXPRESSIONS

Let shape be the value of shnex:matchAll - and nodes be the value of shnex:nodes in the matchAll expression. + and nodes be the value of shnex:nodes in the match all expression. If shnex:nodes is not specified, let nodes be the focus node. Let N be the output nodes of evalExpr(nodes, focusGraph, focusNode, scope). - The output nodes of the matchAll expression contain the boolean true if + The output nodes of the match all expression contain the boolean true if every node n in N conforms to the shape shape; otherwise the output contains the boolean false.

@@ -2345,7 +2344,7 @@

MatchAll Expressions

The following example illustrates the use of shnex:matchAll to derive a property ex:allEmployeesActive that checks whether all employees of a company are currently active. - The matchAll operation tests each employee against a shape that validates their active status. + The match all operation tests each employee against a shape that validates their active status.