Schlagwort-Archive: HTML

Content-Negotiation mit Grails

Content-Negotiation, zu Deutsch Inhaltsvereinbarung, ermöglicht es dem Webserver unterschiedliche Repräsentationen einer Resource an den Client auszuliefern und ist damit eine wichtige Funktion im Web of Data. Nehmen wir zum Beispiel an, die folgende URI identifiziert die Stadt Berlin:

http://example.com/city/berlin

Web-Browser fordern für gewöhnlich HTML-Dokumente an und sollen daher beim Abruf dieser URI eine schön aufbereitete Webseite mit Informationen über Berlin und ggf. ein paar Bilder ausgeliefert bekommen. Gleichzeitig sollen jedoch auch RDF-Daten über Berlin im Web of Data verfügbar gemacht werden.

In bin ein großer Freund des Grails Web-Frameworks, welches ich sowohl beruflich als auch privat nutze. Mit Grails wird – neben so ziemlich allem was Web-Entwicklung angeht – auch die Content-Negotiation zum Kinderspiel. Ich möchte das an dem bereits angesprochenen Beispiel praktisch verdeutlichen. (Ich gebe allerdings keine Einführung in Grails selbst, dazu verweise ich auf die hervorragende Dokumentation)

Nehmen wir an es gibt eine Domainklasse City, welche in verschiedenen Repräsentationen durch den CityController ausgeliefert werden soll.

Wir legen folgendes Mapping in UrlMappings.groovy an:

static mappings = {
  "/city/$name"(resource: "city")
}

Dadurch werden die Requests an URLs der Form /city/name RESTful gemappt und an den CityController weitergeleitet. D.h. GET-Requests gehen automatisch an die show-Action des Controllers POST an save u.s.w. (Details siehe Grails-Dokumentation). Außerdem wird der Part hinter /city/ als Parameter „name“ in die Action hineingegeben.

Mithilfe des withFormat-Ausdrucks kann der Controller auf verschiedene Anfrageformate unterschiedlich reagieren:

class CityController {
  def rdfRenderer

  def show = {
    def city = City.findByName(params.name)
    withFormat {
      html { return [cityInstance: city] }
      json { render city as JSON }
      rdf { rdfRenderer.render(city) }
    }
  }
}

Der rdfRenderer ist ein fiktives Beispiel. Sowas wird leider nicht von Grails mitgeliefert. RDF lässt sich aber sehr leicht mit groovyrdf generieren. Die Codeblöcke werden bei Anfragen nach den entsprechenden Formaten ausgeführt. html und json liefert Grails von Haus aus mit, was rdf bedeutet muss man jedoch kurz selbst in der Config.groovy bekannt geben:

grails.mime.types = [
  html: ['text/html','application/xhtml+xml'], // bereits vorkonfiguriert
  json: ['application/json','text/json'], // bereits vorkonfiguriert
  // [...]
  rdf: 'application/rdf+xml' // selbst ergänzt
]

Das wars im Prinzip schon, leider gibts in Grails derzeit noch einen kleinen Bug: Grails liest für die Content-Negotiation nicht wie üblich den HTTP-Accept-Header aus, sondern den Content-Type. Der Content-Type gibt eigentlich das Format der Daten an, welche man hinsendet und nicht der Daten welche man anfordert. Das lässt sich aber leicht über eine einfache Konfiguration beheben. Dazu in der Config.groovy folgende Einstellung setzen:

grails.mime.use.accept.header = true

Das wars auch schon! Abhängig vom gesetzten Accept-Header reagiert unser Controller nun anders auf den Request und kann entsprechend eine GSP rendern um eine HTML-Seite auszuliefern, JSON-Daten ausgeben oder aber RDF! Und sogar folgende URIs sind gültig:

http://example.com/city/berlin.html - Liefert immer die HTML-Seite
http://example.com/city/berlin.json - Liefert immer JSON-Daten
http://example.com/city/berlin.rdf - Liefert immer RDF-Daten

Wir haben also mit http://example.com/city/berlin eine eindeutige URI, welche die Resource Berlin identifiziert und zum anfragenden Client passende Daten ausliefert. Zudem haben wir für jede der Repräsentationen eine URI mit der entsprechenden „Dateiendung“. Das ist genau das, was wir im Web of Data brauchen 🙂

Data-Browsing – Ein kurzer Ausflug ins Web of Data

Wie versprochen, werden wir das Thema Linked Data nun etwas praktischer angehen. Wenn man mal selbst durch das Datenweb gesurft ist, versteht man viel eher worum es eigentlich geht. Wir brauchen:

  1. Einen Datenbrowser
  2. Einen Einstiegspunkt
  3. Neugier

