XQuery/DBpedia with SPARQL and Simile Timeline - Album Chronology

In this example, the SIMILE project's Timeline JavaScript is used to display the chronology of the albums released by a selected artist or group. As with the football teams in the previous example, the data is extracted from DBpedia via a SPARQL query.

This example has three components:

  • an XQuery script which creates the HTML page, linking to the Timeline JavaScript
  • an XQuery script to query DBpedia for albums for a selected group, assign a year of release to each album and generate a set of events in the form expected by the TimeLine script.
  • an XQuery script to provide an index of groups in a given category

HTML Page script edit

The script accepts one parameter, the name of the artist or group. The JavaScript required to customize the Timeline is defined in-line in a CDATA section. The onLoad function accepts two parameters, the name of the artist and a date to provide the initial focus for the timeline. The event stream is provided by the call to the XQuery script group2tl.xq, passing the group name.

The JavaScript interface here is minimal.

declare option exist:serialize "method=xhtml media-type=text/html";

let $group:= request:get-parameter("group","Eagles")
return
<html>
    <head>
        <script src="http://simile.mit.edu/timeline/api/timeline-api.js" type="text/javascript"></script>
        <script  type="text/javascript">
        <![CDATA[
function onLoad(group,start) {
  var theme = Timeline.ClassicTheme.create();
  theme.event.label.width = 400; // px
  theme.event.bubble.width = 300;
  theme.event.bubble.height = 300;

  var eventSource1 = new Timeline.DefaultEventSource();

  var bandInfo = [
    Timeline.createBandInfo({
        eventSource:    eventSource1,
        theme:          theme,
        date:           start,
        width:          "100%", 
        intervalUnit:   Timeline.DateTime.YEAR, 
        intervalPixels: 45
    }),

  ];
  Timeline.create(document.getElementById("my-timeline"), bandInfo);
  Timeline.loadXML("group2tl.xq?group="+group, function(xml, url) { eventSource1.loadXML(xml, url); });

}
 ]]>
        </script>  
    </head>
    <body onload="onLoad('{$group}',1980);">
        <h1>{$group} Albums</h1>
        <div id="my-timeline" style="height: 700px; border: 1px solid #aaa"></div>
    </body>
</html>


TimeLine events group2tl.xq edit

This script has a similar structure to the football team script. A prototype SPARQL query is edited to change the default name to the supplied name, the query sent to the DBpedia SPARQL service and the resultant SPARQL XML result converted to XML tuples.

Note - the group name needs an additional encoding because SPARQL requires URIs to be uri encoded and group names may contain characters such as ( and ) which require encoding. Hence Queen_(band) must appear in the URI in SPARQL as Queen_%28band%29. In addition the whole query is uri encoded which allows this encoding to be recovered when the whole query is decoded by the SPARQL service. (Whew!)

As with the Football clubs, there may be multiple tuples for the same album and the best (at present just the first non null) set of data needs to be extracted from these tuples. The year of release is hacked out of the multitude of different date formats which may appear and each album represented in the format expected by Timeline, with the pop-up contents serialised. This is limited to the album cover if available and links to DBpedia and Wikipedia.

declare namespace r = "http://www.w3.org/2005/sparql-results#";

declare variable $query := "
PREFIX p: <http://dbpedia.org/property/>  
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT * WHERE { 
     ?album p:artist  <http://dbpedia.org/resource/The_Allman_Brothers_Band>.       
     ?album rdf:type <http://dbpedia.org/class/yago/Album106591815>.
     OPTIONAL {?album p:cover ?cover}.
     OPTIONAL {?album p:name ?name}.
     OPTIONAL {?album p:released ?dateofrelease}.
   }
 ";

declare function local:execute-sparql($query as xs:string) {
  let $sparql := concat("http://dbpedia.org/sparql?format=xml&default-graph-uri=http://dbpedia.org&query=",
                    encode-for-uri($query) 
                 )
  return  doc($sparql)
};

