packages feed

hexpat-streamparser 0.0.2 → 0.1.0

raw patch · 3 files changed

+71/−26 lines, 3 filesdep +hexpat-streamparserdep +hspecdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: hexpat-streamparser, hspec

Dependency ranges changed: base

API changes (from Hackage documentation)

- Text.XML.Expat.StreamParser: (<?>) :: Monad m => EventParser l e m a -> Text -> EventParser l e m a
+ Text.XML.Expat.StreamParser: instance GHC.Classes.Eq e => GHC.Classes.Eq (Text.XML.Expat.StreamParser.AttrParserError e)
+ Text.XML.Expat.StreamParser: instance GHC.Classes.Eq e => GHC.Classes.Eq (Text.XML.Expat.StreamParser.EventParseError e)
+ Text.XML.Expat.StreamParser: instance GHC.Show.Show e => GHC.Show.Show (Text.XML.Expat.StreamParser.AttrParserError e)
- Text.XML.Expat.StreamParser: AttributeNotFound :: Text -> EventParseError e
+ Text.XML.Expat.StreamParser: AttributeNotFound :: Maybe Text -> Text -> EventParseError e
- Text.XML.Expat.StreamParser: parseXMLFile :: EventListParser e a -> ParseOptions Text Text -> FilePath -> IOMode -> IO (Either (EventParseError e, Maybe XMLParseLocation) a)
+ Text.XML.Expat.StreamParser: parseXMLFile :: ParseOptions Text Text -> IOMode -> FilePath -> EventListParser e a -> IO (Either (EventParseError e, Maybe XMLParseLocation) a)

Files

