packages feed

yaml2owl-0.0.1: src/SchemaScaffold.hs

{-# LANGUAGE OverloadedStrings #-}

module SchemaScaffold (prefixesOf, classInfos, scaffold) where

import Data.List (partition)
import Text.XML.Light
import Data.Text (unpack, toLower)
import Data.Map (toList)

import Swish.RDF
import Swish.Namespace (ScopedName, getScopeLocal)
import Swish.QName (getLName, LName)
import Swish.RDF.Vocabulary.OWL

import Swish.RDF.Query (rdfFindValSubj, rdfFindPredVal)

import System.Directory
import System.FilePath( (</>), (<.>) )

mkDir :: FilePath -> IO ()
mkDir = createDirectoryIfMissing True

instancesOf :: RDFLabel -> RDFGraph -> [RDFLabel]
instancesOf = rdfFindValSubj resRdfType

classesOf :: RDFGraph -> [RDFLabel]
classesOf = instancesOf resRdfsClass

xmlns :: String -> String -> Attr
xmlns prefix = Attr $ QName prefix Nothing (Just "xmlns")

data Subject = Subject {
  name :: ScopedName,
  dataProps :: [(String, String, String)],
  objectProps :: [(String, String)]
} deriving (Show, Eq)

prefixesOf :: NSGraph lb -> [Attr]
prefixesOf g = [ xmlns (unpack p) (show u) | (Just p, u) <- toList $ namespaces g ]

--classNames g = [ getScopeLocal sn | Res sn <- classesOf g ]

classInfos :: NSGraph RDFLabel -> [Subject]
classInfos g = map classInfo $ classesOf g
  where
    classInfo klass = Subject (getScopedName klass) dataProps' objectProps'
      where
        props = rdfFindValSubj resRdfsDomain klass g
        graphDataProps = rdfFindValSubj resRdfType (Res owlDatatypeProperty) g
        (dataProperties, objectProperties) = partition (\p-> elem p graphDataProps) props
        dataProps' = [ (show p, (unpack . getLName . localName) p, show $ head $ rdfFindPredVal p resRdfsRange g) | p <- dataProperties ]
        objectProps' = [ (show p, (unpack . getLName . localName) p)  | p <- objectProperties ]
      
localName :: RDFLabel -> LName
localName = getScopeLocal . getScopedName

layout :: [Attr] -> [Element] -> Element
layout prefixes content =
  unode "html" (prefixes, [
    unode "head" (),
    unode "body" content
  ])

index :: Subject -> [Element]
index subject =
  [
    unode "div" ([about ("[" ++ show (name subject) ++ "]"), rev "rdf:type"], individual subject)
  ]

individual :: Subject -> [Element]
individual (Subject name dataProps objectProps) =
  [
    unode "div" [
      unode "p" [
        unode "b" (l ++ ":"),
        unode "span" [property p, datatype t] 
      ]
    | (p, l, t) <- dataProps ],
    unode "div" [
      unode "p" ([rel p], [
        Text $ blank_cdata {cdData = (l ++ ":")},
        Elem $ unode "a" (href "_", unode "span" (property "rdfs:label"))
      ])
    | (p, l) <- objectProps ]
  ]

attr :: String -> String -> Attr
attr name = Attr (unqual name)

rel, rev, href, about, resource, property, datatype :: String -> Attr
rel = attr "rel"
rev = attr "rev"
href = attr "href"
about = attr "about"
resource = attr "resource"
property = attr "property"
datatype = attr "datatype"

label :: Subject -> String
label = unpack . toLower . getLName . getScopeLocal . name

scaffold :: String -> [Attr] -> Subject -> IO ()
scaffold baseDir prefixes subject = do
  let dir = baseDir </> label subject
  mkDir dir
  writeFile (dir </> "index" <.> "html") $ ppElement $ layout prefixes $ index subject
  writeFile (dir </> "_wildcard" <.> "html") $ ppElement $ layout prefixes $ individual subject