-- | Serialize RDF using an approximation (because it does not yet support Unicode escape sequences) of the N-triples format module Hydra.Ext.Rdf.Serde ( rdfGraphToString, ) where import qualified Hydra.Ext.Rdf.Syntax as Rdf import Hydra.Util.Codetree.Script import qualified Hydra.Util.Codetree.Ast as CT import qualified Data.List as L import qualified Data.Set as S -- IRIREF ::= '<' ([^#x00-#x20<>"{}|^`\] | UCHAR)* '>' -- TODO: Unicode escape sequences escapeIriStr :: String -> String escapeIriStr s = L.concat (esc <$> s) where esc c = if c >= '\128' || c <= '\32' || S.member c others then "?" else [c] others = S.fromList $ "<>\"{}|^`\\" -- STRING_LITERAL_QUOTE ::= '"' ([^#x22#x5C#xA#xD] | ECHAR | UCHAR)* '"' -- TODO: Unicode escape sequences escapeLiteralString :: String -> String escapeLiteralString s = L.concat (esc <$> s) where esc c = if c >= '\128' then "?" else case c of '\"' -> "\\\"" '\\' -> "\\\\" '\n' -> "\\n" '\r' -> "\\r" _ -> [c] rdfGraphToString :: Rdf.Graph -> String rdfGraphToString = printExpr . writeGraph writeBlankNode :: Rdf.BlankNode -> CT.Expr writeBlankNode bnode = noSep [cst "_:", cst $ Rdf.unBlankNode bnode] writeGraph :: Rdf.Graph -> CT.Expr writeGraph g = newlineSep (writeTriple <$> (S.toList $ Rdf.unGraph g)) writeIri :: Rdf.Iri -> CT.Expr writeIri iri = noSep [cst "<", cst $ escapeIriStr $ Rdf.unIri iri, cst ">"] -- LANGTAG ::= '@' [a-zA-Z]+ ('-' [a-zA-Z0-9]+)* -- Note: we simply trust language tags to be valid writeLanguageTag :: Rdf.LanguageTag -> CT.Expr writeLanguageTag lang = noSep [cst "@", cst $ Rdf.unLanguageTag lang] writeLiteral :: Rdf.Literal -> CT.Expr writeLiteral lit = noSep [cst lex, suffix] where suffix = case Rdf.literalLanguageTag lit of Nothing -> noSep [cst "^^", writeIri dt] Just lang -> writeLanguageTag lang lex = "\"" ++ (escapeLiteralString $ Rdf.literalLexicalForm lit) ++ "\"" dt = Rdf.literalDatatypeIri lit writeNode :: Rdf.Node -> CT.Expr writeNode n = case n of Rdf.NodeIri iri -> writeIri iri Rdf.NodeBnode bnode -> writeBlankNode bnode Rdf.NodeLiteral lit -> writeLiteral lit writeResource :: Rdf.Resource -> CT.Expr writeResource r = case r of Rdf.ResourceIri iri -> writeIri iri Rdf.ResourceBnode bnode -> writeBlankNode bnode writeTriple :: Rdf.Triple -> CT.Expr writeTriple t = spaceSep [ writeResource $ Rdf.tripleSubject t, writeIri $ Rdf.triplePredicate t, writeNode $ Rdf.tripleObject t, cst "."]