rdf4h 1.3.5 → 1.3.6
raw patch · 10 files changed
+154/−105 lines, 10 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Data.RDF.PatriciaTreeGraph: instance Control.DeepSeq.NFData (Data.Graph.Inductive.PatriciaTree.Gr Data.RDF.Types.Node Data.RDF.Types.Node)
+ Data.RDF.TriplesGraph: instance GHC.Generics.Constructor Data.RDF.TriplesGraph.C1_0TriplesGraph
+ Data.RDF.TriplesGraph: instance GHC.Generics.Datatype Data.RDF.TriplesGraph.D1TriplesGraph
+ Data.RDF.Types: escapeRDFSyntax :: Text -> Text
+ Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_0BaseUrl
+ Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_0LValue
+ Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_0Node
+ Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_0PrefixMappings
+ Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_0Triple
+ Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_1LValue
+ Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_1Node
+ Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_2LValue
+ Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_2Node
+ Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_3Node
+ Data.RDF.Types: instance GHC.Generics.Datatype Data.RDF.Types.D1BaseUrl
+ Data.RDF.Types: instance GHC.Generics.Datatype Data.RDF.Types.D1LValue
+ Data.RDF.Types: instance GHC.Generics.Datatype Data.RDF.Types.D1Node
+ Data.RDF.Types: instance GHC.Generics.Datatype Data.RDF.Types.D1PrefixMappings
+ Data.RDF.Types: instance GHC.Generics.Datatype Data.RDF.Types.D1Triple
- Data.RDF: hWriteH :: forall rdf. (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
+ Data.RDF: hWriteH :: (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
- Data.RDF: hWriteRdf :: forall rdf. (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
+ Data.RDF: hWriteRdf :: (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
- Data.RDF: parseFile :: forall rdf. (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
+ Data.RDF: parseFile :: (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
- Data.RDF: parseString :: forall rdf. (RdfParser p, RDF rdf) => p -> Text -> Either ParseFailure rdf
+ Data.RDF: parseString :: (RdfParser p, RDF rdf) => p -> Text -> Either ParseFailure rdf
- Data.RDF: parseURL :: forall rdf. (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
+ Data.RDF: parseURL :: (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
- Data.RDF: writeH :: forall rdf. (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
+ Data.RDF: writeH :: (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
- Data.RDF: writeRdf :: forall rdf. (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
+ Data.RDF: writeRdf :: (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
- Data.RDF.Query: isIsomorphic :: forall rdf1 rdf2. (RDF rdf1, RDF rdf2) => rdf1 -> rdf2 -> Bool
+ Data.RDF.Query: isIsomorphic :: (RDF rdf1, RDF rdf2) => rdf1 -> rdf2 -> Bool
- Data.RDF.Query: rdfContainsNode :: forall rdf. (RDF rdf) => rdf -> Node -> Bool
+ Data.RDF.Query: rdfContainsNode :: (RDF rdf) => rdf -> Node -> Bool
- Data.RDF.Types: hWriteH :: forall rdf. (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
+ Data.RDF.Types: hWriteH :: (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
- Data.RDF.Types: hWriteRdf :: forall rdf. (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
+ Data.RDF.Types: hWriteRdf :: (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
- Data.RDF.Types: parseFile :: forall rdf. (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
+ Data.RDF.Types: parseFile :: (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
- Data.RDF.Types: parseString :: forall rdf. (RdfParser p, RDF rdf) => p -> Text -> Either ParseFailure rdf
+ Data.RDF.Types: parseString :: (RdfParser p, RDF rdf) => p -> Text -> Either ParseFailure rdf
- Data.RDF.Types: parseURL :: forall rdf. (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
+ Data.RDF.Types: parseURL :: (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
- Data.RDF.Types: writeH :: forall rdf. (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
+ Data.RDF.Types: writeH :: (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
- Data.RDF.Types: writeRdf :: forall rdf. (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
+ Data.RDF.Types: writeRdf :: (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
Files
- rdf4h.cabal +1/−1
- src/Data/RDF/MGraph.hs +33/−0
- src/Data/RDF/PatriciaTreeGraph.hs +3/−5
- src/Data/RDF/Types.hs +32/−27
- src/Text/RDF/RDF4H/NTriplesParser.hs +7/−10
- src/Text/RDF/RDF4H/TurtleParser.hs +69/−53
- src/Text/RDF/RDF4H/TurtleSerializer.hs +1/−1
- src/Text/RDF/RDF4H/XmlParser.hs +3/−4
- testsuite/tests/Data/RDF/GraphTestUtils.hs +4/−3
- testsuite/tests/Test.hs +1/−1
rdf4h.cabal view
@@ -1,5 +1,5 @@ name: rdf4h-version: 1.3.5+version: 1.3.6 synopsis: A library for RDF processing in Haskell description: 'RDF for Haskell' is a library for working with RDF in Haskell.
src/Data/RDF/MGraph.hs view
@@ -20,6 +20,39 @@ -- |A map-based graph implementation. --+-- This instance of 'RDF' is an adjacency map with each subject+-- mapping to a mapping from a predicate node to to the adjacent nodes+-- via that predicate.+--+-- Given the following triples graph::+--+-- @+-- (http:\/\/example.com\/s1,http:\/\/example.com\/p1,http:\/\/example.com\/o1)+-- (http:\/\/example.com\/s1,http:\/\/example.com\/p1,http:\/\/example.com\/o2)+-- (http:\/\/example.com\/s1,http:\/\/example.com\/p2,http:\/\/example.com\/o1)+-- (http:\/\/example.com\/s2,http:\/\/example.com\/p3,http:\/\/example.com\/o3)+-- @+--+-- where+--+-- > hash "http://example.com/s1" = 1600134414+-- > hash "http://example.com/s2" = 1600134413+-- > hash "http://example.com/p1" = 1616912099+-- > hash "http://example.com/p2" = 1616912096+-- > hash "http://example.com/p3" = 1616912097+-- > hash "http://example.com/o1" = 1935686794+-- > hash "http://example.com/o2" = 1935686793+-- > hash "http://example.com/o3" = 1935686792+--+-- the in-memory hashmap representation of the triples graph is:+--+-- @+-- key:1600134414, value:(key:1616912099, value:[1935686794 -- (..\/s1,..\/p1,..\/o1)+-- ,1935686793]; -- (..\/s1,..\/p1,..\/o2)+-- key:1616912096, value:[1935686794]); -- (..\/s1,..\/p2,..\/o1)+-- key:1600134413, value:(key:1616912097, value:[1935686792]) -- (..\/s1,..\/p3,..\/o3)+-- @+-- -- Worst-case time complexity of the graph functions, with respect -- to the number of triples, are: --
src/Data/RDF/PatriciaTreeGraph.hs view
@@ -6,7 +6,6 @@ import Data.RDF.Query import Data.RDF.Types -import Control.DeepSeq (NFData(rnf)) import qualified Data.Graph.Inductive.Graph as G import qualified Data.Graph.Inductive.PatriciaTree as PT import qualified Data.Graph.Inductive.Query.DFS as DFS@@ -18,9 +17,6 @@ newtype PatriciaTreeGraph = PatriciaTreeGraph (PT.Gr Node Node,IntMap.IntMap Node, Maybe BaseUrl, PrefixMappings) deriving (Show) -instance NFData (PT.Gr Node Node)- where rnf x = seq x ()- instance RDF PatriciaTreeGraph where baseUrl = baseUrl' prefixMappings = prefixMappings'@@ -269,7 +265,9 @@ ts1 = if thisNode == fromJust maybeObj then mkTriples idxLookup thisNode adjsIn' [] else []- ts2 = mkTriples idxLookup thisNode [] adjsOut'+ ts2 = if thisNode == fromJust maybeSubj+ then mkTriples idxLookup thisNode [] adjsOut'+ else [] in ts1 ++ ts2 cfun ( _ , _ , _ , _ ) = undefined -- not sure why this pattern is needed to exhaust cfun arg patterns
src/Data/RDF/Types.hs view
@@ -15,7 +15,7 @@ isUNode,isLNode,isBNode, -- * Miscellaneous- resolveQName, absolutizeUrl, isAbsoluteUri, mkAbsoluteUrl,fileSchemeToFilePath,+ resolveQName, absolutizeUrl, isAbsoluteUri, mkAbsoluteUrl,escapeRDFSyntax,fileSchemeToFilePath, -- * RDF Type RDF(baseUrl,prefixMappings,addPrefixMappings,empty,mkRdf,triplesOf,uniqTriplesOf,select,query),@@ -151,44 +151,50 @@ -- |Validate a URI and return it in a @Just UNode@ if it is -- valid, otherwise @Nothing@ is returned. Performs the following:--- +-- -- 1. unescape unicode RDF literals -- 2. checks validity of this unescaped URI using 'isURI' from 'Network.URI' -- 3. if the unescaped URI is valid then 'Node' constructed with 'UNode' unodeValidate :: T.Text -> Maybe Node-unodeValidate t = if Network.isURI uri- then Just (UNode (T.pack uri))+unodeValidate t = if Network.isURI (T.unpack uri)+ then Just (UNode uri) else Nothing where- Right uri = parse unicodeEscParser "" (T.unpack t) + uri = escapeRDFSyntax t++escapeRDFSyntax :: T.Text -> T.Text+escapeRDFSyntax t = T.pack uri+ where+ Right uri = parse unicodeEscParser "" (T.unpack t) unicodeEscParser :: Stream s m Char => ParsecT s u m String unicodeEscParser = do- ss <- many (+ ss <- many ( try (do { _ <- char '\\' ; _ <- char 'U'- ; pos1 <- digit- ; pos2 <- digit- ; pos3 <- digit- ; pos4 <- digit- ; pos5 <- digit- ; pos6 <- digit- ; pos7 <- digit- ; pos8 <- digit+ ; pos1 <- hexDigit+ ; pos2 <- hexDigit+ ; pos3 <- hexDigit+ ; pos4 <- hexDigit+ ; pos5 <- hexDigit+ ; pos6 <- hexDigit+ ; pos7 <- hexDigit+ ; pos8 <- hexDigit ; let str = ['\\','x',pos1,pos2,pos3,pos4,pos5,pos6,pos7,pos8] ; return (read ("\"" ++ str ++ "\"") :: String)}) <|> try (do { _ <- char '\\' ; _ <- char 'u'- ; pos1 <- digit- ; pos2 <- digit- ; pos3 <- digit- ; pos4 <- digit+ ; pos1 <- hexDigit+ ; pos2 <- hexDigit+ ; pos3 <- hexDigit+ ; pos4 <- hexDigit ; let str = ['\\','x',pos1,pos2,pos3,pos4] ; return (read ("\"" ++ str ++ "\"") :: String)}) <|> (anyChar >>= \c -> return [c]))- return (concat ss :: String)- + return (concat ss :: String)++ -- |Return a blank node using the given string identifier. {-# INLINE bnode #-} bnode :: T.Text -> Node@@ -368,26 +374,26 @@ writeH :: forall rdf. (RDF rdf) => s -> rdf -> IO () -- |Write some triples to a file handle using whatever configuration is specified- -- by the first argument. - -- - -- WARNING: if the serialization format has header-level information + -- by the first argument.+ --+ -- WARNING: if the serialization format has header-level information -- that should be output (e.g., \@prefix declarations for Turtle), then you should -- use 'hWriteG' instead of this method unless you're sure this is safe to use, since- -- otherwise the resultant document will be missing the header information and + -- otherwise the resultant document will be missing the header information and -- will not be valid. hWriteTs :: s -> Handle -> Triples -> IO () -- |Write some triples to stdout; equivalent to @'hWriteTs' stdout@. writeTs :: s -> Triples -> IO () - -- |Write a single triple to the file handle using whatever configuration is + -- |Write a single triple to the file handle using whatever configuration is -- specified by the first argument. The same WARNING applies as to 'hWriteTs'. hWriteT :: s -> Handle -> Triple -> IO () -- |Write a single triple to stdout; equivalent to @'hWriteT' stdout@. writeT :: s -> Triple -> IO () - -- |Write a single node to the file handle using whatever configuration is + -- |Write a single node to the file handle using whatever configuration is -- specified by the first argument. The same WARNING applies as to 'hWriteTs'. hWriteN :: s -> Handle -> Node -> IO () @@ -689,4 +695,3 @@ then fmap (T.pack . Network.uriPath) (Network.parseURI (T.unpack fileScheme)) else Nothing fileSchemeToFilePath _ = Nothing-
src/Text/RDF/RDF4H/NTriplesParser.hs view
@@ -8,7 +8,7 @@ import Prelude hiding (init,pred) import Data.RDF.Types import Text.RDF.RDF4H.ParserUtils-import Data.Char(isLetter, isDigit, isLower)+import Data.Char(isLetter, isDigit, isLower,isAlphaNum) import qualified Data.Map as Map import Text.Parsec import Text.Parsec.Text@@ -64,8 +64,8 @@ skipMany1 nt_space obj <- nt_object skipMany nt_space- char '.'- many nt_space+ void (char '.')+ void (many nt_space) return $ Just (Triple subj pred obj) -- A literal is either a language literal (with optional language@@ -76,11 +76,11 @@ -- the closing quote with ^^ followed by the URI of the datatype. nt_literal :: GenParser () LValue nt_literal = - do lit_str <- between_chars '"' '"' inner_literal + do lit_str <- between (char '"') (char '"') inner_literal liftM (plainLL lit_str) (char '@' >> nt_language) <|> liftM (typedL lit_str) (count 2 (char '^') >> nt_uriref) <|> return (plainL lit_str)- where inner_literal = liftM T.concat (manyTill inner_string (lookAhead $ char '"'))+ where inner_literal = inner_string -- A language specifier of a language literal is any number of lowercase -- letters followed by any number of blocks consisting of a hyphen followed@@ -118,7 +118,7 @@ -- A URI reference is one or more nrab_character inside angle brackets. nt_uriref :: GenParser () T.Text-nt_uriref = between_chars '<' '>' (liftM T.pack (many (satisfy ( /= '>'))))+nt_uriref = between (char '<') (char '>') (liftM T.pack (many (satisfy ( /= '>')))) -- A node id is "_:" followed by a name. nt_nodeID :: GenParser () T.Text@@ -141,7 +141,7 @@ -- A character is any Unicode value from ASCII space to decimal 126 (tilde). is_character :: Char -> Bool-is_character c = c >= '\x0020' && c <= '\x007E'+is_character = isAlphaNum -- A non-quote character is a character that isn't the double-quote character. is_nonquote_char :: Char -> Bool@@ -194,9 +194,6 @@ b_nl = T.singleton '\n' b_slash = T.singleton '\\' b_quote = T.singleton '"'--between_chars :: Char -> Char -> GenParser () T.Text -> GenParser () T.Text-between_chars start end parser = char start >> parser >>= \res -> char end >> return res parseString' :: forall rdf. (RDF rdf) => T.Text -> Either ParseFailure rdf parseString' bs = handleParse mkRdf (runParser nt_ntripleDoc () "" bs)
src/Text/RDF/RDF4H/TurtleParser.hs view
@@ -1,4 +1,4 @@--- |An 'RdfParser' implementation for the Turtle format +-- |An 'RdfParser' implementation for the Turtle format -- <http://www.w3.org/TeamSubmission/turtle/>. module Text.RDF.RDF4H.TurtleParser(@@ -22,9 +22,8 @@ import qualified Data.Foldable as F import Data.Char (isDigit) import Control.Monad-import Data.Maybe (fromMaybe) --- |An 'RdfParser' implementation for parsing RDF in the +-- |An 'RdfParser' implementation for parsing RDF in the -- Turtle format. It is an implementation of W3C Turtle grammar rules at -- http://www.w3.org/TR/turtle/#sec-grammar-grammar . -- It takes optional arguments representing the base URL to use@@ -38,7 +37,7 @@ -- |'TurtleParser' is an instance of 'RdfParser'. instance RdfParser TurtleParser where- parseString (TurtleParser bUrl dUrl) = parseString' bUrl dUrl + parseString (TurtleParser bUrl dUrl) = parseString' bUrl dUrl parseFile (TurtleParser bUrl dUrl) = parseFile' bUrl dUrl parseURL (TurtleParser bUrl dUrl) = parseURL' bUrl dUrl @@ -90,12 +89,12 @@ -- grammar rule: [4] prefixID t_prefixID :: GenParser ParseState () t_prefixID =- do try (string "@prefix" <?> "@prefix-directive")+ do void (try (string "@prefix" <?> "@prefix-directive")) pre <- (many1 t_ws <?> "whitespace-after-@prefix") >> option T.empty t_pn_prefix- char ':' >> (many1 t_ws <?> "whitespace-after-@prefix-colon")+ void (char ':' >> (many1 t_ws <?> "whitespace-after-@prefix-colon")) uriFrag <- t_iriref- (many t_ws <?> "prefixID-whitespace")- (char '.' <?> "end-of-prefixID-period")+ void (many t_ws <?> "prefixID-whitespace")+ void (char '.' <?> "end-of-prefixID-period") (bUrl, dUrl, _, PrefixMappings pms, _, _, _, _) <- getState updatePMs $ Just (PrefixMappings $ Map.insert pre (absolutizeUrl bUrl dUrl uriFrag) pms) return ()@@ -103,9 +102,9 @@ -- grammar rule: [6s] sparqlPrefix t_sparql_prefix :: GenParser ParseState () t_sparql_prefix =- do try (caseInsensitiveString "PREFIX" <?> "@prefix-directive")+ do void (try (caseInsensitiveString "PREFIX" <?> "@prefix-directive")) pre <- (many1 t_ws <?> "whitespace-after-@prefix") >> option T.empty t_pn_prefix- char ':' >> (many1 t_ws <?> "whitespace-after-@prefix-colon")+ void (char ':' >> (many1 t_ws <?> "whitespace-after-@prefix-colon")) uriFrag <- t_iriref (bUrl, dUrl, _, PrefixMappings pms, _, _, _, _) <- getState updatePMs $ Just (PrefixMappings $ Map.insert pre (absolutizeUrl bUrl dUrl uriFrag) pms)@@ -114,11 +113,11 @@ -- grammar rule: [5] base t_base :: GenParser ParseState () t_base =- do try (string "@base" <?> "@base-directive")- many1 t_ws <?> "whitespace-after-@base"+ do void (try (string "@base" <?> "@base-directive"))+ void (many1 t_ws <?> "whitespace-after-@base") urlFrag <- t_iriref- (many t_ws <?> "base-whitespace")- (char '.' <?> "end-of-base-period")+ void (many t_ws <?> "base-whitespace")+ (void (char '.') <?> "end-of-base-period") bUrl <- currBaseUrl dUrl <- currDocUrl updateBaseUrl (Just $ Just $ newBaseUrl bUrl (absolutizeUrl bUrl dUrl urlFrag))@@ -126,8 +125,8 @@ -- grammar rule: [5s] sparqlBase t_sparql_base :: GenParser ParseState () t_sparql_base =- do try (caseInsensitiveString "BASE" <?> "@sparql-base-directive")- many1 t_ws <?> "whitespace-after-BASE"+ do void (try (caseInsensitiveString "BASE" <?> "@sparql-base-directive"))+ void (many1 t_ws <?> "whitespace-after-BASE") urlFrag <- t_iriref bUrl <- currBaseUrl dUrl <- currDocUrl@@ -139,16 +138,21 @@ -- grammar rule: [11] predicate t_predicate :: GenParser ParseState Node t_predicate = liftM UNode (t_iri <?> "resource")+-- res <- t_iri <?> "resource"+-- validateUNode res t_nodeID :: GenParser ParseState T.Text-t_nodeID = do { try (string "_:"); cs <- t_name; return $! "_:" `T.append` cs }+t_nodeID = do { void (try (string "_:")); cs <- t_name; return $! "_:" `T.append` cs } -- grammar rules: [139s] PNAME_NS t_pname_ns :: GenParser ParseState T.Text t_pname_ns =do pre <- option T.empty (try t_pn_prefix)- char ':'- return pre+ void (char ':')+ (bUrl, _, _, pms, _, _, _, _) <- getState+ case resolveQName bUrl pre pms of+ Just n -> return n+ Nothing -> unexpected ("Cannot resolve QName prefix: " ++ T.unpack pre) -- grammar rules: [168s] PN_LOCAL t_pn_local :: GenParser ParseState T.Text@@ -165,6 +169,7 @@ -- PERCENT | PN_LOCAL_ESC -- grammar rules: [169s] PLX+t_plx :: GenParser ParseState String t_plx = t_percent <|> t_pn_local_esc_str where t_pn_local_esc_str = do@@ -173,13 +178,15 @@ -- '%' HEX HEX -- grammar rules: [170s] PERCENT+t_percent :: GenParser ParseState String t_percent = do- char '%'+ void (char '%') h1 <- t_hex h2 <- t_hex- return ([h1,h2])+ return (['%',h1,h2]) -- grammar rules: [172s] PN_LOCAL_ESC+t_pn_local_esc :: GenParser ParseState Char t_pn_local_esc = char '\\' >> oneOf "_~.-!$&'()*+,;=/?#@%" -- grammar rules: [140s] PNAME_LN@@ -187,10 +194,7 @@ t_pname_ln = do pre <- t_pname_ns name <- t_pn_local- (bUrl, _, _, pms, _, _, _, _) <- getState- case resolveQName bUrl pre pms of- Just n -> return $ n `T.append` name- Nothing -> unexpected ("Cannot resolve QName prefix: " ++ T.unpack pre)+ return (pre `T.append` name) -- grammar rule: [10] subject t_subject :: GenParser ParseState ()@@ -207,15 +211,15 @@ (nextIdCounter >>= pushSubj . BNodeGen >> many t_ws >> t_predicateObjectList >> many t_ws)- + -- verb objectList (';' (verb objectList)?)* -- -- verb ws+ objectList ( ws* ';' ws* verb ws+ objectList )* (ws* ';')? -- grammar rule: [7] predicateObjectlist t_predicateObjectList :: GenParser ParseState () t_predicateObjectList =- do sepEndBy1 (try (t_verb >> many1 t_ws >> t_objectList >> popPred)) (try (many t_ws >> char ';' >> optional (char ';') >> many t_ws))- return ()+ do void (sepEndBy1 (try (t_verb >> many1 t_ws >> t_objectList >> popPred)) (try (many t_ws >> char ';' >> optional (char ';') >> many t_ws)))+-- return () -- grammar rule: [8] objectlist t_objectList :: GenParser ParseState ()@@ -244,13 +248,13 @@ -- itemList: object (ws+ object)* -- grammar rule: [15] collection t_collection:: GenParser ParseState ()-t_collection = +t_collection = -- ( object1 object2 ) is short for: -- [ rdf:first object1; rdf:rest [ rdf:first object2; rdf:rest rdf:nil ] ] -- ( ) is short for the resource: rdf:nil between (char '(') (char ')') $ do beginColl- many t_ws+ void (many t_ws) emptyColl <- option True (try t_object >> many t_ws >> return False) if emptyColl then void (addTripleForObject rdfNilNode) else void@@ -258,7 +262,7 @@ pushPred rdfRestNode >> addTripleForObject rdfNilNode >> popPred >> popSubj)- finishColl+ void finishColl return () blank_as_obj :: GenParser ParseState ()@@ -271,7 +275,7 @@ poList where genBlank = liftM BNodeGen (try (string "[]") >> nextIdCounter)- poList = between (char '[') (char ']') $ + poList = between (char '[') (char ']') $ liftM BNodeGen nextIdCounter >>= \bSubj -> -- generate new bnode void (addTripleForObject bSubj >> -- add triple with bnode as object@@ -304,7 +308,8 @@ str_literal :: GenParser ParseState Node str_literal =- do str <- t_quotedString <?> "quotedString"+ do str' <- t_quotedString <?> "quotedString"+ let str = escapeRDFSyntax str' liftM (LNode . typedL str) (try (count 2 (char '^')) >> t_iri) <|> liftM (lnode . plainLL str) (char '@' >> t_language) <|>@@ -319,13 +324,13 @@ t_longString :: GenParser ParseState T.Text t_longString =- try ( do { tripleQuoteDbl;+ try ( do { void tripleQuoteDbl; strVal <- liftM T.concat (many longString_char);- tripleQuoteDbl;+ void tripleQuoteDbl; return strVal }) <|>- try ( do { tripleQuoteSingle;+ try ( do { void tripleQuoteSingle; strVal <- liftM T.concat (many longString_char);- tripleQuoteSingle;+ void tripleQuoteSingle; return strVal }) where tripleQuoteDbl = count 3 (char '"')@@ -344,11 +349,11 @@ t_double = do sign <- sign_parser <?> "+-" rest <- try (do { ds <- many1 digit <?> "digit";- char '.';+ void (char '.'); ds' <- many digit <?> "digit"; e <- t_exponent <?> "exponent"; return ( T.pack ds `T.snoc` '.' `T.append` T.pack ds' `T.append` e) }) <|>- try (do { char '.';+ try (do { void (char '.'); ds <- many1 digit <?> "digit"; e <- t_exponent <?> "exponent"; return ('.' `T.cons` T.pack ds `T.append` e) }) <|>@@ -363,8 +368,8 @@ t_decimal :: GenParser ParseState T.Text t_decimal = do sign <- sign_parser- rest <- try (do ds <- many digit <?> "digit"; char '.'; ds' <- option "" (many digit); return (ds ++ ('.':ds')))- <|> try (do { char '.'; ds <- many1 digit <?> "digit"; return ('.':ds) })+ rest <- try (do ds <- many digit <?> "digit"; void (char '.'); ds' <- option "" (many digit); return (ds ++ ('.':ds')))+ <|> try (do { void (char '.'); ds <- many1 digit <?> "digit"; return ('.':ds) }) <|> many1 digit <?> "digit" return $ T.pack sign `T.append` T.pack rest @@ -393,7 +398,7 @@ t_language :: GenParser ParseState T.Text t_language = do initial <- many1 lower;- rest <- many (do {char '-'; cs <- many1 (lower <|> digit); return ( T.pack ('-':cs))})+ rest <- many (do {void (char '-'); cs <- many1 (lower <|> digit); return ( T.pack ('-':cs))}) return $! ( T.pack initial `T.append` T.concat rest) identifier :: GenParser ParseState Char -> GenParser ParseState Char -> GenParser ParseState T.Text@@ -417,9 +422,8 @@ do frag <- liftM (T.pack . concat) (many t_ucharacter) bUrl <- currBaseUrl dUrl <- currDocUrl- case unodeValidate (absolutizeUrl bUrl dUrl frag) of- Nothing -> unexpected ("Invalid URI in Turtle parser: " ++ show (absolutizeUrl bUrl dUrl frag))- Just (UNode t) -> return t+ let frag' = escapeRDFSyntax frag+ validateURI (absolutizeUrl bUrl dUrl frag') -- We make this String rather than T.Text because we want -- t_relativeURI (the only place it's used) to have chars so that@@ -446,7 +450,7 @@ where specialChar = oneOf "\t\n\r" >>= bs1 escapedChar =- do char '\\'+ do void (char '\\') (char 't' >> bs1 '\t') <|> (char 'n' >> bs1 '\n') <|> (char 'r' >> bs1 '\r') <|> (char '\\' >> bs1 '\\') <|> (char '"' >> bs1 '"') twoDoubleQuote = string "\"\"" >> notFollowedBy (char '"') >> bs "\"\""@@ -485,7 +489,7 @@ t_scharacter_in_dquot = (try (string "\\\"") >> return (T.singleton '"')) <|> (try (string "\\'") >> return (T.singleton '\''))- <|> try (do {char '\\';+ <|> try (do {void (char '\\'); (char 't' >> return (T.singleton '\t')) <|> (char 'n' >> return (T.singleton '\n')) <|> (char 'r' >> return (T.singleton '\r'))}) -- echaracter part 1@@ -498,7 +502,7 @@ t_scharacter_in_squot = (try (string "\\'") >> return (T.singleton '\'')) <|> (try (string "\\\"") >> return (T.singleton '"'))- <|> try (do {char '\\';+ <|> try (do {void (char '\\'); (char 't' >> return (T.singleton '\t')) <|> (char 'n' >> return (T.singleton '\n')) <|> (char 'r' >> return (T.singleton '\r'))}) -- echaracter part 1@@ -627,19 +631,19 @@ -- -- The @BaseUrl@ is used as the base URI within the document for resolving any relative URI references. -- It may be changed within the document using the @\@base@ directive. At any given point, the current--- base URI is the most recent @\@base@ directive, or if none, the @BaseUrl@ given to @parseURL@, or +-- base URI is the most recent @\@base@ directive, or if none, the @BaseUrl@ given to @parseURL@, or -- if none given, the document URL given to @parseURL@. For example, if the @BaseUrl@ were--- @http:\/\/example.org\/@ and a relative URI of @\<b>@ were encountered (with no preceding @\@base@ +-- @http:\/\/example.org\/@ and a relative URI of @\<b>@ were encountered (with no preceding @\@base@ -- directive), then the relative URI would expand to @http:\/\/example.org\/b@. -- -- The document URL is for the purpose of resolving references to 'this document' within the document, -- and may be different than the actual location URL from which the document is retrieved. Any reference--- to @\<>@ within the document is expanded to the value given here. Additionally, if no @BaseUrl@ is +-- to @\<>@ within the document is expanded to the value given here. Additionally, if no @BaseUrl@ is -- given and no @\@base@ directive has appeared before a relative URI occurs, this value is used as the -- base URI against which the relative URI is resolved. -- -- Returns either a @ParseFailure@ or a new RDF containing the parsed triples.-parseURL' :: forall rdf. (RDF rdf) => +parseURL' :: forall rdf. (RDF rdf) => Maybe BaseUrl -- ^ The optional base URI of the document. -> Maybe T.Text -- ^ The document URI (i.e., the URI of the document itself); if Nothing, use location URI. -> String -- ^ The location URI from which to retrieve the Turtle document.@@ -658,7 +662,7 @@ TIO.readFile fpath >>= \bs' -> return $ handleResult bUrl (runParser t_turtleDoc initialState (maybe "" T.unpack docUrl) bs') where initialState = (bUrl, docUrl, 1, PrefixMappings Map.empty, [], [], [], Seq.empty) --- |Parse the given string as a Turtle document. The arguments and return type have the same semantics +-- |Parse the given string as a Turtle document. The arguments and return type have the same semantics -- as <parseURL>, except that the last @String@ argument corresponds to the Turtle document itself as -- a string rather than a location URI. parseString' :: forall rdf. (RDF rdf) => Maybe BaseUrl -> Maybe T.Text -> T.Text -> Either ParseFailure rdf@@ -670,6 +674,18 @@ case result of (Left err) -> Left (ParseFailure $ show err) (Right (ts, pms)) -> Right $! mkRdf (F.toList ts) bUrl pms++validateUNode :: T.Text -> GenParser ParseState Node+validateUNode t =+ case unodeValidate t of+ Nothing -> unexpected ("Invalid URI in Turtle parser URI validation: " ++ show t)+ Just u@(UNode{}) -> return u+ Just node -> unexpected ("Unexpected node in Turtle parser URI validation: " ++ show node)++validateURI :: T.Text -> GenParser ParseState T.Text+validateURI t = do+ UNode uri <- validateUNode t+ return uri -------------- -- auxiliary parsing functions
src/Text/RDF/RDF4H/TurtleSerializer.hs view
@@ -156,7 +156,7 @@ writeLiteralString:: Handle -> T.Text -> IO () writeLiteralString h bs = do hPutChar h '"'- T.foldl' writeChar (return True) bs+ void (T.foldl' writeChar (return True) bs) hPutChar h '"' where writeChar :: IO Bool -> Char -> IO Bool
src/Text/RDF/RDF4H/XmlParser.hs view
@@ -1,4 +1,4 @@-{-# Language Arrows,OverloadedStrings,DoAndIfThenElse #-}+{-# Language Arrows,OverloadedStrings,DoAndIfThenElse,DeriveDataTypeable #-} -- |An parser for the RDF/XML format -- <http://www.w3.org/TR/REC-rdf-syntax/>.@@ -18,8 +18,7 @@ import Data.RDF.Types (RDF,RdfParser(..),Node(BNodeGen),BaseUrl(..),Triple(..),Triples,Subject,Predicate,Object,PrefixMappings(..),ParseFailure(ParseFailure),mkRdf,lnode,plainL,plainLL,typedL,unode,bnode,unodeValidate) import qualified Data.Text as T (Text,pack,unpack) import qualified Data.Text.IO as TIO-import Text.XML.HXT.Core (ArrowXml,ArrowIf,ArrowChoice,XmlTree,IfThen((:->)),(>.),(>>.),first,neg,(<+>),expandURI,getName,getAttrValue,getAttrValue0,getAttrl,hasAttrValue,hasAttr,constA,choiceA,getChildren,ifA,arr2A,second,hasName,isElem,isWhiteSpace,xshow,listA,isA,isText,getText,this,unlistA,orElse,sattr,mkelem,xreadDoc,runSLA,fatal,canonicalizeAllNodes)- +import Text.XML.HXT.Core (ArrowXml,ArrowIf,XmlTree,IfThen((:->)),(>.),(>>.),first,neg,(<+>),expandURI,getName,getAttrValue,getAttrValue0,getAttrl,hasAttrValue,hasAttr,constA,choiceA,getChildren,ifA,arr2A,second,hasName,isElem,isWhiteSpace,xshow,listA,isA,isText,getText,this,unlistA,orElse,sattr,mkelem,xreadDoc,runSLA) -- TODO: write QuickCheck tests for XmlParser instance for RdfParser. data XmlParser = XmlParser (Maybe BaseUrl) (Maybe T.Text)@@ -135,7 +134,7 @@ <+> (second (getChildren >>> isElem) >>> parsePredicatesFromChildren) <+> (second (neg (hasName "rdf:Description") >>> neg (hasName "Description")) >>> arr2A readTypeTriple)) >>. replaceLiElems [] (1 :: Int)- where readTypeTriple :: forall a. (ArrowXml a, ArrowState GParseState a) => LParseState -> a XmlTree Triple+ where readTypeTriple :: (ArrowXml a, ArrowState GParseState a) => LParseState -> a XmlTree Triple readTypeTriple state = getName >>> arr (Triple (stateSubject state) rdfType . unode . T.pack) replaceLiElems acc n (Triple s p o : rest) | p == (unode . T.pack) "rdf:li" = replaceLiElems (Triple s ((unode . T.pack) ("rdf:_" ++ show n)) o : acc) (n + 1) rest
testsuite/tests/Data/RDF/GraphTestUtils.hs view
@@ -43,7 +43,7 @@ , testProperty "query_match_sp" (p_query_match_sp _triplesOf) , testProperty "query_match_so" (p_query_match_so _triplesOf) , testProperty "query_match_po" (p_query_match_po _triplesOf)- , testProperty "select_match_none" (p_select_match_none _triplesOf)+ , testProperty "select_match_none" (p_select_match_none _triplesOf) , testProperty "select_match_s" (p_select_match_s _triplesOf) , testProperty "select_match_p" (p_select_match_p _triplesOf) , testProperty "select_match_o" (p_select_match_o _triplesOf)@@ -57,13 +57,14 @@ instance Arbitrary BaseUrl where- arbitrary = oneof $ map (return . BaseUrl . T.pack) ["http://example.com/a", "http://asdf.org/b"]+ arbitrary = oneof $ map (return . BaseUrl . T.pack) ["http://example.com/a","http://asdf.org/b","http://asdf.org/c"] --coarbitrary = undefined instance Arbitrary PrefixMappings where arbitrary = oneof [return $ PrefixMappings Map.empty, return $ PrefixMappings $ Map.fromAscList [(T.pack "eg1", T.pack "http://example.com/1"),- (T.pack "eg2", T.pack "http://example.com/2")]]+ (T.pack "eg2", T.pack "http://example.com/2"),+ (T.pack "eg3", T.pack "http://example.com/3")]] --coarbitrary = undefined -- Test stubs, which just require the appropriate RDF impl function
testsuite/tests/Test.hs view
@@ -36,5 +36,5 @@ ++ XmlParser.tests ++ W3CTurtleTest.tests ++ W3CRdfXmlTest.tests- -- ++ W3CNTripleTest.tests -- contains infinite loop+ ++ W3CNTripleTest.tests )