diff --git a/develop/.buildinfo b/develop/.buildinfo
new file mode 100644
index 000000000..6edbefea3
--- /dev/null
+++ b/develop/.buildinfo
@@ -0,0 +1,4 @@
+# Sphinx build info version 1
+# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
+config: dde5bbfdc3661ad4880e69e8c679c36c
+tags: 645f666f9bcd5a90fca523b33c5a78b7
diff --git a/develop/.doctrees/advanced/SPARQL_Service_Extension.doctree b/develop/.doctrees/advanced/SPARQL_Service_Extension.doctree
new file mode 100644
index 000000000..0de9e6037
Binary files /dev/null and b/develop/.doctrees/advanced/SPARQL_Service_Extension.doctree differ
diff --git a/develop/.doctrees/apis.doctree b/develop/.doctrees/apis.doctree
new file mode 100644
index 000000000..fb1515da8
Binary files /dev/null and b/develop/.doctrees/apis.doctree differ
diff --git a/develop/.doctrees/environment.pickle b/develop/.doctrees/environment.pickle
new file mode 100644
index 000000000..bff84c0d8
Binary files /dev/null and b/develop/.doctrees/environment.pickle differ
diff --git a/develop/.doctrees/federation/federated_and_distributed_queries.doctree b/develop/.doctrees/federation/federated_and_distributed_queries.doctree
new file mode 100644
index 000000000..e15742712
Binary files /dev/null and b/develop/.doctrees/federation/federated_and_distributed_queries.doctree differ
diff --git a/develop/.doctrees/getting_started/getting_started_with_corese-core.doctree b/develop/.doctrees/getting_started/getting_started_with_corese-core.doctree
new file mode 100644
index 000000000..856454d02
Binary files /dev/null and b/develop/.doctrees/getting_started/getting_started_with_corese-core.doctree differ
diff --git a/develop/.doctrees/index.doctree b/develop/.doctrees/index.doctree
new file mode 100644
index 000000000..ca1f723a6
Binary files /dev/null and b/develop/.doctrees/index.doctree differ
diff --git a/develop/.doctrees/install.doctree b/develop/.doctrees/install.doctree
new file mode 100644
index 000000000..044197b89
Binary files /dev/null and b/develop/.doctrees/install.doctree differ
diff --git a/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1Graph.doctree b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1Graph.doctree
new file mode 100644
index 000000000..7638346fc
Binary files /dev/null and b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1Graph.doctree differ
diff --git a/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1Graph_1_1CompareNode.doctree b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1Graph_1_1CompareNode.doctree
new file mode 100644
index 000000000..6d40ef851
Binary files /dev/null and b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1Graph_1_1CompareNode.doctree differ
diff --git a/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1Graph_1_1GTable.doctree b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1Graph_1_1GTable.doctree
new file mode 100644
index 000000000..ac7c63f5d
Binary files /dev/null and b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1Graph_1_1GTable.doctree differ
diff --git a/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1Graph_1_1TreeNode.doctree b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1Graph_1_1TreeNode.doctree
new file mode 100644
index 000000000..c81559339
Binary files /dev/null and b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1Graph_1_1TreeNode.doctree differ
diff --git a/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1load_1_1Load.doctree b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1load_1_1Load.doctree
new file mode 100644
index 000000000..d2fc5c25e
Binary files /dev/null and b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1load_1_1Load.doctree differ
diff --git a/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1print_1_1ResultFormat.doctree b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1print_1_1ResultFormat.doctree
new file mode 100644
index 000000000..0938f0762
Binary files /dev/null and b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1print_1_1ResultFormat.doctree differ
diff --git a/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1query_1_1QueryProcess.doctree b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1query_1_1QueryProcess.doctree
new file mode 100644
index 000000000..59e1211ba
Binary files /dev/null and b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1query_1_1QueryProcess.doctree differ
diff --git a/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1shacl_1_1Shacl.doctree b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1shacl_1_1Shacl.doctree
new file mode 100644
index 000000000..23272fc2b
Binary files /dev/null and b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1shacl_1_1Shacl.doctree differ
diff --git a/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1transform_1_1Transformer.doctree b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1transform_1_1Transformer.doctree
new file mode 100644
index 000000000..b90fd4fa8
Binary files /dev/null and b/develop/.doctrees/java_api/classfr_1_1inria_1_1corese_1_1core_1_1transform_1_1Transformer.doctree differ
diff --git a/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src.doctree b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src.doctree
new file mode 100644
index 000000000..bb5a07bd9
Binary files /dev/null and b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src.doctree differ
diff --git a/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main.doctree b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main.doctree
new file mode 100644
index 000000000..984734ea8
Binary files /dev/null and b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main.doctree differ
diff --git a/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java.doctree b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java.doctree
new file mode 100644
index 000000000..90200ebf2
Binary files /dev/null and b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java.doctree differ
diff --git a/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr.doctree b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr.doctree
new file mode 100644
index 000000000..4f22c3939
Binary files /dev/null and b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr.doctree differ
diff --git a/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria.doctree b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria.doctree
new file mode 100644
index 000000000..509097138
Binary files /dev/null and b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria.doctree differ
diff --git a/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese.doctree b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese.doctree
new file mode 100644
index 000000000..1e9b7a502
Binary files /dev/null and b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese.doctree differ
diff --git a/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core.doctree b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core.doctree
new file mode 100644
index 000000000..bd025a6bb
Binary files /dev/null and b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core.doctree differ
diff --git a/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_api.doctree b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_api.doctree
new file mode 100644
index 000000000..47f6d6e65
Binary files /dev/null and b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_api.doctree differ
diff --git a/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_load.doctree b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_load.doctree
new file mode 100644
index 000000000..9052ef9c7
Binary files /dev/null and b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_load.doctree differ
diff --git a/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_print.doctree b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_print.doctree
new file mode 100644
index 000000000..c75c0ec45
Binary files /dev/null and b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_print.doctree differ
diff --git a/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_query.doctree b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_query.doctree
new file mode 100644
index 000000000..d5369e774
Binary files /dev/null and b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_query.doctree differ
diff --git a/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_shacl.doctree b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_shacl.doctree
new file mode 100644
index 000000000..d3e0ea26c
Binary files /dev/null and b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_shacl.doctree differ
diff --git a/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_transform.doctree b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_transform.doctree
new file mode 100644
index 000000000..06d25fa1f
Binary files /dev/null and b/develop/.doctrees/java_api/dir__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_transform.doctree differ
diff --git a/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_Graph.java.doctree b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_Graph.java.doctree
new file mode 100644
index 000000000..3bfc671d4
Binary files /dev/null and b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_Graph.java.doctree differ
diff --git a/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_api_Loader.java.doctree b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_api_Loader.java.doctree
new file mode 100644
index 000000000..c06658715
Binary files /dev/null and b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_api_Loader.java.doctree differ
diff --git a/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_load_Load.java.doctree b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_load_Load.java.doctree
new file mode 100644
index 000000000..9a50034fc
Binary files /dev/null and b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_load_Load.java.doctree differ
diff --git a/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_print_ResultFormat.java.doctree b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_print_ResultFormat.java.doctree
new file mode 100644
index 000000000..cc0c4d1fc
Binary files /dev/null and b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_print_ResultFormat.java.doctree differ
diff --git a/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_query_QueryProcess.java.doctree b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_query_QueryProcess.java.doctree
new file mode 100644
index 000000000..7dc478e73
Binary files /dev/null and b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_query_QueryProcess.java.doctree differ
diff --git a/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_shacl_Shacl.java.doctree b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_shacl_Shacl.java.doctree
new file mode 100644
index 000000000..06d853f1f
Binary files /dev/null and b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_shacl_Shacl.java.doctree differ
diff --git a/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_transform_Transformer.java.doctree b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_transform_Transformer.java.doctree
new file mode 100644
index 000000000..cc3d42b3f
Binary files /dev/null and b/develop/.doctrees/java_api/file__builds_actions-runners__work_corese-core_corese-core_src_main_java_fr_inria_corese_core_transform_Transformer.java.doctree differ
diff --git a/develop/.doctrees/java_api/library_root.doctree b/develop/.doctrees/java_api/library_root.doctree
new file mode 100644
index 000000000..d7599f0f6
Binary files /dev/null and b/develop/.doctrees/java_api/library_root.doctree differ
diff --git a/develop/.doctrees/java_api/namespace_fr.doctree b/develop/.doctrees/java_api/namespace_fr.doctree
new file mode 100644
index 000000000..1b94ba586
Binary files /dev/null and b/develop/.doctrees/java_api/namespace_fr.doctree differ
diff --git a/develop/.doctrees/java_api/namespace_fr__inria.doctree b/develop/.doctrees/java_api/namespace_fr__inria.doctree
new file mode 100644
index 000000000..aa4b0f1dd
Binary files /dev/null and b/develop/.doctrees/java_api/namespace_fr__inria.doctree differ
diff --git a/develop/.doctrees/java_api/namespace_fr__inria__corese.doctree b/develop/.doctrees/java_api/namespace_fr__inria__corese.doctree
new file mode 100644
index 000000000..0f11ece69
Binary files /dev/null and b/develop/.doctrees/java_api/namespace_fr__inria__corese.doctree differ
diff --git a/develop/.doctrees/java_api/namespace_fr__inria__corese__core.doctree b/develop/.doctrees/java_api/namespace_fr__inria__corese__core.doctree
new file mode 100644
index 000000000..6d63f4e6a
Binary files /dev/null and b/develop/.doctrees/java_api/namespace_fr__inria__corese__core.doctree differ
diff --git a/develop/.doctrees/java_api/namespace_fr__inria__corese__core__api.doctree b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__api.doctree
new file mode 100644
index 000000000..5f0199db6
Binary files /dev/null and b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__api.doctree differ
diff --git a/develop/.doctrees/java_api/namespace_fr__inria__corese__core__load.doctree b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__load.doctree
new file mode 100644
index 000000000..2d4e0ab71
Binary files /dev/null and b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__load.doctree differ
diff --git a/develop/.doctrees/java_api/namespace_fr__inria__corese__core__print.doctree b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__print.doctree
new file mode 100644
index 000000000..792b5c621
Binary files /dev/null and b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__print.doctree differ
diff --git a/develop/.doctrees/java_api/namespace_fr__inria__corese__core__query.doctree b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__query.doctree
new file mode 100644
index 000000000..00e47b657
Binary files /dev/null and b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__query.doctree differ
diff --git a/develop/.doctrees/java_api/namespace_fr__inria__corese__core__shacl.doctree b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__shacl.doctree
new file mode 100644
index 000000000..935d127dc
Binary files /dev/null and b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__shacl.doctree differ
diff --git a/develop/.doctrees/java_api/namespace_fr__inria__corese__core__sparql.doctree b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__sparql.doctree
new file mode 100644
index 000000000..0d771d4f9
Binary files /dev/null and b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__sparql.doctree differ
diff --git a/develop/.doctrees/java_api/namespace_fr__inria__corese__core__sparql__api.doctree b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__sparql__api.doctree
new file mode 100644
index 000000000..6e52e9856
Binary files /dev/null and b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__sparql__api.doctree differ
diff --git a/develop/.doctrees/java_api/namespace_fr__inria__corese__core__transform.doctree b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__transform.doctree
new file mode 100644
index 000000000..ac7d545e2
Binary files /dev/null and b/develop/.doctrees/java_api/namespace_fr__inria__corese__core__transform.doctree differ
diff --git a/develop/.doctrees/java_api/page_deprecated.doctree b/develop/.doctrees/java_api/page_deprecated.doctree
new file mode 100644
index 000000000..e71e351c3
Binary files /dev/null and b/develop/.doctrees/java_api/page_deprecated.doctree differ
diff --git a/develop/.doctrees/java_api/unabridged_orphan.doctree b/develop/.doctrees/java_api/unabridged_orphan.doctree
new file mode 100644
index 000000000..fddb97252
Binary files /dev/null and b/develop/.doctrees/java_api/unabridged_orphan.doctree differ
diff --git a/develop/.doctrees/storage/configuring_and_connecting_to_different_storage_systems_in_corese.doctree b/develop/.doctrees/storage/configuring_and_connecting_to_different_storage_systems_in_corese.doctree
new file mode 100644
index 000000000..036714895
Binary files /dev/null and b/develop/.doctrees/storage/configuring_and_connecting_to_different_storage_systems_in_corese.doctree differ
diff --git a/develop/.doctrees/user_guide.doctree b/develop/.doctrees/user_guide.doctree
new file mode 100644
index 000000000..c847fe1b0
Binary files /dev/null and b/develop/.doctrees/user_guide.doctree differ
diff --git a/develop/_images/corese.svg b/develop/_images/corese.svg
new file mode 100644
index 000000000..1e2386bb0
--- /dev/null
+++ b/develop/_images/corese.svg
@@ -0,0 +1,200 @@
+
+
+
+
diff --git a/develop/_sources/advanced/SPARQL_Service_Extension.md.txt b/develop/_sources/advanced/SPARQL_Service_Extension.md.txt
new file mode 100644
index 000000000..a4e7f3f7c
--- /dev/null
+++ b/develop/_sources/advanced/SPARQL_Service_Extension.md.txt
@@ -0,0 +1,545 @@
+# SPARQL Service Extension
+
+## Abstract
+
+This document presents extensions of SPARQL service implemented in Corese.
+
+## Introduction
+
+In a SERVICE clause, Corese allows for the addition of URL parameters to the service URL. These parameters are used to tune the behaviour of the service. For example, we can specify the format of the query result returned by the service.
+
+For example, the following query will make Corese write a trace of the execution of the query in its logs:
+```
+http://corese.inria.fr/sparql?mode=debug&query=select * {?s ?p ?o}
+```
+
+
+
+### Prefix used in this document.
+
+```turtle
+@prefix st: Short
+Created: 2015, November 5th
+This document defines a function definition language on top of SPARQL filter language. It enables users to define and use simple extension functions directly in (extended) SPARQL. The body of a function is written using SPARQL filter language augmented with additional statements.
+
+In addition to the existing standards dedicated to representation or querying, Semantic Web programmers could really benefit from a dedicated programming language enabling them to directly define functions on RDF terms, RDF graphs or SPARQL results.
+This is especially the case, for instance, when defining SPARQL extension functions.
+
+We propose a function definition language on top of SPARQL filter language by introducing a function clause. It enables users to define and use simple extension functions directly in (extended) SPARQL. The body of functions is written using SPARQL filter language augmented with additional statements. The language can be seen as a kind of SPARQLScript w.r.t SPARQL in the spirit of JavaScript w.r.t HTML.
+
+LDScript is provided with extension datatypes that enable programmers to manipulate RDF objects such as graphs and triples as well as
+XML and JSON objects in a seamless way.
+
+The example below defines and uses the factorial function. Function definitions occur just after query definition.
+
+This proposition is strongly related to SPARQL 1.1 Query Language and to RDF 1.1 Concepts and Abstract Syntax.
+
+The language is built on top of SPARQL filter language extended with the statements defined in this proposition.
+
+The objects of the language are SPARQL variables and RDF terms: URI, literal, blank node.
+The language objects can also be RDF triple and graph as well as SPARQL query solution (mapping) and solution sequence (mappings).
+A list datatype is also introduced whose elements can be any of the objects listed above, including lists. List elements do not need to be of the same kind or of the same datatype.
+Triple, graph, mapping, mappings and list are managed as RDF literals with extension datatypes: dt:triple, dt:graph, dt:mapping, dt:mappings and dt:list. Their content is accessed by pattern matching and they are iterable.
+
+We call LDScript terms the union of RDF terms and LDScript literals with extension datatype in the dt: namespace.
+
+In the document, we use prefix and namespaces shown below:
+
+The function statement defines a function that can be used in a query, a rule, a template or another function. The name of a function is an URI, it can have zero, one or several arguments that are variables.
+Function overloading is provided: several functions can be defined with the same name and different number of arguments. Functions can call other LDScript functions including themselves, SPARQL functions or extension functions.
+The body is a sequence of expressions.
+The result of the function is the result of the last expression of the body, or the result of the return statement if any.
+
+The parameters and the result of a function may be typed as shown below.
+
+This statement defines an anonymous function that can be used with second order functions such as: apply, funcall, map and reduce.
+As it is an expression of the language, it can be bound to a variable, passed to a function call as parameter, it can be an element of a list, etc.
+Compiling an anonymous function produces a function definition with a generated URI.
+This URI is transparently used at runtime to call and execute the function.
+
+
+This @public annotation exports function definitions in the SPARQL interpreter in such a way that future SPARQL queries can use them within current runtime session.
+
+This section details LDScript statements.
+
+LSDcript inherits SPARQL Filter language statements, including the exists clause, SPARQL select and construct queries and Update queries. These statements are evaluated with the Dataset of the embedding SPARQL query that runs the LDScript function. For syntactic reasons, SPARQL queries are embedded in a query statement, except in the let and for statements where it can be avoided.
+
+The result of a select (resp. construct) query is a dt:mappings (resp. dt:graph) datatype extension literal. These datatypes act as "pointers" to the underlying data structure that implements the result of the query.
+
+At runtime, variables that are bound in LDScript stack and that are projected in the select clause of a query are dynamically bound in the where clause. They are bound using an extended values clause that is generated dynamically. It is extended because it accepts blank node values in addition to URI and literals.
+In the example below, we call us:foo(v), the value of ?x is v in the stack and an appropriate values clause is dynamically generated.
+
+For construct queries, variables that are in-scope in the where clause and that are bound in LDScript stack are dynamically bound in the where clause using an extended values clause.
+
+For the exists { BGP } clause, variables that are in-scope in the BGP and that are bound in LDScript stack are dynamically bound in the BGP using an extended values clause.
+
+Statements such as if, bound, coalesce are also available. SPARQL predefined functions are also available with the rq: prefix, e.g. rq:contains.
+
+It is worth noticing that, as any statement, a SPARQL query can be embedded in an anonymous function.
+
+The let statement defines local variables whose scope is the body of the let statement. The result of the statement is the result of the last expression of the body, or the result of the return statement if any.
+
+The dynamic let statement is a variant of the let statement where the scope of the declared variable is not only the body but also the functions that are called in the body (and recursively). In the example below, variable x in anonymous function is bound by the dynamic let.
+
+The let statement enables users to map list elements to variables. The number of variables may be less than the size of the list.
+
+The left argument can be a list of lists of variables.
+
+The let statement can have a select-where query as argument. In this case, the variables in the select clause are defined and bound, in the body of the let clause, with the values of the first query solution. If a variable has no value in the first solution (e.g. due to an optional), the body is executed with the variable left unbound.
+If there is no solution, the body is executed with all select variables left unbound.
+These cases can be trapped in the body by the bound or coalesce functions.
+
+If the left argument is a list of variables, each variable is bound to the corresponding query solution (a mapping) in order.
+
+If the left argument is a list of list of variables, each variable is bound to the value of the corresponding variable (with same name) in the first query solution.
+
+The let statement can take as second argument a construct-where query. The value of the variable is the RDF result graph.
+
+Variables in-scope in the where clause that are bound in LDScript stack are bound in the where clause using an extended values clause generated at runtime.
+The query above is evaluated as shown below if the value of ?x is v in the stack.
+
+This statement assigns a value to a variable.
+
+Local variables are defined by let (var = exp), for (var in exp), function us:fun(var) while
+set(var = exp) sets the value of a variable to the result of the expression.
+
+Global variables are defined by set(var = exp) when var is not a local variable at that time.
+
+The for statement defines a loop on LDScript terms that are iterable datatypes.
+The list below specifies the kind of the term iterated in the statement:
+for (VAR in EXP).
+
+The result returned by the for statement is the boolean value true.
+A specific result can be returned using the return statement which has for effect to interrupt the loop.
+If an iteration of the loop returns an error, the loop terminates and returns an error.
+
+The for statement can take as argument a select-where query. In this case, the loop iterates on the solutions of the query and the variables projected in the select clause are bound to their value of the current solution in the body of the loop.
+If a variable has no value, it remains unbound.
+
+
+The for statement can take as second argument a construct-where query. In this case, the loop iterates on the triples of the result graph.
+
+The access to the content of extension datatypes can be done by declarative pattern matching.
+
+Iterable datatypes can be mapped to a list of variables, by pattern matching, using the let statement.
+
+Pattern matching with dt:mapping datatype is done by variable name and not by position.
+In the example below, variable x is bound to the value of variable x in current mapping.
+
+Extended datatypes can be accessed with pattern matching that focuses on first element(s), rest of the elements and last element(s).
+For this purpose, LDScript introduces two Pattern Matching operators: "." and "|" that can be combined.
+
+The "." operator enables to identify last element(s) of an extension datatype. In the example below, z variable matches the last element whereas x variable matches the first element.
+If there is only one element, the first and the last element are the same. If the extended datatype is empty, the variables remain unbound but the statement does not fail.
+
+It is possible to match several elements among the first ones and/or several elements among the last ones, as shown below. If there are not enough elements, some variables remain unbound.
+
+The "|" operator enables LDScript to match a sublist of elements, after the first element(s). In the example below, the rest variable is bound with the sublist starting after the two first elements. The sublist may be empty if there are not enough elements.
+
+It is possible to combine the two operators. In the example below, the sublist starts after the first two elements and stops before the last two elements. If there are not enough elements, the sublist may be empty.
+
+Sublist and last operators can be used on their own.
+
+The "." and "|" operators can be used with these datatypes:
+dt:list, dt:map, dt:graph, dt:triple, dt:path, dt:mappings.
+
+LDScript extension datatypes can be iterated and mapped to a list of variables using the for statement.
+
+A mappings datatype is iterated as mapping elements.
+Pattern matching with mapping element is done by variable name and not by position.
+In the example below, variable x and y are bound to the values of variable x and y in current mapping.
+
+This statement is a syntactic extension of SPARQL if then else statement.
+
+This statement resumes the execution of a function and returns its result.
+
+This statement returns an error.
+The execution of the LDScript expression resumes and returns an error. An error can be trapped by the coalesce statement as in SPARQL.
+
+This statement checks that the evaluation of an expression does not produce an error and returns a boolean accordingly.
+It is a generalization of the bound statement with any expression as argument.
+
+A second order function is a function whose first argument evaluation returns a function (a function URI or an anonymous function) and which calls this function with the other arguments.
+Second order functions are funcall, apply, map and reduce. They are useful in the context of Linked Data because the name URI of a function to be applied on resources can be determined by a SPARQL query.
+This statement applies a function which is the result of the evaluation of an expression.
+The first argument of the statement is an expression that must return either the URI of a function or an anonymous function.
+
+This statement is similar to the funcall statement but the arguments of the function call are given as a list.
+
+The map statement applies a function iteratively on the elements of an iterable datatype: dt:list, dt:map, dt:graph, dt:mappings, dt:mapping. We use the abstract iterable type to denote any of these types.
+The first argument of the statement is an expression that must return the URI of a function or an anonymous function. SPARQL filter functions, as well as second order functions, are available as URI with the rq: prefix.
+
+If one of the function evaluations returns an error, the map terminates and returns en error.
+
+The map functions described here can also have other arguments. In this case, the values of the arguments are considered at each step of the iteration of the iterable datatypes.
+The map functions iterate the first argument that is iterable. If an additional argument is iterable, it is not iterated.
+
+The map functions described here can operate on iterable datatypes such as graph (iterate triple) or mappings (iterate mapping).
+
+The maplist statement applies a function on the elements of a list and returns the list of results
+
+The mapfind statement search elements for which the function returns true. Function mapfind returns first of such elements or error() if there is no such element. In this latter case, error() can be trapped using coalesce().
+
+The mapfindlist statement finds the elements of an iterable datatype for which the function returns true, return the list of such elements.
+
+The mapevery statement returns true if the function returns true on all elements, false otherwise.
+
+The mapany statement returns true if the function returns true on any element, false otherwise.
+
+This statement applies a binary function iteratively to a list of arguments and produces one final result.
+The first argument of the statement is an expression that must return the URI of a function or an anonymous function.
+When the list is empty, if there is a function definition with the same name and zero argument, this function is called and its result is returned.
+
+Second order functions are available with the rq: prefix and can be combined.
+
+LDScript introduces general purpose extension functions.
+
+Display RDF terms in Turtle syntax.
+
+Display RDF terms string value.
+
+Return a xsd:string Turtle representation of an RDF term.
+
+Return a xsd:string representation of the content of an extension datatype in the dt: namespace.
+
+Return the result of the evaluation of its argument.
+
+Return the current RDF graph.
+
+Execute a SPARQL query whose text is the result of an expression, with possibly a list of variable value bindings.
+
+The xt:load function implements URI dereferencing, it returns the RDF graph resulting from the parsing of an RDF document.
+
+If there is a graph argument, the RDF document is loaded in the graph.
+
+The sequence evaluates its arguments in sequence and returns the result of the last argument.
+If an argument returns an error, the sequence returns an error.
+
+The first argument MUST returns a graph with datatype dt:graph.
+The focus statement evaluates other arguments with the graph as current dataset.
+
+LDScript implementations MAY provide functions to execute STTL SPARQL Transformation.
+STTL is a language that enables users to apply transformations to RDF entities such as Turtle, RDF/XML or JSON transformations to RDF graphs and resources or the functional syntax transformation of OWL ontologies. Note that these functions belong to the st: namespace. In the example below, "transform" is the name of a transformation: st:turtle, st:rdfxml, st:json, st:owl, st:spin, etc.
+
+LDScript implementations MAY provide functions to evaluate SHACL shapes on the current focus graph.
+The result of shape functions is the validation report graph.
+
+Generate the Turtle syntax of the report graph.
+
+Generate the SPIN RDF graph of a SPARQL string query.
+
+Generate an RDF graph for SPARQL Query Results using https://www.w3.org/2001/sw/DataAccess/tests/result-set W3C vocabulary.
+
+Generate XML, JSON or RDF text format for SPARQL Query Results. The RDF format is the same as the one returned by the xt:tograph function.
+
+The objects of the language are RDF terms and LDScript terms.
+
+RDF terms are, as usual, URI, Blank Node and Literal with XSD datatype.
+
+LDScript terms are RDF graph and triple, SPARQL query solution sequence (called mappings), SPARQL query solution (called mapping) and SPARQL property path solution (called path).
+LDScript terms include list whose elements are LDScript objects and map whose keys and values are LDScript objects.
+LDScript terms also include datatypes for XML and JSON objects. The XML datatype is provided with (a subset of) the DOM API.
+
+LDScript objects other than RDF terms are implemented by means of literals with specific extension datatypes in the dt: namespace: dt:list, dt:map, dt:xml, dt:json, dt:graph, dt:triple, dt:path, dt:mappings, dt:mapping.
+Hence, they are implemented as RDF terms (i.e. RDF literals with extension datatypes) and their content can be accessed by specific statements as shown below.
+These datatypes are iterable by means of the for and map statements.
+By extension, we call LDScript terms the objects of the language.
+
+The dt:list extension datatype implements list of LDScript terms, including lists. Although similar, it is distinct from RDF list (rdf:List class with rdf:first, rdf:rest and rdf:nil).
+List elements need to be neither of the same kind nor of the same datatype. The dt:list datatype is provided with a set of functions.
+
+The xt:list function is the list constructor.
+
+The xt:iota function generates a list of successive integers or characters.
+
+The xt:size function returns the number of elements of a list.
+
+The xt:first function returns the first element of a list.
+
+The xt:rest function returns the sublist after the first element..
+
+The xt:get function returns the nth element of a list.
+
+The xt:set function sets the value of the nth element of a list. Error if there is no nth element.
+
+The xt:add function adds a tail element to a list. List is modified.
+
+The xt:add function inserts/adds element to a list at nth place. List is modified.
+
+The xt:cons function adds a head element to a list. Returns copy of list.
+
+The xt:member function tests if element is member of the list.
+
+The xt:swap function swaps elements at given index in the list.
+
+The xt:remove function removes the first occurrence of an element from the list, if it is present. Modify the list.
+
+The xt:removeindex function removes the nth element of the list. Modify the list.
+
+The xt:append function appends two lists, keep duplicates.
+
+The xt:merge function merges two lists and removes duplicates.
+
+The xt:reverse function reverses a list.
+
+The xt:sort function sorts a list.
+
+The xt:sort function sorts a list according to a comparison function.
+
+The dt:map extension datatype implements a Map whose keys and values are LDScript objects.
+
+It is provided with a xt:map constructor function.
+
+The xt:size function returns the size of the map.
+
+The xt:set function enables users to set a key value pair in the map.
+
+The xt:get function enables users to retrieve the value of a key in the map.
+
+The xt:has function checks whether the key is present in the map.
+
+The dt:map datatype is iterable as pairs (key, value).
+
+The dt:json extension datatype implements a JSON Map whose keys and values are LDScript objects.
+
+It is provided with a xt:json constructor function.
+
+The xt:size function returns the size of the json map.
+
+The xt:set function enables users to set a key value pair in the json map.
+
+The xt:get function enables users to retrieve the value of a key in the json map.
+
+The dt:json datatype is iterable as pairs (key, value).
+
+The dt:xml extension datatype represents XML objects provided with XPath function and the DOM API. More precisely, the XML datatype manages org.w3c.dom.Node objects from Java DOM.
+
+It is provided with a xt:xml constructor function.
+
+The XML datatype is provided with an xpath function where exp is a XPath expression.
+
+The XML datatype is provided with a subset of the DOM API.
+Implementations MAY provide more functions from the DOM API.
+
+The dt:xml datatype is iterable on child nodes.
+
+There are two datatypes for RDF entities, dt:graph for RDF graph and dt:triple for RDF triple.
+
+The dt:graph datatype is provided with functions.
+Function xt:size returns the number of triples of a graph.
+
+Function xt:graph returns the current graph.
+
+Function xt:union computes a graph that is the union of two graphs. The arguments are LDScript terms with dt:graph datatype and the result is returned as a LDScript term with dt:graph datatype.
+
+The dt:graph datatype is iterable on its triples.
+
+The dt:triple datatype is provided with functions to access the subject, the property and the object. Implementations MAY provide a function to access the named graph when triples are quads.
+
+Triple's elements are accessible by pattern matching.
+
+There are datatypes for SPARQL entities: dt:mappings for SPARQL Query solution sequence, dt:mapping for SPARQL Query solution and dt:path for Property Path solutions.
+
+The dt:mappings datatype is the datatype of SPARQL Query Solution Sequences, i.e. of select-where SPARQL queries.
+
+It is provided with a function xt:size that returns the number of solutions.
+
+The dt:mappings datatype is provided with functions that
+perform SPARQL algebra operations on SPARQL query solutions of select-where queries. The results are returned as literals with dt:mappings datatype.
+
+The dt:mappings datatype is iterable on its mapping elements.
+
+The dt:mapping datatype is the datatype of SPARQL Query Solutions.
+The datatype is iterable as (variable, value) pairs where variable is the name of a variable represented as a xsd:string.
+
+The dt:path datatype is provided for the case where the implementation provides Property Path variables. It is provided with the xt:size function.
+
+The datatype is iterable on its triples.
+
+The syntax is given in EBNF and relies on SPARQL syntax.
+
+LDScript enables us to propose and implement natural SPARQL extensions.
+
+LDScript statements MAY be available within extended SPARQL Query Filter Constraints.
+
+This statement defines an extension aggregate which computes the list of values of the expression and returns a dt:list literal.
+
+This statement is a values clause where the values are computed by an expression.
+
+It is equivalent to the values clause below.
+
+The extended values statement can be used with several variables.
+
+The statement values unnest can be used on iterable datatypes such as: list, map, json, xml, graph.
+
+The dt:path datatype is provided for the case where the implementation gives access to Property Path solutions.
+In the example below, SPARQL is extended with path variables, the $path variable is bound to the property path that relates ?x and ?y.
+The datatype of the value of $path is dt:path. It is conceptually equivalent to dt:list(dt:triple).
+
+When a variable has for value an RDF graph, the variable can be used in a named graph pattern which is evaluated on the content of the graph. The example below shows this case with variable ?g.
+
+In an ontology, properties may be defined as functions of other properties. For example, the surface can be defined as the product of the length and the width.
+
+Implement a function as a service.
+
+Functions can be used to program approximate match.
+
+Functions can be used to program recursive match.
+
+A SPARQL interpreter may define a set of events and emit events during quering processing.
+A SPARQL interpreter may be provided with an event manager that traps events.
+If a SPARQL query is provided with appropriate function definitions for the events, the event manager calls these functions.
+
+The association between an event and a function is done by an annotation wich is an identifier prefixed by the '@' character. The function name is free whereas the annotation name is fixed.
+
+Function called when query processing starts.
+
+Function called when query processing resumes.
+
+Function called when a solution is found.
+
+LDScript can be use to manage predefined queries by means of anonymous functions.
+
+Translate recursively an rdf:List into a dt:list.
+
+This statement defines an extension aggregate. The first expression (e.g. aggregate(?n)) is the expression to aggregate. The aggregate function computes the list of values of this expression. The second expression (e.g. us:median(?list)) is the function to be applied to the list of values. In the example below, the aggregate computes the median of the values.
+
+This example shows how to parse an XML document and create RDF triples.
+
+LDScript is implemented and available in the Corese Semantic Web Factory.
+SPARQL-Generate provides an implementation of a subset of LDScript where the body of a function is written solely with SPARQL Filter language.
+
+We have also written a SHACL interpreter using SPARQL Function.
+
+Dedicated programming language enabling Semantic Web programmers to define functions on RDF terms, triples and graphs or SPARQL query results can facilitate the development and improve the reuse and maintenance of the code produced for Linked Data.
+We propose to extend SPARQL with LDScript, a script language that enables users to define extension functions.
+Its main characteristics are:
+
+In the future we wish to provide a second implementation on top of another Semantic Web Factory.
+We wish to provide a compiler to Java language and work on performance.
+We would like to design a type checker and investigate Linked Functions.
+
+K. L. Clark, F. G. McCabe.
+Ontology oriented programming in go!
+Applied Intelligence. Springer.
+Volume 24, Issue 3, 2006.
+
+Eyal Oren, Renaud Delbru, Sebastian Gerke, Armin Haller, Stefan Decker.
+ActiveRDF: object-oriented semantic web programming.
+International Conference on World Wide Web, WWW 2007, Banff, Alberta,
+Canada, 2007.
+
+Greg Williams.
+Extensible SPARQL functions with embedded javascript.
+In ESWC Workshop on Scripting for the Semantic Web, SFSW,
+Innsbruck, Austria, volume 248 of CEUR Workshop Proceedings, 2007.
+
+Diego Berrueta, Jose E. Labra, and Ivan Herman.
+XSLT+SPARQL: Scripting the Semantic Web with SPARQL embedded into XSLT stylesheets.
+4th Workshop on Scripting for the Semantic Web
+2008
+
+Axel Polleres,
+Thomas Krennwallner , Nuno Lopes, Jacek Kopecký, Stefan Decker.
+XSPARQL Language Specification.
+W3C Member Submission
+2009
+
+Bernhard Schandl.
+Functions over RDF Language Elements.
+International Semantic Web Conference, ISWC 2009.
+
+Sven Groppe, Jana Neumann, and Volker Linnemann.
+SWOBE - embedding the semantic web languages RDF, SPARQL and SPARUL into java for guaranteeing
+type safety, for checking the satisfiability of queries and for the determination
+of query result types.
+ACM Symposium on Applied
+Computing (SAC), Honolulu, Hawaii, USA, 2009.
+
+Holger Knublauch.
+SPIN JavaScript Functions (SPINx)
+SPIN JavaScript Functions (SPINx)
+2010
+
+V. Eisenberg.
+Ruby on Semantic Web.
+IEEE 27th International Conference on Data Engineering.
+2011
+
+Holger Knublauch.
+SPIN - SPARQL Syntax.
+Member Submission, W3C, 2011.
+http://www.w3.org/Submission/2011/SUBM-spin-sparql-20110222/.
+
+Espen Suenson, Johan Lilius, Ivan Porres.
+OWL Web Ontology Language as a Scripting Language for Smart Space Applications
+Rule-Based Reasoning, Programming, and Applications
+Springer Berlin Heidelberg
+Berlin, Heidelberg
+2011
+
+Olivier Corby, Alban Gaignard, Catherine Faron-Zucker, and Johan Montagnat.
+KGRAM Versatile Data Graphs Querying and
+Inference Engine
+In Proc. IEEE/WIC/ACM International Conference on Web
+Intelligence, Macau, December 2012.
+
+SPARQL 1.1 Query Language,
+Steve Harris, Andy Seaborne.
+W3C Recommendation, March 2013
+
+David Mizell, Kristyn J. Maschhoff, Steven P. Reinhardt.
+Extending SPARQL with graph functions.
+IEEE International Conference on Big Data (Big Data).
+2014
+
+Martin Leinberger, Stefan Scheglmann, Ralf Lämmel, Steffen Staab, Matthias Thimm, Evelyne Viegas.
+Semantic Web Application Development with LITEQ.
+International Semantic Web Conference, ISWC, Riva del Garda, Italy.
+2014.
+
+RDF 1.1 Concepts and Abstract Syntax,
+Graham Klyne, Jeremy J. Carroll, Brian McBride.
+W3C Recommendation, February 2014
+
+Maurizio Atzori.
+Toward the web of functions: Interoperable higher-order functions in
+SPARQL.
+13th International Semantic Web Conference, ISWC, Riva del Garda, Italy, volume 8797 of LNCS, 2014.
+\n%s\t
\n\n\n"
+ group {
+ format {
+ "\t\t\n\t\t\t \n"
+ ?s ?p ?o
+ }
+ }
+ }
+}
+where {
+ ?s ?p ?o
+}
+order by ?s ?p ?o
+```
+
+**Result :**
+
+```html
+
+
+
+ %s \n\t\t\t%s \n\t\t\t%s \n\t\t
+
+
+
+
+```
+
+| ?s | ?p | ?o |
+| ------------------------------ | ------------------------------------------------- | --------------------------- |
+|
+
+ http://example.org/EdithPiaf
+ http://example.org/firstName
+ Edith
+
+
+ http://example.org/EdithPiaf
+ http://example.org/lastName
+ Piaf
+
+
+ http://example.org/EdithPiaf
+ http://www.w3.org/1999/02/22-rdf-syntax-ns#type
+ http://example.org/Singer
+ Contributions and discussions
+
+.. _discussion forum: https://github.com/orgs/corese-stack/discussions
+.. _issue reports: https://github.com/corese-stack/corese-core/issues
+.. _pull requests: https://github.com/Wimmics/corese/pulls/
+
+For support questions, comments, and any ideas for improvements you’d like to discuss, please use our `discussion forum`_. We welcome everyone to contribute to `issue reports`_, suggest new features, and create `pull requests`_.
+
+
+.. #############################################################################
+.. The statements below are to produce the title of the page in the tab
+ and a menu with the links to the pages of the documentation
+
+.. raw html below is used to hide the title of the page but retain it in the
+ tab title. https://github.com/sphinx-doc/sphinx/issues/8356
+.. raw:: html
+
+
+
+.. toctree::
+ :hidden:
+
+ Installation SPARQL Function
+LDScript: a Linked Data Script Language
+
+
+Modified: 2020, December 1st
+Authors
+
+Olivier Corby <olivier.corby@inria.fr>
+Catherine Faron Zucker <faron@i3s.unice.fr>
+Fabien Gandon <fabien.gandon@inria.fr>
+
+
+
+
+
+Abstract
+Table of contents
+
+1 Introduction
+ 1.1 Relationship to W3C Recommendations
+
+2 Function Definition
+ 2.1 Function
+ 2.2 Anonymous Function
+ 2.3 Annotation
+
+3 Statement
+ 3.1 SPARQL
+ 3.2 Let
+ 3.3 For
+ 3.4 Pattern Matching
+ 3.5 If Then Else
+ 3.6 Return
+ 3.7 Error
+ 3.8 Safe
+
+4 Second Order Function
+ 4.1 Funcall
+ 4.2 Apply
+ 4.3 Map
+ 4.4 Reduce
+
+5 Predefined Extension Function
+ 5.1 General Purpose
+ 5.2 SPARQL Transformation
+ 5.3 SHACL
+
+6 Datatype
+ 6.1 LDScript Datatype
+ 6.2 RDF Datatype
+ 6.3 SPARQL Datatype
+
+7 Language Syntax
+
+8 SPARQL Extension
+ 8.1 LDScript in SPARQL
+ 8.2 Aggregate
+ 8.3 Values Unnest
+ 8.4 Property Path Variable
+ 8.5 Named Graph Pattern
+
+9 Use Case
+ 9.1 Functional Property
+ 9.2 Functional Service
+ 9.3 Approximate Match
+ 9.4 Recursive Match
+ 9.5 Event Driven Function
+ 9.6 Predefined Query
+
+10 Implementation
+
+11 Conclusion
+
+
+
+
+1 Introduction
+Example
+
+
+select *
+where {
+ ?x rdf:value ?n
+ filter (?n >= us:fac(10))
+}
+
+function us:fac(?n) {
+ if (?n = 0, 1, ?n * us:fac(?n - 1))
+}
+
+
+For the sake of usability, LDScript variables out of a SPARQL Query can be written without "?" as shown below. Variables n and ?n are the same variables.
+
+
+
+function us:fac(n) {
+ if (n = 0, 1, n * us:fac(n - 1))
+}
+
+
+
+
+1.1 Relationship to W3C Recommendations
+2 Function Definition
+
+
+
+
+
+prefix rq: <http://ns.inria.fr/sparql-function/>
+prefix dt: <http://ns.inria.fr/sparql-datatype/>
+prefix st: <http://ns.inria.fr/sparql-template/>
+prefix xt: <http://ns.inria.fr/sparql-extension/>
+prefix us: <http://ns.inria.fr/sparql-extension/user/>
+prefix dom: <http://ns.inria.fr/sparql-extension/dom/>
+prefix sh: <http://www.w3.org/ns/shacl#>
+
+
+
+
+2.1 Function
+
+
+function us:fun(x, y) {
+ x + y
+}
+
+
+
+
+
+function xsd:integer us:fun(xsd:integer x, xsd:integer y) {
+ x + y
+}
+
+
+
+
+
+
+
+2.2 Anonymous Function
+
+function(x) { 1 / (x * x) }
+
+
+
+maplist(function(x) { 1 / (x * x) } , xt:iota(5))
+
+
+
+
+
+
+2.3 Annotation
+
+Public
+
+@public
+function us:foo() {
+ xt:display("Hello World")
+}
+
+@public {
+
+ function us:bar(x, y) {
+ us:gee(x * y)
+ }
+
+ function us:gee(x) {
+ x * x
+ }
+}
+
+
+
+
+
+3 Statement
+
+3.1 SPARQL
+
+query(select ?x ?y where { ?x foaf:knows ?y })
+
+
+
+
+
+datatype(query(select ?x ?y where {?x foaf:knows ?y})) = dt:mappings
+datatype(query(construct where {?x foaf:knows ?y})) = dt:graph
+
+
+
+us:foo(v)
+
+function us:foo(?x) {
+ query(select ?x ?y where { values ?x { v } ?x foaf:knows ?y })
+}
+
+
+
+Query and Anonymous Function
+
+let (query = function() { query(select .. where ..) }) {
+ datatype(funcall(query)) = dt:mappings
+}
+
+
+
+
+
+
+
+3.2 Let
+
+let (z = x + y, t = 2 * z) {
+ us:foo(t)
+}
+
+
+
+
+
+Dynamic Let
+
+letdyn (x = exp) { maplist(function(y) { us:fun(x, y) }, list }
+
+
+
+
+
+
+
+
+
+Let List
+
+
+
+let ((x y z) = list) {
+ us:foo(x, y, z)
+}
+
+
+
+
+let (((x y), (z t)) = @((1 2)(3 4))) {
+
+}
+
+
+
+
+
+
+
+Let Select Query
+
+
+let (select ?x ?y where { ?x foaf:knows ?y }) {
+ us:bar(?x, ?y)
+}
+
+
+
+
+
+let ((s1 s2) = select * where { ?x foaf:knows ?y }) {
+ us:foo(s1, s2)
+}
+
+
+
+let (((x y)) = select * where { ?x foaf:knows ?y }) {
+ us:foo(x, y)
+}
+
+
+
+
+
+Let Construct Query
+
+
+
+function us:foo(?x) {
+ let (g = construct where { ?x foaf:knows ?y}) {
+ g
+ }
+}
+
+
+
+function us:foo(?x) {
+ let (g = construct where { values ?x { v } ?x foaf:knows ?y}) {
+ g
+ }
+}
+
+
+
+Set
+
+set (var = val)
+
+
+set (x = x + 1)
+
+
+
+
+Global variable
+
+
+
+
+The runtime scope of a global variable is the runtime scope of the outermost query within which the variable is defined, including functions and subqueries.
+When LDScript is used with STTL, the scope of a global variable is the whole STTL transformation.
+
+
+When a global variable is defined in a function, the global variable definition remains valid outside the function when the function resumes, until the outermost query resumes.
+
+
+
+A local variable definition temporarily hides a global variable with the same name within the lexical scope of the statement that defines the local variable.
+
+
+
+A global variable cannot be referenced directly in a SPARQL query,
+however it can be accessed by means of a function call that returns the value of the global variable. In other words, global variables belong to LDScript, not to SPARQL.
+
+3.3 For
+
+
+
+
+
+for (n in xt:list(1, 2, 3)) {
+ if (us:prime(n)) {
+ xt:display(n)
+ }
+}
+
+
+
+
+For Select Query
+
+
+
+
+for (select ?x ?y where {?x foaf:knows ?y}) {
+ us:foo(x, y)
+}
+
+
+
+
+
+
+For Construct Query
+
+
+
+for (t in construct where {?x foaf:knows ?y}) {
+ let ((s p o) = t) {
+
+ }
+}
+
+
+
+for ((s p o) in construct where {?x foaf:knows ?y}) {
+
+}
+
+
+
+
+
+3.4 Pattern Matching
+Let Pattern Matching
+let ((e1 e2 e3) = list)
+
+let ((t1 t2 t3) = graph)
+
+let ((s p o) = triple)
+
+let ((m1 m2 m3) = mappings)
+
+
+
+let ((x y) = mapping)
+
+
+
+
+
+Extended Let Pattern Matching
+
+
+let ((x . z) = term)
+
+
+
+let ((x y . z t) = term)
+
+
+
+
+let ((x y | rest) = term)
+
+
+
+let ((x y | rest . z t) = term)
+
+
+
+
+let (( | list) = term)
+
+
+
+let (( | list . z t) = term)
+
+
+
+let (( . z t) = term)
+
+
+Examples
+
+
+
+let ((x y | rest . z t) = xt:iota(5))
+x = 1 ; y = 2 ; rest = (3) ; z = 4 ; t = 5
+
+
+
+let ((x y | rest . z t) = xt:iota(4))
+x = 1 ; y = 2 ; rest = () ; z = 3 ; t = 4
+
+
+
+
+let ((x y | rest . z t) = xt:iota(3))
+x = 1 ; y = 2 ; rest = () ; z = 2 ; t = 3
+
+
+
+let ((x y | rest . z t) = xt:iota(2))
+x = 1 ; y = 2 ; rest = () ; z = 1 ; t = 2
+
+
+
+let ((x y | rest . z t) = xt:iota(1))
+x = 1 ; y is UNBOUND ; rest = () ; z is UNBOUND ; t = 1
+
+
+
+For Pattern Matching
+
+
+for (elem in list)
+
+
+
+for ((x y) in listOfPairs)
+
+
+
+for (triple in graph)
+
+
+
+for ((s p o) in graph)
+
+
+
+for (term in triple)
+
+
+
+for (mapping in mappings)
+
+
+
+for ((var val) in mapping)
+
+
+
+for ((x y) in mappings)
+
+
+
+
+
+
+
+
+
+
+3.5 If Then Else
+
+if (x > 0) {
+ us:foo(x)
+}
+else if (y > 0) {
+ us:bar(y)
+}
+else {
+ us:gee(x, y)
+}
+
+
+
+
+
+
+3.6 Return
+
+term return(term t)
+
+
+function us:test(a, b)
+ for (x in xt:iota(a, b)) {
+ if (us:prime(x)) { return(x) }
+ }
+}
+
+
+
+
+3.7 Error
+
+if (x < 0) {
+ error()
+}
+
+
+
+
+
+3.8 Safe
+
+safe(x / y)
+
+
+
+
+
+
+
+
+
+
+4 Second Order Function
+
+
+We use the abstract function type to denote either the URI of a function or an anonymous function.
+4.1 Funcall
+
+term funcall (function fun, term t1, ... term tn)
+
+
+
+funcall (us:getMethod(us:surface, x), x)
+
+
+
+
+
+
+
+
+4.2 Apply
+
+term apply (function fun, dt:list arglist)
+
+
+
+apply (rq:regex, xt:list("test", "e", "i"))
+
+
+
+
+
+
+4.3 Map
+
+map (function fun, iterable term)
+
+
+
+map (xt:display, xt:list(1, 2, 3))
+
+
+
+
+
+map (us:fun, xt:list(1, 2, 3), 4)
+
+
+
+
+map (us:foo, query(select * where { ?x ?p ?y }))
+
+
+
+
+dt:list maplist (function fun, iterable term)
+
+
+maplist (function(x) { 1 / (x * x) }, xt:list(1, 2, 3))
+
+
+
+
+
+
+term mapfind (function fun, iterable term)
+
+
+mapfind (us:prime, xt:list(1, 2, 3))
+
+
+
+dt:list mapfindlist (function fun, iterable term)
+
+
+mapfindlist (us:prime, xt:list(1, 2, 3))
+
+
+
+xsd:boolean mapevery (function fun, iterable term)
+
+
+mapevery (us:prime, xt:list(1, 2, 3))
+
+
+
+xsd:boolean mapany (function fun, iterable term)
+
+
+mapany (function(y) { exists { x p y } }, xt:list(1, 2, 3))
+
+
+
+
+
+4.4 Reduce
+
+term reduce (function fun, dt:list list)
+
+
+reduce (rq:plus, xt:iota(5)) = 15
+
+
+
+
+
+Combining second order functions
+
+reduce(rq:concat, maplist(rq:funcall,
+ xt:list(rq:year, rq:month, rq:day, rq:hours, rq:minutes, rq:seconds),
+ now()))
+
+
+
+
+
+
+
+5 Predefined Extension Function
+5.1 General Purpose
+
+Display
+
+xt:display(term t)
+
+
+Print
+
+xt:print(term t)
+
+
+
+Turtle
+
+xsd:string xt:turtle(term t)
+
+
+
+
+Content
+
+xsd:string xt:content(LDScript term t)
+
+
+
+
+
+Self
+
+term xt:self(term t)
+
+
+
+
+
+Graph
+
+dt:graph xt:graph()
+
+
+
+SPARQL Query
+
+dt:mappings xt:sparql(xsd:string selectQuery)
+dt:mappings xt:sparql(xsd:string selectQuery, xsd:string var, term val, ...)
+
+dt:graph xt:sparql(xsd:string constructQuery)
+dt:graph xt:sparql(xsd:string constructQuery, xsd:string var, term val, ...)
+
+
+
+
+
+
+Load
+
+dt:graph xt:load(URI uri)
+
+
+
+dt:graph xt:load(URI uri, dt:graph g)
+
+
+
+
+
+
+Sequence
+
+xt:sequence(exp e1, .. exp en)
+
+
+
+Focus Statement
+
+term xt:focus(dt:graph g, exp e1, .., exp en)
+
+
+xt:focus(
+ xt:load(<http://example.org/test>),
+ exists { ?x rdf:value 2.718 })
+
+
+
+
+
+5.2 SPARQL Transformation
+
+xsd:string st:apply-templates-with(URI transform)
+xsd:string st:apply-templates-with(URI transform, term node)
+
+xsd:string st:call-template(URI name, term node_1, .., term node_n)
+xsd:string st:call-template-with(URI transform, URI name, term node_1, .., term node_n)
+
+
+
+
+
+
+
+5.3 SHACL
+
+dt:graph sh:shacl()
+dt:graph sh:shaclshape(shape)
+dt:graph sh:shaclshape(shape, node)
+dt:graph sh:shaclnode(node)
+
+
+
+xsd:boolean sh:conform(graph)
+
+
+
+
+
+
+
+xsd:string xt:turtle(dt:graph g)
+
+
+
+
+
+Format
+
+
+dt:graph xt:spin(xsd:string q)
+
+
+
+
+dt:graph xt:tograph(dt:mappings m)
+
+
+
+
+xsd:string xt:xml (dt:mappings m)
+xsd:string xt:json(dt:mappings m)
+xsd:string xt:rdf (dt:mappings m)
+
+
+
+
+6 Datatype
+
+6.1 LDScript Datatype
+
+List
+
+dt:list xt:list(term t...)
+
+
+xt:list(1, 2, 3)
+xt:list(xt:list(1, 2), xt:list(3, 4))
+
+
+
+dt:list xt:iota(term t)
+dt:list xt:iota(term t1 , term t2)
+
+
+xt:iota(5) = xt:list(1, 2, 3, 4, 5)
+xt:iota(5, 7) = xt:list(5, 6, 7)
+xt:iota('a', 'c') = xt:list('a', 'b', 'c')
+
+
+
+
+xsd:integer xt:size(dt:list list)
+
+
+
+
+
+term xt:first(dt:list list)
+
+
+
+dt:list xt:rest(dt:list list)
+
+
+
+term xt:get(dt:list list, xsd:integer n)
+
+
+
+
+
+xt:set(dt:list list, xsd:integer n, term t)
+
+
+
+xt:add(dt:list list, term t)
+
+
+
+xt:add(dt:list list, xsd:integer n, term t)
+
+
+
+dt:list xt:cons(term t, dt:list list)
+
+
+
+xsd:boolean xt:member(term t, dt:list list)
+
+
+
+
+dt:list xt:swap(dt:list list, xsd:integer i1, xsd:integer i2)
+
+
+
+xt:remove(dt:list list, term t)
+
+
+
+xt:removeindex(dt:list list, xsd:integer n)
+
+
+
+
+
+dt:list xt:append(dt:list l1, dt:list l2)
+
+
+
+dt:list xt:merge(dt:list l1, dt:list l2)
+
+
+
+dt:list xt:reverse(dt:list list)
+
+
+
+dt:list xt:sort(dt:list list)
+
+
+
+
+dt:list xt:sort(dt:list list, function fun)
+
+
+
+xt:sort(list, us:compare)
+
+function us:compare(x, y) {
+ if (x < y, -1, if(x = y, 0, 1))
+}
+
+
+
+
+
+
+
+Map
+
+dt:map xt:map()
+
+
+
+xt:set(dt:map amap, term key, term value)
+
+
+
+
+term xt:get(dt:map amap, term key)
+
+
+
+term xt:has(dt:map amap, term key)
+
+
+
+
+
+
+
+for ((key val) in amap) { }
+
+map (function((key, val)) { }, amap)
+
+
+
+
+
+
+JSON
+
+dt:json xt:json()
+
+dt:json xt:json(xsd:string jsonString)
+
+
+
+xt:set(dt:json json, term key, term value)
+
+
+
+
+term xt:get(dt:json json, term key)
+
+
+
+
+for ((key val) in json) { }
+
+map (function((key, val)) { }, json)
+
+
+
+
+
+
+
+
+
+
+
+XML
+
+dt:xml xt:xml(xsd:string xmlString)
+dt:xml xt:xml(URI uri)
+
+
+
+
+dt:list(dt:xml) xpath(dt:xml doc, exp)
+
+
+
+xsd:string dom:getNodeType(dt:xml node)
+xsd:string dom:getNodeName(dt:xml node)
+xsd:string dom:getLocalName(dt:xml node)
+xsd:string dom:getNodeValue(dt:xml node)
+xsd:string dom:getTextContent(dt:xml node)
+
+URI dom:getNamespaceURI(dt:xml node)
+URI dom:getBaseURI(dt:xml node)
+
+dt:map(xsd:string, xsd:string) dom:getAttributes(dt:xml node)
+
+dt:list(dt:xml) dom:getElementsByTagName(dt:xml node, xsd:string name)
+dt:list(dt:xml) dom:getElementsByTagNameNS(dt:xml node, xsd:string ns, xsd:string name)
+dt:list(dt:xml) dom:getChildNodes(dt:xml node)
+
+dt:xml dom:getElementById(dt:xml node)
+dt:xml dom:getFirstChild(dt:xml node)
+dt:xml dom:getNodeParent(dt:xml node)
+dt:xml dom:getOwnerDocument(dt:xml node)
+
+xsd:boolean dom:hasAttribute(dt:xml node, xsd:string name)
+xsd:string dom:getAttribute(dt:xml node, xsd:string name)
+xsd:boolean dom:hasAttributeNS(dt:xml node, xsd:string ns, xsd:tring name)
+xsd:string dom:getAttributeNS(dt:xml node, xsd:string ns, xsd:tring name)
+
+
+
+for (node in xml) { }
+
+map (function(node) { }, xml)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6.2 RDF Datatype
+
+Graph Datatype
+
+
+xsd:integer xt:size(dt:graph g)
+
+
+
+dt:graph xt:graph()
+
+
+
+
+dt:graph xt:union(dt:graph g1, dt:graph g2)
+
+
+
+for (atriple in agraph) { }
+for ((s p o) in agraph) { }
+
+map (function(atriple) { }, agraph)
+map (function((s, p, o)) { }, agraph)
+
+
+
+
+
+Triple Datatype
+
+
+term xt:subject(dt:triple t)
+term xt:property(dt:triple t)
+term xt:object(dt:triple t)
+term xt:graph(dt:triple t)
+
+
+
+let ((s p o) = atriple) { }
+
+
+
+
+6.3 SPARQL Datatype
+
+Mappings
+
+xsd:integer xt:size(dt:mappings m)
+
+
+
+
+dt:mappings xt:join(dt:mappings m1, dt:mappings m2)
+dt:mappings xt:union(dt:mappings m1, dt:mappings m2)
+dt:mappings xt:minus(dt:mappings m1, dt:mappings m2)
+dt:mappings xt:optional(dt:mappings m1, dt:mappings m2)
+
+
+
+for (mapping in mappings) { }
+
+map (function(mapping) { }, mappings)
+
+
+
+
+
+
+Mapping
+
+for ((var val) in mapping) { }
+
+map (function((var, val)) { }, mapping)
+
+
+
+Path
+
+for (atriple in apath) { }
+
+map (function(atriple) { }, apath)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7 Language Syntax
+
+LDScript ::= SPARQL_QueryUnit Fun
+Fun ::= (Annotation Function | Annotation Package)*
+Function ::= 'function' Type? Uri FunVarList Body
+Package ::= '{' Function+ '}'
+Annotation ::= ( '@public' | '@debug' )*
+
+Body ::= '{' '}' | '{' Exp (';' Exp)* '}'
+
+Exp ::= SPARQL_Constraint -- with BuiltInCall extended below
+
+BuiltInCall ::= SPARQL_BuiltInCall
+| Let | For | If | Return | Error | SecondOrder | Lambda | Query
+
+SecondOrder ::= Funcall | Apply | MapFun | Reduce |
+
+Query ::= 'query' '(' (SelectQuery | ConstructQuery | Update1) ')'
+
+ExpQuery = Exp | '@' List | SelectQuery | ConstructQuery
+
+Let ::=
+LetName '(' LetDecl (',' LetDecl)* ')' Body |
+LetName '(' SelectQuery ')' Body
+
+LetName = 'let' | 'letdyn'
+
+LetDecl ::= Var '=' ExpQuery | VarExp '=' ExpQuery
+
+Type ::= Uri
+
+VarExp ::= '(' VAR+ ('|' VAR )? ('.' VAR+)? ')'
+
+VarList ::= '(' Var (Var)* ')'
+VarListSep ::= '(' Var (',' Var)* ')'
+
+FunVarList ::= '(' ')' | '(' Type? Var (',' Type? Var)* ')'
+
+For ::=
+'for' '(' Var 'in' ExpQuery ')' Body |
+'for' '(' VarList 'in' ExpQuery ')' Body |
+'for' '(' SelectQuery ')' Body
+
+If ::= 'if' '(' Exp ')' Body ('else' ( Body | If )) ?
+
+Funcall::= 'funcall' '(' Exp (',' Exp)* ')'
+Apply ::= 'apply' '(' Exp ',' Exp ')'
+Reduce ::= 'reduce' '(' Exp ',' Exp ')'
+MapFun ::= Map '(' Exp (',' Exp)+ ')'
+Map ::= 'map' | 'maplist' | 'mapfind' | 'mapfindlist'
+ | 'mapany' | 'mapevery'
+
+Lambda ::= 'function' LambdaVarList Body
+LambdaVarList ::= FunVarList | '(' VarListSep ')'
+
+Error ::= 'error' '(' ')'
+
+Return ::= 'return' '(' Exp ')'
+
+List ::= '(' (RDFTerm | List)* ')'
+
+
+
+
+
+
+
+
+
+
+
+
+
+8 SPARQL Extension
+
+8.1 LDScript in SPARQL
+
+
+select * where {
+ ?x us:method [ us:name us:validate ; us:function fun ]
+ filter funcall(?fun, ?x)
+}
+
+
+
+
+
+
+
+
+8.2 Aggregate
+
+select (aggregate(distinct ?n) as ?list)
+where {
+ ?x rdf:value ?n
+}
+
+
+
+
+
+
+8.3 Values Unnest
+
+values ?n { unnest(xt:list(1, 2, 3)) }
+
+
+values ?n { 1 2 3 }
+
+
+
+
+values (?n ?m) { unnest(xt:list(xt:list(1, 2), xt:list(3, 4))) }
+
+
+
+values ?elem { unnest(?list) }
+values ?node { unnest(?xml) }
+values ?triple { unnest(?graph) }
+
+values (?key ?val) { unnest(?map) }
+values (?key ?val) { unnest(?json) }
+values (?s ?p ?o) { unnest(?graph) }
+
+
+
+
+
+8.4 Property Path Variable
+
+select * where {
+ ?x foaf:knows+ :: $path ?y
+}
+
+
+
+
+
+8.5 Named Graph Pattern
+
+select * where {
+ bind (us:getGraph() as ?g)
+ graph ?g { }
+}
+
+
+
+
+
+
+LDScript SPARQL Extension
+
+
+
+Aggregate ::= SPARQL_Aggregate |
+'aggregate' '(' ('distinct')? Exp ')'
+
+ValuesClause ::= SPARQL_ValuesClause |
+'values' Var '{' 'unnest' '(' Exp ')' '}' |
+'values' VarList '{' 'unnest' '(' Exp ')' '}'
+
+VerbPath ::= Path ( '::' Var )?
+
+
+
+
+
+
+
+
+
+9 Use Case
+
+
+
+9.1 Functional Property
+
+select * where {
+ ?x a us:Figure
+ bind (us:surface(?x) as ?s)
+}
+
+function us:surface(?x) {
+ let ((?w, ?l) = select * where { ?x us:width ?w ; us:length ?l }) {
+ ?w * ?l
+ }
+}
+
+
+
+
+
+9.2 Functional Service
+
+function us:service(?x) {
+ let (select ?x ?l where {
+ service <http://fr.dbpedia.org/sparql> {
+ ?x rdfs:label ?l}}) {
+ ?l
+ }
+}
+
+
+
+
+9.3 Approximate Match
+
+select * where {
+ ?x a ?t
+ filter us:match(foaf:Person, ?t)
+}
+
+function us:match(?q, ?t) {
+ exists {
+ { ?t rdfs:subClassOf* ?q } union
+ { ?q rdfs:subClassOf/(rdfs:subClassOf*|^rdfs:subClassOf) ?t }
+ }
+}
+
+
+
+
+9.4 Recursive Match
+
+select * where {
+ ?x a foaf:Person
+ ?y a foaf:Person
+ filter us:match(?x, ?y)
+}
+
+function us:match(?x, ?y) {
+ exists {
+ { ?x foaf:knows ?y } union
+ { ?x foaf:knows ?z . ?y a foaf:Person filter us:match(?z, ?y) }
+ }
+}
+
+
+
+
+
+
+
+9.5 Event Driven Function Call
+
+
+@before function us:before(query)
+
+
+
+@after function us:after(mappings)
+
+
+
+
+@result us:result(mapping)
+
+
+
+
+
+
+9.6 Predefined Query
+
+
+function us:foo() {
+ let (list = xt:list(
+ function() { query(select .. where ..) },
+ function() { query(select .. where ..) }
+ )) {
+ maplist(rq:funcall, list)
+ }
+}
+
+
+
+
+9.7 Mapping rdf:List with dt:list
+
+
+select x (us:list(l) as list) where {
+ x rdf:value l .
+}
+
+function us:list(l) {
+ let (select ?l
+ (aggregate (if (?b, us:list(?e),
+ if (?e = rdf:nil, xt:list(), ?e))) as ?list)
+ where {
+ ?l rdf:rest*/rdf:first ?e
+ bind (exists { ?e rdf:rest ?a } as ?b)
+ } ) {
+ return (list)
+ }
+}
+
+
+
+9.8 Aggregate
+
+select (aggregate(?n) as ?list) (us:median(?list) as ?med)
+where {
+ ?x rdf:value ?n
+}
+
+function us:median(?list) {
+ xt:get(xt:sort(?list), xsd:integer(xt:size(?list) / 2))
+}
+
+
+
+
+
+
+9.9 SHACL to SPARQL path translator
+
+
+
+
+prefix sh: <http://www.w3.org/ns/shacl#>
+#
+# path = URI | bnode
+# bnode : [sh:zeroOrOnePath exp ] | (exp1 .. expn)
+#
+function sh:path(path) {
+ if (isURI(path)) {
+ return (xt:turtle(path))
+ }
+ else {
+ let (select * where { ?path ?oper ?val filter (?oper not in (rdf:first)) } ) {
+ return (if (oper = rdf:rest, sh:sequencePath(path), funcall(oper, val)))
+ }
+ }
+}
+
+function sh:paren(path) {
+ if (isURI(path), sh:path(path), concat("(", sh:path(path), ")"))
+}
+
+function sh:oneOrMorePath(path) {
+ concat(sh:paren(path), "+")
+}
+
+function sh:zeroOrOnePath(path) {
+ concat(sh:paren(path), "?")
+}
+
+function sh:zeroOrMorePath(path) {
+ concat(sh:paren(path), "*")
+}
+
+function sh:inversePath(path) {
+ concat("^", sh:paren(path))
+}
+
+# path = (e1 .. en)
+function sh:alternativePath(path) {
+ sh:reduce(path, "|")
+}
+
+# path = (e1 .. en)
+function sh:sequencePath(path) {
+ sh:reduce(path, "/")
+}
+
+function sh:reduce(path, sep) {
+ letdyn (astr = sep) {
+ reduce(function(x, y) { concat(x, astr, y) },
+ maplist(sh:path, sh:list(path)))
+ }
+}
+
+function sh:list(path) {
+ let (select path (aggregate(?exp) as ?list)
+ where { ?path rdf:rest*/rdf:first ?exp } ) {
+ return (list)
+ }
+}
+
+
+
+
+
+
+9.10 Create RDF from XML
+
+insert {
+ ?uri foaf:name ?author .
+ [ us:author ?uri ; us:title ?title ]
+}
+where {
+ values ?book { unnest(xpath(us:xml(), "/doc/book")) }
+ bind (dom:getTextContent(xt:xpath(?book, "title")) as ?title)
+ bind (dom:getTextContent(xt:xpath(?book, "author")) as ?author)
+ bind (uri(concat(us:, replace(?author, " ", ""))) as ?uri)
+}
+
+
+# XML document
+function us:xml() {
+xt:xml(
+"""
+<doc>
+<book><title>1984</title><author>Georges Orwell</author></book>
+<book><title>Le Capital au XXIe siècle</title><author>Thomas Piketty</author></book>
+<book><title>Capital et idéologie</title><author>Thomas Piketty</author></book>
+</doc>
+"""
+)
+}
+
+
+
+
+10 Implementation
+Examples
+
+
+11 Conclusion
+
+
+
+Bibliography
+
+
+
+
+
+
+Olivier Corby and Catherine Faron-Zucker. +A Transformation Language for RDF based on SPARQL. +Web Information Systems and Technologies - Selected Extended +Papers from WEBIST 2015. Springer-Verlag, Lecture Notes in Business +Information Processing, 2015. Best paper nominee. +
+Gabriel Ciobanu, Ross Horne, Vladimiro Sassone +Minimal type inference for Linked Data consumers. J. Log. Algebr. Meth. Program. +84(4): 485-504 (2015) +
+Florian Weber, Andreas Bihlmaier, Heinz Worn. +Semantic Object-Oriented Programming (SOOP) +INFORMATIK, Lecture Notes in Informatics (LNI) +2016 +
+Olivier Corby, Catherine Faron-Zucker and Fabien Gandon, +LDScript: a Linked Data Script Language, +International Semantic Web Conference, ISWC, spotlight paper, +2017 October, Vienna, Austria. +
+Martin Leinberger, Ralf Lämmel, Steffen Staab. +The Essence of Functional Programming on Semantic Data. +Programming Languages and Systems: 26th European Symposium on Programming, ESOP 2017, Held as Part of the European Joint Conferences on Theory and Practice of Software, ETAPS, Uppsala, Sweden, April, 2017. +
+Maxime Lefrançois, Antoine Zimmermann, and Noorani Bakerally. +A SPARQL extension for generating RDF from heterogeneous formats. +14th European Semantic Web Conference, ESWC, +Portoroz, Slovenia, volume 10249 of LNCS, 2017. +
+Chi Zhang, Jakob Beetz, Bauke de Vries. +BimSPARQL: Domain-specific functional SPARQL extensions for querying RDF building data +Semantic Web Journal, 2017. +
+Jean-Baptiste Lamy. +Owlready: Ontology-oriented programming in Python +with automatic classification and high level constructs +for biomedical ontologies. +Technical Report +2017 +
+René Schubotz, Christian Vogelgesang, Torsten Spieldenner. +SPARQλ: SPARQL as a function. +Conference: Future of Information and Communication Conference (FICC) 2019, San Francisco, USA. +2019 +
+Philipp Seifer, Martin Leinberger, Ralf Lämmel, and Steffen Staab. +Semantic Query Integration With Reason. +Programming journal. +2019 +
+Kurt Cagle +Extending MarkLogic SPARQL with Javascript +2018 +
+Ben De Meester, Tom Seymoens, Anastasia Dimoua, Ruben Verborgh. +Implementation-independent function reuse, +2020 +Future Generation Computer Systems +
+Extensions in ARQ +Jena documentation +
+Corese defines an Inference Rule Language based on SPARQL construct-where query form. The where clause defines a condition and the construct clause defines the conclusion. +Rules are applied in forward chaining until saturation. +
+ ++ + +
+Corese defines an Inference Rule Language based on SPARQL construct-where query form. The where clause defines a condition and the construct clause defines the conclusion. +Rules are applied in forward chaining until saturation. Corese implements OWL RL using such a rule base. +The example below shows the inference rule that implements OWL transitivity. +
+ ++construct { + ?x ?p ?z +} +where { + ?p a owl:TransitiveProperty . + ?x ?p ?y . + ?y ?p ?z +} ++ +The document uses the namespaces shown below. + +
+prefix kg: <http://ns.inria.fr/corese/kgram/> +prefix rul: <http://ns.inria.fr/corese/rule/> ++ + + +
+ + + + +
+A rule base consists of a list of rules. +The rule engine evaluates a rule base as follows. +It considers all the rules, in order in the rule base. +For each rule, it executes the where clause and if there are solutions, it instantiates the triple patterns of the construct clause with every solution to form a set of triples. +Then, it inserts these triples into the current dataset. +In order to enhance tracability, triples infered by the rule engine are inserted in the kg:rule named graph in the dataset. +The rule engine iterates the cycle above on the entire rule base, possibly several times, until no new triple is generated. +Termination is ensured provided that two conditions are verified: no new graph nodes are inserted and no new properties are created. In this case, termination is ensured because the rule engine engine stops after saturation. +
+ ++Negation is authorized in the where clause, e.g. minus and filter not exists. However, the rule engine does not perform any consistency checking. Hence, a rule can deduce something based on the absence of a pattern while another rule can infer the pattern that was considered absent, in which case there may be a contradiction. +In addition, rules do not retract triples from the dataset. +
+ + ++The query below enables users to retrieve triples infered by the rule engine. +
+ ++select * +from kg:rule +where { + ?s ?p ?o +} ++ + + + + +
+ + + +
+Inference rules are construct where SPARQL queries. +They can use every SPARQL statements, including property path, bind, values and service. +Rules are defined in an RDF document with .rul extension, using RDF/XML syntax as shown below. +Rules should be placed within CDATA sections in order to parse correctly < and & characters. Each rule must declare its prefix and namespaces. +
+ ++<?xml version="1.0"?> +<rdf:RDF + xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns = "http://ns.inria.fr/corese/rule/"> + +<rule> +<body> +<![CDATA[ +prefix owl: <http://www.w3.org/2002/07/owl#> +construct { + ?x ?p ?z +} +where { + ?p a owl:TransitiveProperty . + ?x ?p ?y . + ?y ?p ?z +} +]]> +</body> +</rule> + +<rule> +<body> +<![CDATA[ +prefix owl: <http://www.w3.org/2002/07/owl#> +construct { + ?y ?p ?x +} +where { + ?p a owl:SymmetricProperty . + ?x ?p ?y . +} +]]> +</body> +</rule> + +</rdf:RDF> ++ + + + + +
+ + + + + + + + + + + diff --git a/develop/_static/extensions/sttl.html b/develop/_static/extensions/sttl.html new file mode 100644 index 000000000..7bba4934a --- /dev/null +++ b/develop/_static/extensions/sttl.html @@ -0,0 +1,1162 @@ + + + + + + + + + + +
+29 January 2017 +
+ ++This version: http://ns.inria.fr/sparql-template +
+ ++This document defines the syntax and semantics of the STTL language. STTL stands for SPARQL Template Transformation Language. In STTL transformations describe rules for transforming an RDF source graph into a text result. STTL is designed as an extension of the SPARQL 1.1 Query Language to build on standards and ease its adoption. +
+ + ++RDF provides us with a general purpose graph-oriented data model to represent and interchange data on the Web. However, the transformation and presentation of RDF data is still an open issue. Among the initiatives to answer this question there are extensive works for providing RDF with several varied syntaxes (XML, N-Triples, Turtle, RDFa, TriG, N-Quads, JSON-LD) and for linking it to other data sources (R2RML, CSV-LD, etc.). With the multiplication of data sources and data formats, developers of the Web of data now spend a lot of time and energy to build transformations to present RDF data to users and transform data from one source to another. Moreover, RDF is more and more used as a syntax to represent other languages (e.g. SPIN) and we consider that RDF can then be viewed as a pivot language to represent the abstract syntax trees of expressions of other languages. +
++For this reason, we propose the SPARQL Template Transformation Language (STTL) that enables Semantic Web developers to write specific yet compact RDF transformers toward other languages and formats. This document defines the syntax and semantics of STTL. A transformation expressed in STTL describes rules for transforming an RDF source graph into a text result. STTL is an extension of SPARQL 1.1 Query Language. To some extend STTL is to RDF what XSLT is to XML. An STTL engine takes an RDF graph and a transformation (a set of templates) as input and generates a textual output format as a character stream. Output format may be unstructured text such as natural language, or structured text such as Turtle, HTML, XML, Latex, CSV, etc. If the RDF graph represents the Abstract Syntax Tree of another language, e.g. SPIN, the transformation engine may generate a concrete syntax, e.g. SPARQL. +
+ + + + + +
+STTL is related with SPARQL, RDF and somehow with XSLT.
+
+XSLT is a language for transforming XML documents into other XML documents.
+
+STTL is similar to XSLT as it is a language for transforming RDF graphs into text formats such as RDF documents. However, STTL operates on the graph model of RDF, not on its syntax (that is, not on its RDF/XML syntax).
+
+
+STTL is built on top of SPARQL 1.1 Query Language. It is an extension of SPARQL with an additional template query form and a set of extension functions. +
+ + + + ++ + + +
+STTL uses the prefix and namespaces shown below, which are omitted in the rest of the document: +
+ ++prefix st: <http://ns.inria.fr/sparql-template/> +prefix foaf: <http://xmlns.com/foaf/0.1/> +prefix ex: <http://example.org/ns/> ++ + + + + +
+A transformation is a set of templates. + +A template is a declarative rule with a condition part and a format part. + +A template is applied on a focus node. A focus node is an RDF term of the RDF graph that is currently processed by a transformation engine. +
+ ++A transformation can be defined in two different formats. + +
+In the process of finding the applicable template, more than one template may be eligible. However, in the general case, only one template will be applied. The first template in the transformation is chosen except if templates have priorities. In this case, the template with the highest priority is chosen. +
+ + + + + + + ++SPARQL 1.1 Query Language proposes four query forms: select, construct, ask and describe. +STTL proposes an additional query form: template. + + +The template where query form is used to specify a text pattern that is instantiated with the results of the where clause. It is similar to the construct clause but generates text instead of generating RDF triples. +The text pattern is made of constants (literals) and evaluable expressions (variables, function calls, etc.). +
+ + ++The where clause is executed as a SPARQL query where clause, with focus node bound to variable ?in if any, producing a solution sequence. It must be noted that the from, from named, order by, group by, having, limit, offset and values clauses are available for templates with the same syntax and semantics as SPARQL. +
+ ++The template clause is instantiated for each solution of the where clause, producing a text for each solution. +Variables in the template clause are replaced by their value from the solution, using by default the Turtle syntax. +The result of a template is the concatenation of the text results produced by all the solutions. +It must be noted that aggregates are available in the template clause with the same semantics as SPARQL. In the case of aggregates, the aggregate operations are performed, possibly with group by, thus producing a new solution sequence. The template clause is evaluated on the solution sequence resulting from the aggregate. +
+ ++The example below lists all the triples linking URI in the current RDF graph in NTriple format. +
+ ++template { + ?in " " ?p " " ?o " ." +} +where { + ?in ?p ?o + filter (isURI(?in) && isURI(?o)) +} ++ + + + +
+A template can have a name (an URI) and parameters. +In the example shown below, the name of the template is ex:display and the parameter list is (?x). +
+ + ++template ex:display(?x) { + st:apply-templates(?y) +} +where { + ?x foaf:knows ?y +} ++ + + + + + +
+ + +
+The data model used by STTL is the same as the one used by SPARQL: RDF Dataset. +The data model used by STTL is the RDF Dataset resulting from the parsing of the input RDF document(s) whatever their syntax is: RDF/XML, Turtle, N3, JSON-LD or RDFa. + +If the triple store is provided with an entailment regime (e.g. RDFS), STTL exploits the entailments in the same way than SPARQL. +
+ + + ++The result of a transformation is a text, that is a character stream. +The text can be structured (HTML, RDF/XML, XML, etc.), it can represent statements of a language (e.g. Turtle, SPARQL, OWL functional syntax, etc.), it can be natural language, etc. +
+ + + + + ++ + + + +
+In the process of finding the applicable template, more than one template may be eligible. In the +general case, only one template will be applied. If no indication is given the first template applied +following the order of the .rq files or the RDF document. +Alternatively, if the possible templates have specified priorities, the template with the highest priority is chosen. +
+ + + + + ++A template in a transformation may apply other templates. This is done using the st:apply-templates extension function. Below is an example of template which generates the functional syntax of an OWL allValuesFrom restriction statement. +
+ ++template { + "allValuesFrom(" + st:apply-templates(?p) " " + st:apply-templates(?c) + ")" +} +where { + ?in a owl:Restriction ; + owl:onProperty ?p ; + owl:allValuesFrom ?c . +} ++ + +
The previous template when applied to :
+ + ++[] a owl:Restriction ; + owl:onProperty foaf:knows ; + owl:allValuesFrom foaf:Person . ++ +
generates the text below:
+ + ++allValuesFrom(foaf:knows foaf:Person) ++ +
+In the template above, two variables occur in the template clause: ?p and ?c. These variables are recursively processed by the st:apply-templates extension function using the set of templates of the transformation. +If no template succeeds, a default format is generated which is the Turtle format. +The where clause is the same as in SPARQL, except that variable ?in is bound to the focus node. The focus node is the node that is the argument of the current st:apply-templates function call. +
+ ++The st:apply-templates function applies the first template in the transformation such that 1) the template were not already applied on the same focus node previously, 2) +the where clause, with its ?in variable bound to the focus node, returns a solution sequence that is not empty and 3) the template clause does not raise an error. +
+ + ++Note that the st:apply-templates function can be called in the where part as shown below. +
+ + ++template { + "allValuesFrom(" ?pp " " ?cc ")" +} +where { + ?in a owl:Restriction ; + owl:onProperty ?p ; + owl:allValuesFrom ?c . + bind (st:apply-templates(?p) as ?pp) + bind (st:apply-templates(?c) as ?cc) +} ++ + + +
+A named template is called by name with parameter values using the st:call-template function. When several parameters occur, parameter passing is done by position (i.e. not by name). +
+ + ++template { + st:call-template(ex:display, ?in) +} +where { + ?in a foaf:Person +} ++ + + + +
+The result of a template is the concatenation of the texts resulting from the instantiation of the template clause on every solution of the +where clause. +By default, a newline character is inserted as separator between text solutions. It is possible to overload the separator using the separator statement, similar to the SPARQL group_concat aggregate separator statement as shown below. +
+ ++template { + ?name ; separator = ", " +} +where { + ?in foaf:name ?name +} ++ + + + + + + + + + + + + + +
+In order to apply templates, the language provides a set of SPARQL extension functions. Running a transformation engine on a set of templates is done by an initial call to st:apply-templates-with in a SPARQL query (or a template) where the st-uri argument is the URI of the transformation. This function can also be used to apply another transformation within a transformation. Hence a complex transformation can be split into simpler ones. + +The uri argument of st:call-template is the name of a template. +The term argument is the focus node, it is an RDF term. +
+ ++In some cases, it is necessary to apply several templates in order to transform a focus node. In this case, the st:apply-templates-all function may be used. The result of st:apply-templates-all is the concatenation of the results of all the templates that succeed. +
+ ++The st:apply-templates-graph functions enables the transformer to focus on a specific named graph. The graph-uri argument is the name of a graph. +
+ + ++The st:call-template functions enables the transformer to call a specific named template. The uri argument is the name of a named template. +
+ ++st:apply-templates(term) + +st:apply-templates-with(st-uri) +st:apply-templates-with(st-uri, term) + +st:apply-templates-all(term) +st:apply-templates-with-all(st-uri, term) + +st:apply-templates-graph(graph-uri) +st:apply-templates-with-graph(st-uri, graph-uri) + +st:call-template(uri, term_1, .., term_n) +st:call-template-with(st-uri, uri, term_1, .., term_n) ++ + + + + + + +
+There are aditional utility functions. +
+ ++st:turtle(term) + +st:format(text-format, term, ...) + +st:number() + +st:nl() ++ + +
+st:turtle returns the Turtle format of an RDF term.
+
+
+st:format given a text pattern with %s text variables and expressions, returns a formatted string.
+
+
+st:number returns a number corresponding to the solution position.
+
+
+st:nl returns a new line and take indentation defined by box into account.
+
+SPARQL functions can be used in the template clause. +
+ ++template { + "The name of " xsd:string(?in) " is " xsd:string(?n) "." +} +where { + ?in foaf:name ?n +} ++ + + + +
+ + + + +
+STTL provides a "hook" to define extension functions that are available within a transformation. + +To do so, STTL provides a simple formalism to define SPARQL extension functions. +The function clause enables users to define a function with an URI as name and a list of parameter variables. +The body of the function is defined using SPARQL filter language. +
+ ++function ex:display(?x) { + if (isURI(?x), + concat("<", str(?x), ">"), + str(?x)) +} + +function ex:fac(?n) { + if (?n = 0, 1, ?n * ex:fac(?n - 1)) +} ++ + + + +
+As there are no natural root nodes in a graph, we provide the possibility to define a specific start template that determines the nodes to start with. The start template, if any, is the st:start named template. Otherwise, the first template of the transformation that succeeds is applied. +
+ ++template st:start { + st:apply-templates(?x) +} +where { + ?x a foaf:Person +} ++ + + + +
+The st:profile named template enables users to define extension functions. This template is not executed (this is why it is empty), it is a place holder for function definition and it is considered at compile time only. + +By convention, function definitions that are listed below the st:profile template are available for all templates of the transformation. +
+ ++Function st:process is a predefined function that specifies the processing of variables in the template clause. +The default behaviour is to call st:turtle to generate the Turtle format of the argument. +This function can be overloaded. +
+ ++In the example below, st:apply-templates is called on blank nodes and +st:turtle is called on URIs and literals. +
+ + ++template st:profile {} +where {} + +function st:process(?x) { + if (isBlank(?x), st:apply-templates(?x), st:turtle(?x)) +} ++ + + + + + + + +
+STTL provides a mechanism to attach a priority to templates. In the case where several templates may be applied, the one with the highest priority is chosen. + +In the case where several templates may succeed, it may be necessay to sort templates according to an explicit priority. Smaller numbers represent higher priority. +
+ ++Pragma enables to define priority. It +may be used in the future to define new features. +
+ ++template { ... } +where { ... } +pragma { st:template st:priority 1 } ++ + + +
+ + + + +
+Conditional processing is done using SPARQL if then else filter expression. +
++template { + if (?age >= 18, + st:call-template(st:adult, ?in), + st:call-template(st:child, ?in)) +} +where { + ?in foaf:age ?age +} ++ + + +
+The combined use of if, st:call-template and recursion enables to implement powerful processing such as printing the development of n!. +
+ ++template st:fac(?n) { + if (?n = 0, 1, + concat(?n, ".", st:call-template(st:fac, ?n - 1))) +} +where {} ++ + + + +
+Sorting is done using SPARQL order by clause. +
+ ++template { + st:apply-templates(?in) +} +where { + ?in a foaf:Person ; + foaf:name ?name +} +order by ?name ++ + + + + + + +
+The group statement is syntactic sugar for group_concat() aggregate operation, except that it can have several arguments. In addition, it can have a separator which acts in the same way as SPARQL group_concat aggregate separator. + +Below is an example that concatenates the elements of a list. +
+ + ++template { + "list(" + group { ?elem } + ")" +} +where { + ?in rdf:rest*/rdf:first ?elem +} ++ + +
+ +
+ + + + + + ++Box enable to increment the indentation of the output character stream when st:nl() is used. +
+ + ++template { + "list(" + box { + group { ?elem st:nl() } + } + ")" +} +where { + ?in rdf:rest*/rdf:first ?elem +} ++ + + + +
+Format enable to specify a string pattern with text variables (%s) and a list of expressions. Text variables are replaced by the values of expressions. +
+ + ++template { + format { + "<h1>%s</h1><p>%s</p>" + ?title ?text + } +} +where { + ?in ex:title ?title ; ex:text ?text +} ++ + + + + + + + + + + + + +
+ + + + + + +
+We provide the syntax of SPARQL template, based on +SPARQL 1.1 grammar. +
++Template ::= + Prologue + TemplateClause + DatasetClause* + WhereClause + SolutionModifier + ValuesClause + Pragma + Function* + +TemplateClause ::= + 'template' NameArg ? '{' + TExpression * + Separator ? + '}' + +TExpression ::= PrimaryExpression | Box | Format | Group + +NameArg ::= (iri VarList) | VarList + +VarList ::= '(' Var * ')' + +Group ::= + 'group' ( 'distinct' ) ? '{' + ( PrimaryExpression | Box | Format ) * + Separator ? + '}' + +Box ::= + 'box' '{' TExpression * '}' + +Format ::= + 'format' '{' + PrimaryExpression + TExpression + + '}' + +Separator ::= ';' 'separator' '=' String + +Pragma ::= ( 'pragma' '{' Triple+ '}' ) ? + +Function ::= 'function' iri VarList '{' PrimaryExpression '}' ++ + + + +
+Syntax of the RDF document for tranformations is given in RDF/XML format. +Each template must define its prefix and namespaces. +
+ ++<rdf:RDF + xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' + xmlns='http://ns.inria.fr/sparql-template/'> + +<rule> +<body> +<![CDATA[ +prefix st: <http://ns.inria.fr/sparql-template/> +template st:list(?l) { + ?e +} +where { + ?l rdf:rest*/rdf:first ?e +} +]]> +</body> +</rule> + +<rule> +<body> +... +</body> +</rule> + +</rdf:RDF> ++ + + + +
+ + + + + + + +
+SPARQL Templates are compiled as select-where SPARQL queries where variables in the template clause are replaced by a call to the st:process extension function. Its default behaviour is to call st:turtle. +When st:process is bound to st:apply-templates in the profile, it implements the recursive call to the transformation engine. This function plays a similar role as the xsl:apply-templates clause in XSLT. +Its behavior consists in executing templates one by one from the set of templates until one of them succeeds. The result of the st:apply-templates function call is the result of this successful template execution. +
+ ++A template succeeds if the evaluation of the where clause returns solution(s) and if the evaluation of the template clause does not raise an error. An error may be caused by an unbound variable. +
+ ++The focus node is the node that the transformation engine is processing at the current time. +It is bound to a distinguished ?in variable the value of which is determined at run time by a process equivalent to the one shown below where the st:getFocusNode() function +represents the focus node value determined from the environment. +
+ ++The template below: +
+ ++template { + "allValuesFrom(" ?p " " ?c ")" +} +where { + ?in a owl:Restriction ; + owl:onProperty ?p ; + owl:allValuesFrom ?c . +} ++ +
+is compiled into a select-where SPARQL query as shown below. The st:concat function is similar to the SPARQL concat function. +
+ ++select + (st:concat ( + "allValuesFrom(", + st:process(?p), " ", st:process(?c), ")") + as ?out) +where { + bind (st:getFocusNode() as ?in) . + ?in a owl:Restriction ; + owl:onProperty ?p ; + owl:allValuesFrom ?c . +} ++ + +
+Executing a template consists first in executing the where part which results in a solution sequence (i. e. variable bindings). + +Then the select clause is executed, providing a solution sequence extended with the projected variable ?out. +This is standard SPARQL query execution. + +To finish, an additional group_concat(?out) aggregate operation is performed on the SPARQL solution sequence, resulting into one solution where all values of the ?out variable are concatenated into a string value. This is the final result of the template and this is the result returned by the st:apply-templates function. +Hence, it is possible to implement a STTL engine on top of a SPARQL interpreter using extension functions. +
+ + + ++The group statement: +
+ ++template { + "list(" + group { ?x ?y } + ")" +} +where { + ... +} ++ +
+is compiled as: +
+ ++select + (st:concat("list(", group_concat(concat(st:process(?x), st:process(?y))), ")") + as ?out) +where { + ... +} ++ + + + + +
+ + + + + +
+We present some use cases for STTL. +
+ ++List the content of a graph in Turtle syntax. +
+ ++template { + ?x " " ?p " " ?y "." +} +where { + ?x ?p ?y +} +order by ?x ?p ?y ++ + +
+List the named graphs of a Dataset in Trig syntax. +
+ ++template { + "graph " ?g " {\n" + group { ?x " " ?p " " ?y ".\n" } + "}" +} +where { + graph ?g { ?x ?p ?y } +} +group by ?g +order by ?g ++ + +
+Generate an HTML table with the triples of the RDF graph. +
+ ++template { + format { + """ + <html> + <body> + <table>%s</table> + </body> + </html> + """ + + group { + format { + "<tr><td>%s</td><td>%s</td><td>%s</td></tr>\n" + ?s ?p ?o + } + } + } +} +where { + ?s ?p ?o +} +order by ?s ?p ?o ++ + + + + + + + + + + + +
+ + + + +
+SPARQL Template Transformation Language aims at generating presentation format for RDF graphs. It is designed as an extension of SPARQL 1.1 Query Language. +STTL is available in the Corese Semantic Web Factory and it is used in the Corese Web server. +Preliminary works show that STTL can also be used to perform constraint checking with templates that return boolean values instead of text. +
+ + + ++ + + +