packages feed

expat-enumerator (empty) → 0.1

raw patch · 4 files changed

+194/−0 lines, 4 filesdep +basedep +bytestringdep +enumeratorsetup-changed

Dependencies added: base, bytestring, enumerator, hexpat, text, transformers, xml-types

Files

+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Text/XML/Expat/Enumerator.hs view
@@ -0,0 +1,141 @@+{-# LANGUAGE DeriveDataTypeable #-}++-----------------------------------------------------------------------------+-- |+-- Module: Text.XML.Expat.Enumerator+-- Copyright: 2010 John Millikin+-- License: MIT+--+-- Maintainer: jmillikin@gmail.com+-- Portability: portable+--+-----------------------------------------------------------------------------+module Text.XML.Expat.Enumerator+	( Expat.Encoding (..)+	, ParseError (..)+	, parseBytesIO+	, parseTextIO+	) where+import qualified Data.ByteString as B+import qualified Data.Enumerator as E+import qualified Data.Enumerator.Text as ET+import Data.Enumerator ((>>==), ($$))+import qualified Data.Text as T+import qualified Data.Text.Encoding as TE+import qualified Data.Text.Lazy as TL+import qualified Data.XML.Types as X+import qualified Text.XML.Expat.Internal.IO as Expat++import qualified Control.Exception as Exc+import Control.Monad (forM)+import Control.Monad.IO.Class (MonadIO, liftIO)+import Data.Typeable (Typeable)+import qualified Data.IORef as IO+import Foreign.C (CString, CStringLen)++-- | A replacement for 'Expat.XMLParseError', defined so it can be given+-- a non-orphan 'Exc.Exception' instance.+data ParseError = ParseError+	{ parseErrorMessage :: T.Text+	, parseErrorLocation :: Expat.XMLParseLocation+	}+	deriving (Show, Typeable)++instance Exc.Exception ParseError++parseTextIO :: MonadIO m => E.Enumeratee T.Text X.Event m b+parseTextIO s = E.joinI (ET.encode ET.utf8 $$ parseBytesIO (Just Expat.UTF8) s)++parseBytesIO :: MonadIO m+             => Maybe Expat.Encoding -- ^ If present, will override Expat's+                                     -- encoding detection.+             -> E.Enumeratee B.ByteString X.Event m b+parseBytesIO enc s = do+	p <- liftIO $ Expat.newParser enc+	ref <- liftIO $ setCallbacks p+	eneeParser p ref s++setCallbacks :: Expat.Parser -> IO (IO.IORef [X.Event])+setCallbacks p = do+	eventRef <- IO.newIORef []+	let addEvent e = IO.modifyIORef eventRef (e:) >> return True+	let toName local = X.Name local Nothing Nothing+	+	Expat.setStartElementHandler p $ \_ cName cAttrs -> do+		local <- peekUTF8 cName+		attrs <- forM cAttrs $ \(cAttrName, cAttrText) -> do+			attrLocal <- peekUTF8 cAttrName+			attrText <- peekUTF8 cAttrText+			let content = X.ContentText attrText+			return $ X.Attribute (toName attrLocal) [content]+		addEvent (X.EventBeginElement (toName local) attrs)+	+	Expat.setEndElementHandler p $ \_ cName -> do+		local <- peekUTF8 cName+		addEvent (X.EventEndElement (toName local))+	+	Expat.setCharacterDataHandler p $ \_ cstr -> do+		text <- peekUTF8Len cstr+		addEvent (X.EventContent (X.ContentText text))+	+	Expat.setProcessingInstructionHandler p $ \_ ctgt cdst -> do+		tgt <- peekUTF8 ctgt+		dst <- peekUTF8 cdst+		addEvent (X.EventInstruction (X.Instruction tgt dst))+	+	Expat.setCommentHandler p $ \_ cstr -> do+		text <- peekUTF8 cstr+		addEvent (X.EventComment text)+	+	return eventRef++eneeParser :: MonadIO m+           => Expat.Parser+           -> IO.IORef [X.Event]+           -> E.Enumeratee B.ByteString X.Event m b+eneeParser p eventRef = E.checkDone (E.continue . step) where+	step k E.EOF = checkEvents k+		(\ptr -> Expat.parseChunk ptr B.empty True)+		(\k' -> E.yield (E.Continue k') E.EOF)+	+	step k (E.Chunks []) = E.continue (step k)+	step k (E.Chunks xs) = checkEvents k+		(\ptr -> parseChunks ptr xs)+		(\k' -> E.continue (step k'))+	+	parseChunks _ [] = error "Text.XML.Expat.Enumerator: parseChunks []"+	parseChunks ptr (x:xs) = do+		maybeErr <- Expat.parseChunk ptr x False+		case maybeErr of+			Just err -> return (Just err)+			Nothing -> if null xs+				then return Nothing+				else parseChunks ptr xs+	+	checkEvents k runParse next = do+		(events, maybeErr) <- liftIO (getEvents runParse)+		let checkError k' = case maybeErr of+			Nothing -> next k'+			Just err -> throwError err+		if null events+			then checkError k+			else k (E.Chunks events) >>== E.checkDone checkError+	+	getEvents runParse = liftIO $ do+		IO.writeIORef eventRef []+		err <- Expat.withParser p runParse+		events <- IO.readIORef eventRef+		return (reverse events, err)+	+	throwError err = E.throwError (ParseError (T.pack msg) loc) where+		Expat.XMLParseError msg loc = err++peekUTF8 :: CString -> IO TL.Text+peekUTF8 cstr = do+	bytes <- B.packCString cstr+	return (TL.fromChunks [TE.decodeUtf8 bytes])++peekUTF8Len :: CStringLen -> IO TL.Text+peekUTF8Len cstr = do+	bytes <- B.packCStringLen cstr+	return (TL.fromChunks [TE.decodeUtf8 bytes])
+ expat-enumerator.cabal view
@@ -0,0 +1,29 @@+name: expat-enumerator+version: 0.1+synopsis: Enumerator-based API for Expat+license: MIT+license-file: license.txt+author: John Millikin <jmillikin@gmail.com>+maintainer: jmillikin@gmail.com+copyright: Copyright (c) John Millikin 2010+build-type: Simple+cabal-version: >=1.6+category: Enumerator, Text, XML, Parsing+stability: experimental+bug-reports: mailto:jmillikin@gmail.com+tested-with: GHC==6.12.1++library+  ghc-options: -Wall -fno-warn-unused-do-bind++  build-depends:+      base >= 4 && < 5+    , bytestring >= 0.9 && < 0.10+    , text >= 0.7 && < 0.8+    , enumerator >= 0.4 && < 0.5+    , transformers >= 0.2 && < 0.3+    , hexpat >= 0.19 && < 0.20+    , xml-types >= 0.1.1 && < 0.2++  exposed-modules:+    Text.XML.Expat.Enumerator
+ license.txt view
@@ -0,0 +1,22 @@+Copyright (c) 2010 John Millikin++Permission is hereby granted, free of charge, to any person+obtaining a copy of this software and associated documentation+files (the "Software"), to deal in the Software without+restriction, including without limitation the rights to use,+copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the+Software is furnished to do so, subject to the following+conditions:++The above copyright notice and this permission notice shall be+included in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR+OTHER DEALINGS IN THE SOFTWARE.