hexpat-streamparser.cabal view
@@ -1,7 +1,7 @@ cabal-version: 1.12 name: hexpat-streamparser description: streaming xml parser combinators using hexpat-version: 0.0.2+version: 0.1.0 maintainer: kristof@resonata.be copyright: Kristof Bastiaensen 2020 license: BSD3@@ -28,3 +28,18 @@         parser-combinators >= 1.2 && < 1.3,         transformers >= 0.5 && < 0.6,         bytestring >= 0.10 && < 0.11+   default-extensions: OverloadedStrings++test-suite test+  type: exitcode-stdio-1.0+  default-language: Haskell2010        +  hs-source-dirs:+    tests+  main-is:+    test.hs+  build-depends:+    hexpat >= 0.20 && < 0.21,     +    hexpat-streamparser == 0.1.0,+    base >= 4 && < 5,+    hspec+  default-extensions: OverloadedStrings
src/Text/XML/Expat/StreamParser.hs view
@@ -56,7 +56,6 @@   , someEmptyTag   , emptyTag   , text-  , (<?>)     -- * Re-exports from "Control.Applicative.Combinators"   ,  (C.<|>)   , C.optional@@ -103,6 +102,7 @@ import qualified Data.Text as Text import Data.Text (Text) import Text.XML.Expat.SAX as Expat+import Data.List (nub)  newtype CPSExceptT e m a =   CPSExceptT { getCPSExceptT :: forall r. ((e -> m r) -> (a -> m r) -> m r) }@@ -159,28 +159,31 @@   UnMatchedTag |   ExpectedCloseTag |   XmlError XMLParseError |-  AttributeNotFound Text |+  AttributeNotFound (Maybe Text) Text |   UnknownAttributes [Text]|   Expected [Text] |   CustomError e-  deriving (Show)+  deriving (Show, Eq)  data AttrParserError e =   AttrRequired Text |   AttrEmpty |   CustomAttrError e+  deriving (Show, Eq)  attrErrorToEvent :: AttrParserError e -> EventParseError e attrErrorToEvent AttrEmpty = Empty-attrErrorToEvent (AttrRequired t) = AttributeNotFound t+attrErrorToEvent (AttrRequired t) = AttributeNotFound Nothing t attrErrorToEvent (CustomAttrError e) = CustomError e --- | semigroup instance concatenates Expected values if any, or--- returns the last error.  Xml parse errors take precedence.+-- | semigroup instance concatenates Expected tags. instance Semigroup (EventParseError e) where-  XmlError e <> _ = XmlError e+  e <> Empty = e   Expected t <> Expected s = Expected $ t ++ s-  Expected t <> _ = Expected t+  AttributeNotFound (Just t) _ <> Expected s = Expected $ t: s+  Expected t <> AttributeNotFound (Just s) _ = Expected $ t ++ [s]+  AttributeNotFound (Just s) _ <> AttributeNotFound (Just t) _ =+    Expected $ nub [s, t]   _ <> e = e  instance Monoid (EventParseError e) where@@ -243,11 +246,17 @@   put $ ParserState newState stream   pure oldState +-- combine old and new consumed state+updateConsumedState :: Monad m => Bool -> EventParser l e m ()+updateConsumedState oldState = EventParser $ do+  ParserState newState stream <- get+  put $ ParserState (oldState || newState) stream+ instance Monad m => Alternative (EventParser l e m) where   EventParser p <|> EventParser q = EventParser $ do     -- clear consumed state     oldConsumedState <- getEventParser $ setConsumedState False-    catchError p $ \err -> do+    res <- catchError p $ \err -> do       ParserState pConsumed _ <- get       if pConsumed         -- don't backtrack when already consumed some state@@ -259,8 +268,11 @@              else do              -- if nothing consumed, then reset consumed state and              -- combine error messages-             _ <- getEventParser $ setConsumedState oldConsumedState +             getEventParser $ updateConsumedState oldConsumedState              throwError (err <> err2)+    getEventParser $ updateConsumedState oldConsumedState+    pure res+   empty = EventParser $ throwError Empty  instance Monad m => MonadPlus (EventParser l e m) where@@ -307,12 +319,12 @@ -- | Lazily parse an xml file into a value.  This function ensures the --  input is consumed and the file handle closed, before returning the --  value.-parseXMLFile :: EventListParser e a-             -> Expat.ParseOptions Text Text-             -> FilePath+parseXMLFile :: Expat.ParseOptions Text Text              -> IOMode+             -> FilePath+             -> EventListParser e a              -> IO (Either (EventParseError e, Maybe XMLParseLocation) a)-parseXMLFile parser parseOptions fp mode =+parseXMLFile parseOptions mode fp parser =   withFile fp mode $ \h -> do   bs <- LazyBS.hGetContents h   pure $! parseXMLByteString parser parseOptions bs@@ -363,7 +375,7 @@                 StartElement _ _ -> throwError ExpectedCloseTag                 CharacterData t                   | not (Text.all (`elem` (" \t\r\n" :: String)) t) ->-                    error "unexpected text"+                    throwError ExpectedCloseTag                 FailDocument err -> do                   put $ ParserState consumed (Ordered list)                   throwError $ XmlError err@@ -419,10 +431,6 @@ noAttrs :: AttrParser e () noAttrs = pure () --- | Annotate the parser with a name for better parse errors-(<?>) :: Monad m => EventParser l e m a -> Text -> EventParser l e m a-parser <?> msg = parser <|> EventParser (throwError $ Expected [msg])- -- | Parse a tag that succeed on the given test function.  Parses the -- children in the order or the inner parser. someTag :: (Monad (ItemM l), List l)@@ -462,13 +470,12 @@ -- someUnorderedTag inner = _ -- | Skip next tag skipTag :: (Monad (ItemM l), List l) => EventParser l e (ItemM l) ()-skipTag = (someTag (const True) skipAttrs $ const skipTags)-          <?> "Any Tag"+skipTag = someTag (const True) skipAttrs $ const skipTags {-# INLINE skipTag #-}            -- | Skip remaining tags and text, if any. skipTags :: (Monad (ItemM l), List l) => EventParser l e(ItemM l) ()-skipTags = void $ many (skipTag <|> void text)+skipTags = optional text >> skipMany (skipTag >> void text)  -- | Skip zero or more tags until the given parser succeeds skipTagsTill ::@@ -484,9 +491,13 @@     -> AttrParser e b           -- ^ attribute parser     -> (b -> EventParser l e (ItemM l) a) -- ^ tag children parser     -> EventParser l e (ItemM l) a-tag name attrP children = someTag (== name) attrP children-                          <?> (name <> " Tag")-+tag name attrP children =+  catchError (someTag (== name) attrP children) $ \err ->+  case err of+    ExpectedTag -> throwError $ Expected [name]+    AttributeNotFound Nothing a -> throwError $ AttributeNotFound (Just name) a+    _ -> throwError err+     -- -- | Parse a tag with the given name, using the inner parser for the -- -- children tags.  The children tags can be in any order.  Note that -- -- this is less efficient than an orderedTag, since it has to keep
+ tests/test.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE OverloadedStrings #-}+module Main (main) where++import Test.Hspec+import Text.XML.Expat.StreamParser+import Text.XML.Expat.SAX++main :: IO ()+main = hspec spec++spec :: Spec+spec =+  describe "parse XML tests" $ do+  it "skips tags" $+    parseXMLByteString (tag "foo" skipAttrs $ const skipTags)+    (ParseOptions Nothing Nothing) "<foo></foo>"+    `shouldBe` (Right () :: Either (EventParseError String, Maybe XMLParseLocation) ())++