SPARQL query to get all parent of a node

Your data can be represented in RDF as data.n3:

@prefix : <http://example.org/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

:Network rdfs:subClassOf :Main .

:ATM rdfs:subClassOf :Network .
:ARPANET rdfs:subClassOf :Network .

:Software rdfs:subClassOf :Main .

:Linux rdfs:subClassOf :Software .
:Windows rdfs:subClassOf :Software .

:XP rdfs:subClassOf :Windows .
:Win7 rdfs:subClassOf :Windows .
:Win8 rdfs:subClassOf :Windows .

From here, you just want a SPARQL query that finds all the things connected to a particular class by a path (including the empty path) of rdfs:subClassOf properties.

prefix : <http://example.org/>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>

select ?superclass where { 
  :Win7 rdfs:subClassOf* ?superclass
}
--------------
| superclass |
==============
| :Win7      |
| :Windows   |
| :Software  |
| :Main      |
--------------

The results in that query aren’t necessarily ordered by their position in the path (though in this case they happen to be). If you do need them in order, you can do this (which is based on this answer about computing the position of elements in an RDF list):

prefix : <http://example.org/>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>

select ?class where { 
  :Win7 rdfs:subClassOf* ?mid .
  ?mid rdfs:subClassOf* ?class .
}
group by ?class
order by count(?mid)

This finds each ancestor ?class of :Win7 as well as each ?mid intermediate ancestor. For ancestor ?class, the distance is computed as the number of intermediate relations in between (count(?mid)). It orders the results based that distance, so :Win7 is the closest ancestor, :Windows after that, and so on.

You can even do some of the fancy formatting you want like this:

prefix : <http://example.org/>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>

select (group_concat( ?name ; separator="--" )  as ?path) where {
  {
    select ?name where { 
      :Win7 rdfs:subClassOf* ?mid .
      ?mid rdfs:subClassOf* ?class .
      bind( strAfter( str(?class), "http://example.org/") as ?name )
    }
    group by ?class ?name
    order by count(?mid)
  }
}
-----------------------------------
| path                            |
===================================
| "Win7--Windows--Software--Main" |
-----------------------------------

It might be possible to do some fancier string processing and to get the multiline string. You might look at the latter part of this answer where there is some fancy formatting for a nicely aligned matrix for ideas.

Leave a Comment