javascriptphpsparqlrdfseasyrdf

Get label only for items that exists on wikidata with php sparql


I am working on a personal project using PHP and RDF4J Workbench Service and I have a repository with 3 contexts, one for robot categories, one for those robots that belongs to these categories and another one in which I store the owl:sameAs property to wikidata identifiers for the initial data.

The problem is that a user can insert robots and the new inserted ones will not be linked to wikidata identifiers but instead will have unique URI's resulted by just removing the extra-space and concatenating the name that user had inserted. Now, when I query for the data I need, I want all these robots to be shown, but if my query is as it follows:

PREFIX : <http://example.com#> 
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> 
PREFIX wdt: <http://www.wikidata.org/prop/direct/> 
PREFIX owl: <http://www.w3.org/2002/07/owl#> 
PREFIX wd: <http://www.wikidata.org/entity/> 
SELECT ?name ?image ?releaseDate ?skills ?manufacturer ?mass
 WHERE { 
         { SELECT ?robot ?image ?releaseDate ?skills ?manufacturer ?mass 
              WHERE {
                     <http://example.com#EducationalRobots> a :Category; :hasRobots [:idRobot ?x] .      
                     ?x owl:sameAs ?robot . 
                     ?x :hasImage ?image . 
                     ?x :releaseDate ?releaseDate . 
                     ?x :hasSkills ?skills . 
                     ?x :manufacturer ?manufacturer. 
                     ?x :hasMass ?mass
                    } 
             } 
    SERVICE <https://query.wikidata.org/sparql> { 
             ?robot rdfs:label ?name .
             FILTER(lang(?name)="en") 
        } 
}

in the end I will only get the initial statements I inserted, those that do have a wikidata identifier linked. So I was thinking of maybe making the difference in the backend, using an if statement where I can ASK if the items from the requested category have an identifier and if so do a specific query, the one from above, else just replace the query and retrieve the local URI. But isn't there a way of doing this directly in the query, so the code will look much cleaner ? Such as SELECT IF statement or so. I am not familiar with advanced query practices and I would appreciate any advice.

Snippet of the graph:

enter image description here

Request:

function getDetails(id) {
  //console.log(id);
  let url = "query.php";
  $.ajax({
    type: "POST",
    url:url,
    data: {"id": id },
    success: function (response){
      let final = JSON.parse(response);
      console.log(final.results);
      $('#tableId').find('tbody')
          .empty();

      final.results.bindings.forEach((item, index)=>{   
        console.log(item);
        if (item.name) { 
          s = item.name;
          id = s.split(" ").join("");  

             $('#tableId').find('tbody')
                .append($(`<tr id=${id} class="border_bottom">`)
                  .append($('<td class="mt-3 text-center">')
                    .append(`<p class='mt-4'><b><i>${item.name.value} </i></b></p><br><button class='btn btn-danger' id='${item.name.value}' onclick="deleteMovie(this.id, '${id}')">Delete</button></div>`)
                  )
                  .append($('<td class="text-center">')
                    .append($('<img height="150" width="250">')
                      .attr('src', 'images/'+item.image.value)
                    )
                  )
                  .append($('<td>')
                    .append($('<small> Manufacturer: </small><p>'+ item.manufacturer.value+ '</p><small>Release date: </small><p>' + item.releaseDate.value +'</p><small>Skills: </small><p>'+item.skills.value +'</p><small> Mass: </small><p>'+item.mass.value + ' kg</p>'))
                  )
                )     
        }
    })   
    }
  });
}

And in the backend I'm working with EasyRdf\Sparql\Client:

<?php

$id = $_POST['id'];

require 'vendor/autoload.php';

$address = "http://localhost:8080/rdf4j-server/repositories/graph?query=";
 
$query = "PREFIX : <http://example.com#> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> 
PREFIX wdt: <http://www.wikidata.org/prop/direct/> 
PREFIX owl: <http://www.w3.org/2002/07/owl#> 
PREFIX wd: <http://www.wikidata.org/entity/> 
SELECT ?name ?image ?releaseDate ?skills ?manufacturer ?mass
 WHERE { { SELECT ?robot ?image ?releaseDate ?skills ?manufacturer ?mass WHERE {<".$id."> a :Category; :hasRobots [:idRobot ?x] . ?x owl:sameAs ?robot . ?x :hasImage ?image . ?x :releaseDate ?releaseDate . ?x :hasSkills ?skills . ?x :manufacturer ?manufacturer. ?x :hasMass ?mass} } SERVICE <https://query.wikidata.org/sparql> { ?robot rdfs:label ?name . FILTER(lang(?name)=\"en\") } }";


$qry = urlencode($query);
//  print $qry;

$client = new EasyRdf\Http\Client($address.$qry);

$client->setHeaders("Accept","application/sparql-results+json");

$resultJSON = $client->request()->getBody();

// print $resultJSON;

$finalResult = new EasyRdf\Sparql\Result($rezultatJSON,"application/sparql-results+json");
// print $finalResult;

return $finalResult;

Thank you !


Solution

  • The final query:

    PREFIX : <http://example.com#>  
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>  
    PREFIX wdt: <http://www.wikidata.org/prop/direct/>  
    PREFIX owl: <http://www.w3.org/2002/07/owl#>  
    PREFIX wd: <http://www.wikidata.org/entity/>  
    
    SELECT ?name ?image ?releaseDate ?skills ?manufacturer ?mass 
    FROM :robots FROM :samenessgraph FROM :categories  WHERE {
      :EducationalRobots a :Category; :hasRobots [:idRobot ?x] .                            
      ?x :hasImage ?image .   
      ?x :releaseDate ?releaseDate .  
      ?x :hasSkills ?skills .   
      ?x :manufacturer ?manufacturer .   
        ?x :hasMass ?mass . 
      OPTIONAL { ?x owl:sameAs ?robot } 
      BIND(COALESCE(?robot, "unknown") as ?input) OPTIONAL {     
        SERVICE <https://query.wikidata.org/sparql> {               
          ?input rdfs:label ?wdName .              
          FILTER(lang(?name)="en")          
        }          
      }     
      OPTIONAL { ?x rdfs:label ?label }     
      BIND(COALESCE(?wdName, ?label, strafter(str(?x), str(:))) as ?name) }
    

    as mentioned in the comments.