{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
module Swish.RDF.Formatter.NTriples
( formatGraphAsText
, formatGraphAsLazyText
, formatGraphAsBuilder
)
where
import Swish.RDF.Formatter.Internal ( NodeGenState(..)
, SLens (..)
, emptyNgs
, mapBlankNode_
)
import Swish.GraphClass (Arc(..))
import Swish.Namespace (ScopedName, getQName)
import Swish.RDF.Graph (RDFGraph, RDFLabel(..))
import Swish.RDF.Graph (getArcs)
import Swish.RDF.Vocabulary (fromLangTag)
import Control.Monad.State
import Data.Char (ord, intToDigit, toUpper)
#if (!defined(__GLASGOW_HASKELL__)) || (__GLASGOW_HASKELL__ < 710)
import Data.Monoid
import Control.Applicative ((<$>))
#endif
import qualified Data.Set as S
import qualified Data.Text as T
import qualified Data.Text.Lazy as L
import qualified Data.Text.Lazy.Builder as B
type Formatter a = State NodeGenState a
_nodeGen :: SLens NodeGenState NodeGenState
_nodeGen :: SLens NodeGenState NodeGenState
_nodeGen = forall a b. (a -> b) -> (a -> b -> a) -> SLens a b
SLens forall a. a -> a
id forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall a. a -> a
id
formatGraphAsText :: RDFGraph -> T.Text
formatGraphAsText :: RDFGraph -> Text
formatGraphAsText = Text -> Text
L.toStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. RDFGraph -> Text
formatGraphAsLazyText
formatGraphAsLazyText :: RDFGraph -> L.Text
formatGraphAsLazyText :: RDFGraph -> Text
formatGraphAsLazyText = Builder -> Text
B.toLazyText forall b c a. (b -> c) -> (a -> b) -> a -> c
. RDFGraph -> Builder
formatGraphAsBuilder
formatGraphAsBuilder :: RDFGraph -> B.Builder
formatGraphAsBuilder :: RDFGraph -> Builder
formatGraphAsBuilder RDFGraph
gr = forall s a. State s a -> s -> a
evalState (RDFGraph -> Formatter Builder
formatGraph RDFGraph
gr) NodeGenState
emptyNgs
formatGraph :: RDFGraph -> Formatter B.Builder
formatGraph :: RDFGraph -> Formatter Builder
formatGraph RDFGraph
gr = forall a. Monoid a => [a] -> a
mconcat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Arc RDFLabel -> Formatter Builder
formatArc (forall a. Set a -> [a]
S.toList (forall (lg :: * -> *) lb. LDGraph lg lb => lg lb -> ArcSet lb
getArcs RDFGraph
gr))
space, nl :: B.Builder
space :: Builder
space = Char -> Builder
B.singleton Char
' '
nl :: Builder
nl = Builder
" .\n"
formatArc :: Arc RDFLabel -> Formatter B.Builder
formatArc :: Arc RDFLabel -> Formatter Builder
formatArc (Arc RDFLabel
s RDFLabel
p RDFLabel
o) = do
Builder
sl <- RDFLabel -> Formatter Builder
formatLabel RDFLabel
s
Builder
pl <- RDFLabel -> Formatter Builder
formatLabel RDFLabel
p
Builder
ol <- RDFLabel -> Formatter Builder
formatLabel RDFLabel
o
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat [Builder
sl, Builder
space, Builder
pl, Builder
space, Builder
ol, Builder
nl]
formatLabel :: RDFLabel -> Formatter B.Builder
formatLabel :: RDFLabel -> Formatter Builder
formatLabel lab :: RDFLabel
lab@(Blank String
_) = RDFLabel -> Formatter Builder
mapBlankNode RDFLabel
lab
formatLabel (Res ScopedName
sn) = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ ScopedName -> Builder
showScopedName ScopedName
sn
formatLabel (Lit Text
lit) = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Text -> Builder
quoteText Text
lit
formatLabel (LangLit Text
lit LanguageTag
lang) = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat [Text -> Builder
quoteText Text
lit, Builder
"@", Text -> Builder
B.fromText (LanguageTag -> Text
fromLangTag LanguageTag
lang)]
formatLabel (TypedLit Text
lit ScopedName
dt) = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat [Text -> Builder
quoteText Text
lit, Builder
"^^", ScopedName -> Builder
showScopedName ScopedName
dt]
formatLabel RDFLabel
lab = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ String -> Builder
B.fromString forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show RDFLabel
lab
mapBlankNode :: RDFLabel -> Formatter B.Builder
mapBlankNode :: RDFLabel -> Formatter Builder
mapBlankNode = forall a. SLens a NodeGenState -> RDFLabel -> State a Builder
mapBlankNode_ SLens NodeGenState NodeGenState
_nodeGen
showScopedName :: ScopedName -> B.Builder
showScopedName :: ScopedName -> Builder
showScopedName ScopedName
s = Text -> Builder
B.fromText (Text -> Text
quote (String -> Text
T.pack (forall a. Show a => a -> String
show (ScopedName -> QName
getQName ScopedName
s))))
quoteText :: T.Text -> B.Builder
quoteText :: Text -> Builder
quoteText Text
st = forall a. Monoid a => [a] -> a
mconcat [Builder
"\"", Text -> Builder
B.fromText (Text -> Text
quote Text
st), Builder
"\""]
quote :: T.Text -> T.Text
quote :: Text -> Text
quote = (Char -> Text) -> Text -> Text
T.concatMap Char -> Text
quoteT
quoteT :: Char -> T.Text
quoteT :: Char -> Text
quoteT Char
'\\' = Text
"\\\\"
quoteT Char
'"' = Text
"\\\""
quoteT Char
'\n' = Text
"\\n"
quoteT Char
'\t' = Text
"\\t"
quoteT Char
'\r' = Text
"\\r"
quoteT Char
c =
let nc :: Int
nc = Char -> Int
ord Char
c
in if Int
nc forall a. Ord a => a -> a -> Bool
> Int
0xffff
then String -> Text
T.pack (Char
'\\'forall a. a -> [a] -> [a]
:Char
'U'forall a. a -> [a] -> [a]
: Int -> Int -> String
numToHex Int
8 Int
nc)
else if Int
nc forall a. Ord a => a -> a -> Bool
> Int
0x7e Bool -> Bool -> Bool
|| Int
nc forall a. Ord a => a -> a -> Bool
< Int
0x20
then String -> Text
T.pack (Char
'\\'forall a. a -> [a] -> [a]
:Char
'u'forall a. a -> [a] -> [a]
: Int -> Int -> String
numToHex Int
4 Int
nc)
else Char -> Text
T.singleton Char
c
numToHex :: Int -> Int -> String
numToHex :: Int -> Int -> String
numToHex Int
c = String -> Int -> String
go []
where
go :: String -> Int -> String
go String
s Int
0 = forall a. Int -> a -> [a]
replicate (Int
c forall a. Num a => a -> a -> a
- forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s) Char
'0' forall a. [a] -> [a] -> [a]
++ String
s
go String
s Int
n =
let (Int
m,Int
x) = forall a. Integral a => a -> a -> (a, a)
divMod Int
n Int
16
in String -> Int -> String
go (Int -> Char
iToD Int
xforall a. a -> [a] -> [a]
:String
s) Int
m
iToD :: Int -> Char
iToD Int
x | Int
x forall a. Ord a => a -> a -> Bool
< Int
10 = Int -> Char
intToDigit Int
x
| Bool
otherwise = Char -> Char
toUpper forall a b. (a -> b) -> a -> b
$ Int -> Char
intToDigit Int
x