geojsonwikidatawikimediawikimedia-commons

Get geojson data from Wikidata


I request Wikidata entities and get their geoshape property (P3896).

For example (try it):

SELECT ?item ?itemLabel ?geoshape ?geoshapeLabel
WHERE
{
  VALUES ?item { wd:Q142 }
  ?item wdt:P3896 ?geoshape.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

So I get an url: http://commons.wikimedia.org/data/main/Data:France.map

I tried to fetch data with Javascript:

But I got error due to CORS policy:

No 'Access-Control-Allow-Origin' header is present on the requested resource.

Is there any way to get geojson data from Wikidata from web application?


Solution

  • According to @Pascalo we can use

    fetch('https://commons.wikimedia.org/w/api.php?action=query&prop=revisions&rvslots=*&rvprop=content&format=json&titles=Data:France.map&origin=*')
    

    The complete JS solution to get geojson data from Wikidata can be the following:

    class SPARQLQueryDispatcher {
      constructor(endpoint) {
        this.endpoint = endpoint;
      }
      query(sparqlQuery, simplify = true) {
        const fullUrl = this.endpoint + "?query=" + encodeURIComponent(sparqlQuery);
        const headers = {
          Accept: "application/sparql-results+json"
        };
        return fetch(fullUrl, {
            headers
          })
          .then(body => body.json())
          .then(data => (simplify ? this.simplify(data) : data));
      }
      simplify(data) {
        const bindings = data.results.bindings;
        return bindings.map(binding => {
          Object.keys(binding).forEach(function(key, index) {
            binding[key] = binding[key].value;
          });
          return binding;
        });
      }
    }
    
    function buildQuery(ids) {
      const wds = ids.map(id => `wd:${id}`).join(" ");
      return `
    SELECT ?item ?itemLabel ?geoshape ?geoshapeLabel
    WHERE
    {
      VALUES ?item { ${wds} }
      ?item wdt:P3896 ?geoshape.
      SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
    }
    `;
    }
    
    function fetchGeojson(rows) {
      const titles = rows
        .filter(r => r.geoshape)
        .map(r => r.geoshape.split("/data/main/").pop())
        .join("|");
      return fetch(`https://commons.wikimedia.org/w/api.php?action=query&prop=revisions&rvslots=*&rvprop=content&format=json&titles=${titles}&origin=*`)
        .then(r => r.json())
        .then(r => Object.values(r.query.pages))
        .then(r => r.map(r => JSON.parse(r.revisions[0].slots.main["*"]).data));
    }
    
    const queryDispatcher = new SPARQLQueryDispatcher("https://query.wikidata.org/sparql");
    const query = buildQuery(["Q90"]); // Q90 = Paris
    
    queryDispatcher
      .query(query)
      .then(fetchGeojson)
      .then(console.log);