Search code examples
sparqlrdf

SPARQL query template with language filters


I'm pretty new with SPARQL and I'm trying to insert some kind of language filter for literals returned by my query template. The problem is the dataset doesn't provide a well structured tagging system so I got to restrict results in some conditional way AND make these conditions work with the following template:

SELECT distinct ?s ?p ?o WHERE {      
  ?this :is :something. // this pattern is passed as argument 
                        // to the js func that manage the 
                        // query
  {
   bind(?this as ?s)
   ?s ?p ?o.       
   // here i putted my filters
  }
}

The filter I want to add should provide a way to return only the "english version" for patterns with literals. if no english version is provided then return the untagged one - there is always an untagged one.

Based on solutions for similar questions, I tried with this:

filter(!isLiteral(?o) || (langMatches(lang(?o), 'en')) || lang(?o)='')

but - of course - ends up returning both: english and untagged literals.

Another way, that solved the problem for someone, is using two OPTIONAL pattern like here:

optional { 
  ?country rdfs:label ?label
  filter langMatches(lang(?label), "en")
}
optional { 
  ?country rdfs:label ?label
}

but I have the ?s ?p ?o pattern in my template that already returns all the triples associated with a specific subject, then optional patterns seems useless here.

I've read other questions similar to these but no one seems to fits my query template, so if someone can help me understanding this I'll be grateful.


Solution

  • If I'm interpretting your question right, it is doable using a single FILTER with several disjuncts ordered in manner of preference, e.g. like:

    PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
    select * where { 
        bind(skos:member as ?s)
            ?s ?p ?o .
            filter (
                !isLiteral(?o) ||
                langmatches(lang(?o), "en") 
                || (langmatches(lang(?o), "") && not exists {
                        ?s ?p ?other. 
                        filter(isLiteral(?other) && langmatches(lang(?other), "en")) 
                    }))
    
    } 
    
    • it will pass for any non-literal value bount ot ?o
    • then for literals with language tag that match @en
    • and finally, literals without language tag, for which there is no statement with the same subject and predicate, that has a literal with @en tag

    HTH

    the use of skos:member in the query above is just to have something bound to the ?s and it is arbitraty ...