You may find this answer, which describes SPARQL's group_concat
, useful:
In SPARQL, when you have a result set of query solutions, you can group
on one or more of the variables, merging solutions that have these variables in common. For instance, consider the data
@prefix : <http://example.org/people/>.
:person1 :hasChild :child1, :child2, :child3 .
:person2 :hasChild :child4, :child5 .
:person3 :hasChild :child6 .
If you run the following query on it
prefix : <http://example.org/people/>
select ?person ?child where {
?person :hasChild ?child .
}
you get results like this:
$ arq --data data.n3 --query query.sparql
----------------------
| person | child |
======================
| :person3 | :child6 |
| :person2 | :child5 |
| :person2 | :child4 |
| :person1 | :child3 |
| :person1 | :child2 |
| :person1 | :child1 |
----------------------
Iterating through the results as you have in your question would produce the type of output that you're currently getting. What we'd like to do is to actually get results like:
$ arq --data data.n3 --query query.sparql
----------------------------------------
| person | child |
========================================
| :person3 | :child6 |
| :person2 | :child4, :child5 |
| :person1 | :child1, :child2, :child3 |
----------------------------------------
and that's exactly what group_by
lets us do. A query like this:
prefix : <http://example.org/people/>
select ?person (group_concat(?child;separator=' and ') as ?children) where {
?person :hasChild ?child .
}
group by ?person
produces (notice that the variable in the result is ?children
, not ?child
, because we've used group_concat(...) as ?children
to create the new variable ?children
):
$ arq --data data.n3 --query query.sparql
---------------------------------------------------------------------------------------------------------------------------
| person | children |
===========================================================================================================================
| :person3 | "http://example.org/people/child6" |
| :person1 | "http://example.org/people/child3 and http://example.org/people/child2 and http://example.org/people/child1" |
| :person2 | "http://example.org/people/child5 and http://example.org/people/child4" |
---------------------------------------------------------------------------------------------------------------------------
If you use a query like this and iterate through the results, printing them as you have, you'll get output like you want. If you do want to strip the leading http://example.org/people/
off from the persons and children, you'll need a bit more string processing. For instance, using STRAFTER to remove the http://example.org/people/
prefix, you can use a query like this:
prefix : <http://example.org/people/>
select
(strafter(str(?personX),"http://example.org/people/") as ?person)
(group_concat(strafter(str(?child),"http://example.org/people/");separator=' and ') as ?children)
where {
?personX :hasChild ?child .
}
group by ?personX
to get results like:
$ arq --data data.n3 --query query.sparql
----------------------------------------------
| person | children |
==============================================
| "person3" | "child6" |
| "person2" | "child5 and child4" |
| "person1" | "child3 and child2 and child1" |
----------------------------------------------
which, when you do your printing, will give you results like
person3 has children child6
person2 has children child5 and child4
person1 has children child3 and child2 and child1