Es gibt gibt schon einige Datenbrowser, allerdings scheinen die mehr Proof-of-Concept zu sein, als nutzbare Tools. Ich persönlich komme aktuell immer noch am besten mit Tabulator zurecht, obwohl der nicht sonderlich intuitiv zu bedienen ist. Das schöne an Tabulator ist aber, dass es dafür ein Firefox-Addon gibt, das schnell installiert ist. Außerdem lädt Tabulator automatisch „sameAs-Links“ nach, d.h. Daten die unter einer anderen URI verfügbar sind, aber das gleiche Objekt beschreiben werden gleich mitgeladen. Ich werde unsere kleine Erkundungstour durch das Datenweb anhand von Tabulator beschreiben. Wer erstmal nichts installieren mag, kann aber auch einen der Online-Browser verwenden, z.B. den OpenLink Data Explorer, Disco oder Marbles.

Teilweise geht es sogar ganz ohne Datenbrowser, nämlich dann wenn die Datenquellen ihre Daten auch gleich in einer HTML-Variante bereitstellen. Das ist zum Beispiel bei dbpedia.org der Fall. DBpedia ist das Abbild der Wikipedia im Web of Data. Das Projekt liest systematisch Daten aus der Wikipedia aus und veröffentlicht sie als RDF. Unter der URI http://dbpedia.org/resource/Karlsruhe finden sich zum Beispiel Daten zur Stadt Karlsruhe. Ruft man diese URI mit einem normalen Web-Browser ab, werden die Daten als HTML-Dokument angezeigt. Das passiert sogar, wenn man die Tabulator-Erweiterung installiert hat, weil Firefox immer noch primär ein HTML-Browser ist. Wie man das ändern kann erkläre ich in einem späteren Artikel (Tipp für Neugierige: Spielt mal mit Modify Headers am Accept-Header herum). Für den Moment reicht es, explizit die URI http://dbpedia.org/data/Karlsruhe abzurufen, um an die Rohdaten zu kommen [1]. Wir erfahren so tolle Sachen wie die Einwohnerzahl, die Telefonvorwahl und das Bundesland.

Mit Linked Data hat das alles aber noch recht wenig zu tun. Aufgrund der Informationsfülle wird zwar sehr gerne in die DBpedia hinein verlinkt, aber nur sehr wenige Links führen wieder hinaus. Wir suchen uns deshalb einen anderen Startpunkt, am besten von jemandem der sich auskennt: Tim Berners-Lee. Ja, klickt ruhig auf den Link, er führt direkt zu Daten über die Person Tim Berners-Lee, mitsamt einer ganzen Menge Links zu weiterführenden Daten, irgendwo in den Weiten des Webs. Wir erfahren zum Beispiel, dass er der Organisation „World Wide Web Consortium“ angehört und wenn ihr auf den kleinen grauen Pfeil daneben klickt, klappen zusätzliche Infos zu dieser Organisation aus. Wir erfahren auch, dass Berners-Lee der Autor von „Weaving the Web“ ist. Wenn man Shift gedrückt hält, wenn man auf den Pfeil klickt, werden die Daten zu diesem Buch im kompletten Browser-Tab geladen, statt nur ausgeklappt.

Leider stoßen wir dann schon recht schnell an die Grenzen des Datenwebs. Zum Beispiel wird der Verlag des Buches (Harper Paperbacks) zwar genannt, aber nicht verlinkt. Wir können also keine weiteren Daten zum Verlag abrufen. Es liegt an uns allen, diese Grenzen zu sprengen, so wie wir schon das WWW groß gemacht haben und täglich vergrößern. Aber schaut euch einfach mal ein bisschen um, es gibt schon einiges zu entdecken. Unter http://data.kontroversen.de/foaf.rdf#me habe ich auch ein paar Daten über mich online gestellt und mit meinem Identi.ca- sowie Twitter-Account verknüpft. (Ja, dem Thema Datenschutz und informationelle Selbstbestimmung in Bezug zu Linked Data werde ich auch noch einen Beitrag widmen)

So, ich denke das genügt erstmal als kleines, anschauliches Praxisbeispiel bzw. als Startpunkt für eigene Experimente. Bei Fragen und Problemen meldet euch einfach in den Kommentaren.

[1] Genau genommen ist das nicht ganz richtig, denn http://dbpedia.org/data/Karlsruhe verweist auf ein RDF-Dokument mit Daten über die Stadt Karlsruhe, während http://dbpedia.org/resource/Karlsruhe die Stadt selbst identifiziert. Dieser kleine aber feine Unterschied äußert sich auch in der Art wie Tabulator die Daten darstellt.