declare function local:sparql-to-tuples($rdfxml ) {
   for $result in $rdfxml//r:result
   return
     <tuple>
            { for $binding  in $result/r:binding
               return                
                 if ($binding/r:uri)
                     then   element {$binding/@name}  {
                                    attribute type  {"uri"} , 
                                    string($binding/r:uri) 
                                }
                     else   element {$binding/@name}  {
                                    attribute type {$binding/@datatype}, 
                                    string($binding/r:literal)
                               }
             }
      </tuple>
 };

declare function local:clean($text) {
    let $text:= util:unescape-uri($text,"UTF-8")
    let $text := replace($text,"http://dbpedia.org/resource/","")
    let $text := replace($text,"\(.*\)","")
    let $text := replace($text,"_"," ")
    return $text
};

declare function local:year-from-date($d) {
   let $d := replace($d,"[^0-9\-]","")
   let $dp := tokenize($d,"-")
   let $year := $dp[1]
   return 
      if ($year castable as xs:integer and string-length($year)=4)
      then $year
      else ()
};
 
let $group := request:get-parameter ("group","The_Allman_Brothers_Band")
let $groupx := replace($group," ","_")
let $queryx := replace($query,"The_Allman_Brothers_Band",encode-for-uri($group))
let $result  := local:execute-sparql($queryx)
let $tuples := local:sparql-to-tuples($result)
return
<data>
   {for $album in distinct-values($tuples/album)
    let $rows := $tuples[album=$album]
    let $name := local:clean($album)
    let $year := local:year-from-date(($rows/dateofrelease)[1]) 
    let $cover := ($rows/cover)[1]
    where exists($year)
    return      
        <event start="{$year}" title="{$name}">
          {util:serialize(
          <div>
            {if (starts-with($cover,"http://")) then <img src="{$cover}" height="200" alt=""/> else () }
             <p><a href="{$album}">DBpedia</a> <a href="{replace($album,"dbpedia.org/resource","en.wikipedia.org/wiki")}">Wikipedia</a></p>
           </div>
           , "method=xhtml")
          }
         </event>
    }
 </data>

Execution edit

Group Index edit

This script queries DBpedia for the resources which belong to a specified category, for example Rock_and_Roll_Hall_of_Fame_inductees. A table of group names in alphabetical order provides links to the Timeline view using the script above, and to an HTML table view of the discography.


declare namespace r = "http://www.w3.org/2005/sparql-results#";

declare option exist:serialize "method=xhtml media-type=text/html";
declare variable $query := "
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX p: <http://dbpedia.org/property/> 
SELECT * WHERE { 
      ?group  skos:subject <http://dbpedia.org/resource/Category:Rock_and_Roll_Hall_of_Fame_inductees>.
   }
 ";
 
declare function local:execute-sparql($query as xs:string) {
  let $sparql := concat("http://dbpedia.org/sparql?format=xml&default-graph-uri=http://dbpedia.org&query=",
                   escape-uri($query,true()) 
                  )
  return  doc($sparql)
};

declare function local:clean($text) {
    let $text:= util:unescape-uri($text,"UTF-8")
    let $text := replace($text,"\(.*\)","")
    let $text := replace($text,"_"," ")
    return $text
};

let $category := request:get-parameter("category","Rock_and_Roll_Hall_of_Fame_inductees")
let $queryx := replace($query,"Rock_and_Roll_Hall_of_Fame_inductees",$category)
let $result  := local:execute-sparql($queryx)
return
<html>
<body>
  <h1>{local:clean($category)}</h1>
  <table border="1">
  {$result}
   {  for $group in $result//r:result/r:binding[@name="group"]/r:uri
      let $name := substring-after($group,"resource/")
      let $namex := local:clean($name)
      order by $name
      return      
        <tr>
           <td>{$namex}</td>
           <td><a href="group2html.xq?group={$name}">HTML</a></td>
           <td><a href="groupTimeline.xq?group={$name}">Timeline</a></td>
         </tr>
   }
   </table>
 </body>
 </html>


Index of Rock and Roll Groups and Artists

Category Index edit