Search code examples
rubysparqlrdf

Creating a pattern from a property path


Given an RDF::URI and a SPARQL property path (stored as a String), I want to find values that satisfy the following query

SELECT ?value WHERE {
    <URI> <property_path> ?value .
}

I managed to get by using the following snippet, but is feels very hackish:

query = SPARQL.parse(<<~QUERY)       
  SELECT ?value WHERE {              
    <#{uri}> #{property_path} ?value     
  }                                  
QUERY                                
graph.query(query)

Is there a better way to achieve this, using a RDF::Query for example?


Solution

  • From my understanding, you consider string interpolation to be "hackish" because you would like to deal with "things, not strings". This desire is definitely not reprehensible in a Semantic Web related field.

    If so, you could construct queries using SPARQL::Algebra.

    All snippets below have the same meaning:

    SPARQL query (q1)

    SELECT ?value WHERE {              
        <http://example.org/green-goblin>
        <http://www.w3.org/2000/01/rdf-schema#label>|<http://xmlns.com/foaf/0.1/name>
        ?value .    
    }
    

    SPARQL Algebra expression (q2)

    (project
        ?value
        (path
            <http://example.org/green-goblin>
            (alt
                <http://www.w3.org/2000/01/rdf-schema#label>
                <http://xmlns.com/foaf/0.1/name>
            )
            ?value
        )
    )    
    

    Ruby code (q3)

    Operator::Project.new(
        Variable(:value),
        Operator::Path.new(
            RDF::URI('http://example.org/green-goblin'),
            Operator::Alt.new(
                RDF::URI('http://www.w3.org/2000/01/rdf-schema#label'),
                RDF::URI('http://xmlns.com/foaf/0.1/name')
            ),
        Variable(:value)
        )
    )
    

    Compare internal representations or queries results:

    require 'rubygems'
    require 'sparql'
    require 'sparql/algebra'
    
    include SPARQL::Algebra
    
    query1 = SPARQL.parse(q1) 
    query2 = SPARQL::Algebra::Expression.parse(q2)
    query3 = eval(q3)
    
    puts query1.to_sxp
    puts query2.to_sxp
    puts query3.to_sxp
    
    query1.execute(queryable) do |result|
      puts result.inspect
    end
    
    query2.execute(queryable) do |result|
      puts result.inspect
    end
    
    query3.execute(queryable) do |result|
      puts result.inspect
    end
    

    The difference is that you do not need string manipulations in the third case.
    These "operators" even have URIs (e.g. Operator[:project]).