从 Wikidata 获取 geojson 数据
Get geojson data from Wikidata
我请求维基数据实体并获取它们的 geoshape property (P3896)。
例如 (try it):
SELECT ?item ?itemLabel ?geoshape ?geoshapeLabel
WHERE
{
VALUES ?item { wd:Q142 }
?item wdt:P3896 ?geoshape.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
所以我得到一个url:http://commons.wikimedia.org/data/main/Data:France.map
我尝试使用 Javascript 获取数据:
fetch('http://commons.wikimedia.org/data/main/Data:France.map?origin=*')
fetch('https://commons.wikimedia.org/w/index.php?title=Data:France.map&action=raw&origin=*')
但是由于 CORS 政策我遇到了错误:
No 'Access-Control-Allow-Origin' header is present on the requested
resource.
有没有办法从 Web 应用程序中获取 Wikidata 的 geojson 数据?
根据@Pascalo我们可以使用
fetch('https://commons.wikimedia.org/w/api.php?action=query&prop=revisions&rvslots=*&rvprop=content&format=json&titles=Data:France.map&origin=*')
从维基数据获取geojson数据的完整JS方案可以如下:
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);
我请求维基数据实体并获取它们的 geoshape property (P3896)。
例如 (try it):
SELECT ?item ?itemLabel ?geoshape ?geoshapeLabel
WHERE
{
VALUES ?item { wd:Q142 }
?item wdt:P3896 ?geoshape.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
所以我得到一个url:http://commons.wikimedia.org/data/main/Data:France.map
我尝试使用 Javascript 获取数据:
fetch('http://commons.wikimedia.org/data/main/Data:France.map?origin=*')
fetch('https://commons.wikimedia.org/w/index.php?title=Data:France.map&action=raw&origin=*')
但是由于 CORS 政策我遇到了错误:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
有没有办法从 Web 应用程序中获取 Wikidata 的 geojson 数据?
根据@Pascalo我们可以使用
fetch('https://commons.wikimedia.org/w/api.php?action=query&prop=revisions&rvslots=*&rvprop=content&format=json&titles=Data:France.map&origin=*')
从维基数据获取geojson数据的完整JS方案可以如下:
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);