From f9c68cad1273d6d7b2373600b8d6d11080b7863a Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Wed, 26 Dec 2012 21:56:42 -0600 Subject: Initial commit --- DBpedia.hs | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 DBpedia.hs (limited to 'DBpedia.hs') diff --git a/DBpedia.hs b/DBpedia.hs new file mode 100644 index 0000000..1f4d74b --- /dev/null +++ b/DBpedia.hs @@ -0,0 +1,90 @@ +{- DBpedia.hs -- requesting ages from DBpedia +Copyright (C) 2012 Benjamin Barenblat + +This module is a part of ageOf. + +ageOf is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +ageOf is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +ageOf. If not, see . -} + +module DBpedia (dbpedia) where + +import Control.Monad (void) +import Database.HSparql.Connection +import Database.HSparql.QueryGenerator +import qualified Data.Time as Time (Day, parseTime) +import qualified Data.RDF as RDF (Node(..), LValue(..)) +import qualified Data.Text as Text (unpack) +import System.CurrentLocale (currentLocale) +import System.Locale (TimeLocale) + +import RequestMethod (RequestMethod(BirthDateFunction)) + +-- The DBpedia plugin, defined by the single function 'getBirthDate'. +dbpedia :: RequestMethod +dbpedia = BirthDateFunction getBirthDate + +getBirthDate :: String -> IO (Maybe Time.Day) +getBirthDate name = do + locale <- currentLocale + response <- askDBpedia $ selectBirthDate name + return $ case response of + Nothing -> Nothing + Just Unbound -> Nothing + Just (Bound node) -> parseAsDate locale node + +{- Generates a DBpedia SELECT query for a person's birth date. You can see the +generated query by running 'putStrLn $ createSelectQuery simpleSelect'. -} +selectBirthDate :: String -> Query SelectQuery +selectBirthDate name = do + -- Variables + page <- var + birthDate <- var + -- Prefixes + dbpprop <- prefix "dbprop" $ iriRef "http://dbpedia.org/property/" + rdfs <- prefix "rdfs" $ iriRef "http://www.w3.org/2000/01/rdf-schema#" + -- Okay, here we go. + let query = SelectQuery [birthDate] + void $ triple page (rdfs .:. "label") (name, "en") + void $ triple page (dbpprop .:. "birthDate") birthDate + return query + +{- Runs a SELECT query for a single variable on DBpedia, returning the first +possible match. -} +askDBpedia :: Query SelectQuery -> IO (Maybe BindingValue) +askDBpedia q = do + result <- selectQuery "http://dbpedia.org/sparql" q + return $ case result of + Just ([x]:_) -> Just x + Just ((_:_):_) -> error "got more than one bound variable" + _ -> Nothing + +-- Parses an RDF literal as a date. +parseAsDate :: TimeLocale -> RDF.Node -> Maybe Time.Day +parseAsDate locale (RDF.LNode node) = + let value = + case node of + RDF.PlainL v -> v + RDF.PlainLL v _lang -> v + RDF.TypedL v _type -> v + in parseXMLSchemaDate locale $ Text.unpack value +parseAsDate _ _ = Nothing + +{- Parses a date somewhat as described in the XML Schema +. TODO: Handle large (>12-hour) time +zone offsets correctly. TODO: Handle BCE (negative) years correctly. -} +parseXMLSchemaDate :: TimeLocale -> String -> Maybe Time.Day +parseXMLSchemaDate locale dateString = + let expectedFormat = + if length dateString > length "YYYY-MM-DD" + then "%F%z" -- There's a time zone. + else "%F" + in Time.parseTime locale expectedFormat dateString -- cgit v1.2.3