astrosearch / RDFUtils.hs

{-# LANGUAGE OverloadedStrings #-}

module RDFUtils 
       (
         blogPost
       , isRetweet
       , numFollowers
       , numFriends
       , follows
       , protectedFriends
       , fromRESTAPI
       , fromStreaming
       , twLangCode
       , illustrate
         
       , pURI
         
       , toTime
       , toText
       , fromRDF
         
       , triple
       , describe
       , findTweets  
       , findUsers
       , getElem
       , findElem
         
       , readN3Graph
       , readGraph
       , readGraphs
       , n3ToGraph
       , ttlToGraph
       )
where
  
import qualified Data.Text as T  
import qualified Data.Text.Lazy as LT
import qualified Data.Text.Lazy.IO as LT

import Swish.RDF  
import Swish.RDF.Query
import Swish.RDF.Parser.N3 (parseN3fromText)
import Swish.RDF.Parser.Turtle (parseTurtlefromText)
import Swish.RDF.Vocabulary.RDF (rdfType)
import Swish.RDF.Vocabulary.SIOC (siocUserAccount)

import Swish.Namespace (ScopedName, makeScopedName)
import Swish.QName (LName)

import Network.URI (URI, parseURI)

import Data.Maybe (fromMaybe, listToMaybe)
import Data.Time (UTCTime)
import Data.List (foldl')

import Utils (getJust)

instance FromRDFLabel T.Text where
  fromRDFLabel (Lit x)        = Just x
  fromRDFLabel (LangLit x _)  = Just x
  fromRDFLabel _              = Nothing

-- QUS: is this really not in Swish?
instance ToRDFLabel T.Text where
  toRDFLabel = Lit
  
pURI :: String -> URI
pURI u = getJust ("parseURI sent '" ++ u ++ "'") $ parseURI u

toRL :: Maybe T.Text -> URI -> LName -> RDFLabel
toRL a b = Res . makeScopedName a b

-- will not resolve
purl :: URI
purl = pURI "http://purl.org/net/djburke/demo/twitter#"
  
sioct :: URI
sioct = pURI "http://rdfs.org/sioc/types#"
       
blogPost, isRetweet, numFollowers, numFriends, fromRESTAPI, twLangCode :: RDFLabel
blogPost      = toRL (Just "sioc_t") sioct "MicroblogPost"
isRetweet     = toRL (Just "tw") purl "isRetweet"
numFollowers  = toRL (Just "tw") purl "numFollowers"
numFriends    = toRL (Just "tw") purl "numFriends"
fromRESTAPI   = toRL (Just "tw") purl "fromRESTAPI"
twLangCode    = toRL (Just "tw") purl "langCode"

fromStreaming, follows, protectedFriends :: RDFLabel
fromStreaming    = toRL (Just "tw") purl "fromStreamingAPI"
follows          = toRL (Just "tw") purl "follows"
protectedFriends = toRL (Just "tw") purl "protectedFriends"

{-
Maybe use dc:subject or sioc: style instead?
-}
illustrate :: RDFLabel
illustrate = toRL (Just "lode") (pURI "http://linkedevents.org/ontology/") "illustrate"


triple :: (ToRDFLabel a, ToRDFLabel b, ToRDFLabel c) => a -> b -> c -> RDFTriple
triple = toRDFTriple

-- | Find all the triples that have the label as subject.
describe :: RDFGraph -> RDFLabel -> [RDFTriple]
describe gr s = rdfFindArcs (rdfSubjEq s) gr

-- | Find all the tweets in the graph.
findTweets :: 
  RDFGraph 
  -> [RDFLabel]
findTweets = rdfFindValSubj (Res rdfType) blogPost

-- | Find all the users in the graph.
findUsers :: 
  RDFGraph 
  -> [RDFLabel]
findUsers = rdfFindValSubj (Res rdfType) (Res siocUserAccount)

toTime :: RDFLabel -> UTCTime
toTime l = fromMaybe (error $ "Invalid time: " ++ show l) (fromRDFLabel l)

toText :: RDFLabel -> T.Text
toText l = fromMaybe (error $ "Invalid label: " ++ show l) (fromRDFLabel l)
 
fromRDF :: RDFLabel -> String
fromRDF l = 
  fromMaybe 
  (error ("Unable to convert to string: " ++ show l))
  $ fromRDFLabel l

toN3, toTTL :: LT.Text -> RDFGraph
toN3  = either error id . parseN3fromText
toTTL = either error id . parseTurtlefromText

n3ToGraph :: [LT.Text] -> RDFGraph  
n3ToGraph = toN3 . LT.concat
  
ttlToGraph :: [LT.Text] -> RDFGraph  
ttlToGraph = toTTL . LT.concat
  
-- | Read in a graph (N3 format).           
readN3Graph :: FilePath -> IO RDFGraph             
readN3Graph fname = toN3 `fmap` LT.readFile fname
  
-- | Read in a graph (Turtle format).           
readGraph :: FilePath -> IO RDFGraph             
readGraph fname = toTTL `fmap` LT.readFile fname
  
-- | Read in the data from multiple files, merging into a single graph.
readGraphs :: [FilePath] -> IO RDFGraph
readGraphs inFiles = foldl' merge emptyRDFGraph `fmap` mapM readGraph inFiles

-- | Return the first triple that contains the predicate
--   in the list of triples.
getElem :: 
  ScopedName      -- ^ Predicate to search for.
  -> [RDFTriple] 
  -> Maybe RDFTriple
getElem l = listToMaybe . filter (rdfPredEq (Res l))
  
-- | Return the first object that matches the predicate
--   in the list of triples.
findElem :: 
  (RDFLabel -> a) 
  -> ScopedName   -- ^ Predicate to search for.
  -> [RDFTriple] 
  -> Maybe a
findElem conv l ts = (conv . arcObj) `fmap` getElem l ts
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.