Javascript实现关联数据(Linked Data)查询及注意细节

前言

  自由百科全书不仅仅应当可以自由编写,而更应该可以自由获得。

  DBpedia对Wikipedia的数据变成Linked Data形式,使得机器也能读懂并自由获得这些数据。

  本文的主要目的是利用Javascript从DBpedia中获取我们想要的数据。

  对Linked Data不太了解的请参考:关联数据入门——RDF

  SPARQL

  Trying to use the Semantic Web without SPARQL is like trying to use a relational database without SQL.

  —— Tim Berners-Lee

  SPARQL是Semantic Web(语义网)的SQL,用于数据查询的语言。

  SPARQL Endpoint

  SPARQL查询终端,是一种HTTP绑定协议,用于通过HTTP进行SPARQL查询,并返回相应数据。

  DBpedia的SPARQL Endpoint地址是:http://dbpedia.org/sparql

  大家可以通过浏览器打开这个页面,进行SPARQL查询(最好翻墙,没翻墙查询经常失败,不太明白为什么= =)。

  不过这种查询最终返回结果是HTML页面,并不是我们想要的,我们可以通过设置Request Header的Accept属性来指定返回数据类型。

  例如如果指定为:text/xml,那么返回的便是RDF格式数据。

  那么我们如何输入SPARQL查询代码呢?

  只需通过get或者post方法用参数query,将代码传过去。例如:

  如果想查询:select distinct ?Concept where {[] a ?Concept} LIMIT 100

  则可利用该链接得到数据:

  http://dbpedia.org/sparql?query=select%20distinct%20?Concept%20where%20{[]%20a%20?Concept}%20LIMIT%20100

  其中空格被转成%20。

  实现细节

  •跨域

  我们可以通过AJAX实现这一功能,但是AJAX在部分浏览器中无法跨域,然而很显然我们想要的Linked Data几乎都是跨域的。

  实际上,在一些较老版本的浏览器,我们没有不改变其数据形式的方法在前端进行动态跨域异步读取。

  不过我们可以通过服务器代理的方法来解决跨域问题。

  •GET or POST

  使用GET还POST呢?

  这个可能出于很多方面考虑,但是考虑到GET可能被缓存,所以我们使用POST来避免数据被缓存。

  •以什么形式返回数据

  前面我们说到用text/xml可以返回RDF数据,但是RDF在Javascript中并不好处理,所以我们使用json方式返回,也就是需要将Accept设置成application/sparql-results+json。

  实现

  接口参考Python的SPARQL Wrapper

  

复制代码 代码如下:

  (function(root, factory) {

  if(typeof define === "function"){

  define("SPARQLWrapper", factory); // AMD || CMD

  }else{

  root.SPARQLWrapper = factory(); // <script>

  }

  }(this, function(){

  'use strict'

  function SPARQLWrapper(endpoint){

  this.endpoint = endpoint;

  this.queryPart = "";

  this.type = "json";

  }

  SPARQLWrapper.prototype = {

  constructor: SPARQLWrapper,

  setQuery: function(query){

  this.queryPart = "query=" + encodeURI(query);

  },

  setType: function(type){

  this.type = type.toLowerCase();

  },

  query: function(type, callback){

  callback = callback === undefined ? type : this.setType(type) || callback;

  var xhr = new XMLHttpRequest();

  xhr.open('POST', this.endpoint, true);

  xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');

  switch(this.type){

  case "json":

  type = "application/sparql-results+json";

  break;

  case "xml":

  type = "text/xml";

  break;

  case "html":

  type = "text/html";

  break;

  default:

  type = "application/sparql-results+json";

  break;

  }

  xhr.setRequestHeader("Accept", type);

  xhr.onreadystatechange = function(){

  if(xhr.readyState == 4){

  var sta = xhr.status;

  if(sta == 200 || sta == 304){

  callback(xhr.responseText);

  }else{

  console && console.error("Sparql query error: " + xhr.status + " " + xhr.responseText);

  }

  window.setTimeout(function(){

  xhr.onreadystatechange= new Function();

  xhr = null;

  },0);

  }

  }

  xhr.send(this.queryPart);

  }

  }

  return SPARQLWrapper;

  }));

  使用方法,例如需要查询:

  select distinct ?Concept where {[] a ?Concept} LIMIT 100

  则该页面为:

  

复制代码 代码如下:

  <!DOCTYPE html>

  <html xmlns="http://www.w3.org/1999/xhtml">

  <head>

  <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />

  <script src="SPARQLWrapper.js" type="text/javascript"></script>

  </head>

  <body>

  <script>

  var sparql = new SPARQLWrapper("http://dbpedia.org/sparql");

  sparql.setQuery('select distinct ?Concept where {[] a ?Concept} LIMIT 100');

  sparql.query(function(json){

  console.log(eval('(' + json + ')');

  });

  </script>

  </body>

  </html>

  小例子:下载