hexpat (empty) → 0.1
raw patch · 8 files changed
+643/−0 lines, 8 filesdep +basedep +haskell98setup-changed
Dependencies added: base, haskell98
Files
- C2HS.hs +220/−0
- LICENSE +26/−0
- Setup.lhs +4/−0
- Text/XML/Expat/IO.chs +133/−0
- Text/XML/Expat/IO.hs +164/−0
- Text/XML/Expat/Tree.hs +50/−0
- hexpat.cabal +20/−0
- test.hs +26/−0
+ C2HS.hs view
@@ -0,0 +1,220 @@+-- C->Haskell Compiler: Marshalling library+--+-- Copyright (c) [1999...2005] Manuel M T Chakravarty+--+-- Redistribution and use in source and binary forms, with or without+-- modification, are permitted provided that the following conditions are met:+-- +-- 1. Redistributions of source code must retain the above copyright notice,+-- this list of conditions and the following disclaimer. +-- 2. Redistributions in binary form must reproduce the above copyright+-- notice, this list of conditions and the following disclaimer in the+-- documentation and/or other materials provided with the distribution. +-- 3. The name of the author may not be used to endorse or promote products+-- derived from this software without specific prior written permission. +--+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN+-- NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED+-- TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR+-- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+-- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+-- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+--+--- Description ---------------------------------------------------------------+--+-- Language: Haskell 98+--+-- This module provides the marshaling routines for Haskell files produced by +-- C->Haskell for binding to C library interfaces. It exports all of the+-- low-level FFI (language-independent plus the C-specific parts) together+-- with the C->HS-specific higher-level marshalling routines.+--++module C2HS (++ -- * Re-export the language-independent component of the FFI + module Foreign,++ -- * Re-export the C language component of the FFI+ module CForeign,++ -- * Composite marshalling functions+ withCStringLenIntConv, peekCStringLenIntConv, withIntConv, withFloatConv,+ peekIntConv, peekFloatConv, withBool, peekBool, withEnum, peekEnum,++ -- * Conditional results using 'Maybe'+ nothingIf, nothingIfNull,++ -- * Bit masks+ combineBitMasks, containsBitMask, extractBitMasks,++ -- * Conversion between C and Haskell types+ cIntConv, cFloatConv, cToBool, cFromBool, cToEnum, cFromEnum+) where +++import Foreign+ hiding (Word)+ -- Should also hide the Foreign.Marshal.Pool exports in+ -- compilers that export them+import CForeign++import Monad (when, liftM)+++-- Composite marshalling functions+-- -------------------------------++-- Strings with explicit length+--+withCStringLenIntConv s f = withCStringLen s $ \(p, n) -> f (p, cIntConv n)+peekCStringLenIntConv (s, n) = peekCStringLen (s, cIntConv n)++-- Marshalling of numerals+--++withIntConv :: (Storable b, Integral a, Integral b) + => a -> (Ptr b -> IO c) -> IO c+withIntConv = with . cIntConv++withFloatConv :: (Storable b, RealFloat a, RealFloat b) + => a -> (Ptr b -> IO c) -> IO c+withFloatConv = with . cFloatConv++peekIntConv :: (Storable a, Integral a, Integral b) + => Ptr a -> IO b+peekIntConv = liftM cIntConv . peek++peekFloatConv :: (Storable a, RealFloat a, RealFloat b) + => Ptr a -> IO b+peekFloatConv = liftM cFloatConv . peek++-- Passing Booleans by reference+--++withBool :: (Integral a, Storable a) => Bool -> (Ptr a -> IO b) -> IO b+withBool = with . fromBool++peekBool :: (Integral a, Storable a) => Ptr a -> IO Bool+peekBool = liftM toBool . peek+++-- Passing enums by reference+--++withEnum :: (Enum a, Integral b, Storable b) => a -> (Ptr b -> IO c) -> IO c+withEnum = with . cFromEnum++peekEnum :: (Enum a, Integral b, Storable b) => Ptr b -> IO a+peekEnum = liftM cToEnum . peek+++-- Storing of 'Maybe' values+-- -------------------------++instance Storable a => Storable (Maybe a) where+ sizeOf _ = sizeOf (undefined :: Ptr ())+ alignment _ = alignment (undefined :: Ptr ())++ peek p = do+ ptr <- peek (castPtr p)+ if ptr == nullPtr+ then return Nothing+ else liftM Just $ peek ptr++ poke p v = do+ ptr <- case v of+ Nothing -> return nullPtr+ Just v' -> new v'+ poke (castPtr p) ptr+++-- Conditional results using 'Maybe'+-- ---------------------------------++-- Wrap the result into a 'Maybe' type.+--+-- * the predicate determines when the result is considered to be non-existing,+-- ie, it is represented by `Nothing'+--+-- * the second argument allows to map a result wrapped into `Just' to some+-- other domain+--+nothingIf :: (a -> Bool) -> (a -> b) -> a -> Maybe b+nothingIf p f x = if p x then Nothing else Just $ f x++-- |Instance for special casing null pointers.+--+nothingIfNull :: (Ptr a -> b) -> Ptr a -> Maybe b+nothingIfNull = nothingIf (== nullPtr)+++-- Support for bit masks+-- ---------------------++-- Given a list of enumeration values that represent bit masks, combine these+-- masks using bitwise disjunction.+--+combineBitMasks :: (Enum a, Bits b) => [a] -> b+combineBitMasks = foldl (.|.) 0 . map (fromIntegral . fromEnum)++-- Tests whether the given bit mask is contained in the given bit pattern+-- (i.e., all bits set in the mask are also set in the pattern).+--+containsBitMask :: (Bits a, Enum b) => a -> b -> Bool+bits `containsBitMask` bm = let bm' = fromIntegral . fromEnum $ bm+ in+ bm' .&. bits == bm'++-- |Given a bit pattern, yield all bit masks that it contains.+--+-- * This does *not* attempt to compute a minimal set of bit masks that when+-- combined yield the bit pattern, instead all contained bit masks are+-- produced.+--+extractBitMasks :: (Bits a, Enum b, Bounded b) => a -> [b]+extractBitMasks bits = + [bm | bm <- [minBound..maxBound], bits `containsBitMask` bm]+++-- Conversion routines+-- -------------------++-- |Integral conversion+--+cIntConv :: (Integral a, Integral b) => a -> b+cIntConv = fromIntegral++-- |Floating conversion+--+cFloatConv :: (RealFloat a, RealFloat b) => a -> b+cFloatConv = realToFrac+-- As this conversion by default goes via `Rational', it can be very slow...+{-# RULES + "cFloatConv/Float->Float" forall (x::Float). cFloatConv x = x;+ "cFloatConv/Double->Double" forall (x::Double). cFloatConv x = x+ #-}++-- |Obtain C value from Haskell 'Bool'.+--+cFromBool :: Num a => Bool -> a+cFromBool = fromBool++-- |Obtain Haskell 'Bool' from C value.+--+cToBool :: Num a => a -> Bool+cToBool = toBool++-- |Convert a C enumeration to Haskell.+--+cToEnum :: (Integral i, Enum e) => i -> e+cToEnum = toEnum . cIntConv++-- |Convert a Haskell enumeration to C.+--+cFromEnum :: (Enum e, Integral i) => e -> i+cFromEnum = cIntConv . fromEnum
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright (c) 2008 Evan Martin <martine@danga.com>+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:+* Redistributions of source code must retain the above copyright notice,+ this list of conditions and the following disclaimer.+* Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+* Neither the name of the author nor the names of contributors may be+ used to endorse or promote products derived from this software without+ specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.lhs view
@@ -0,0 +1,4 @@+#! /usr/bin/env runhaskell++> import Distribution.Simple+> main = defaultMain
+ Text/XML/Expat/IO.chs view
@@ -0,0 +1,133 @@+-- hexpat, a Haskell wrapper for expat+-- Copyright (C) 2008 Evan Martin <martine@danga.com>++-- |This module wraps the Expat API directly, with IO.++module Text.XML.Expat.IO (+ -- ** Parser Setup+ Parser, newParser,++ -- ** Parsing+ parse,++ -- ** Parser Callbacks+ StartElementHandler, EndElementHandler, CharacterDataHandler,+ setStartElementHandler, setEndElementHandler, setCharacterDataHandler+) where++import C2HS++#include <expat.h>++-- Expat functions start with "XML", but C2HS appears to ignore our "as"+-- definitions if they only differ from the symbol in case. So we write out+-- XML_* in most cases anyway... :(+{#context lib = "expat" prefix = "XML"#}++-- |Opaque parser type.+type ParserPtr = Ptr ()+newtype Parser = Parser (ForeignPtr ())++withParser :: Parser -> (ParserPtr -> IO a) -> IO a+withParser (Parser fp) = withForeignPtr fp++withOptCString :: Maybe String -> (CString -> IO a) -> IO a+withOptCString Nothing f = f nullPtr+withOptCString (Just str) f = withCString str f++{#fun unsafe XML_ParserCreate as parserCreate+ {withOptCString* `Maybe String'} -> `ParserPtr' id#}+foreign import ccall "&XML_ParserFree" parserFree :: FunPtr (ParserPtr -> IO ())++-- |Create a 'Parser'. The optional parameter is the default character+-- encoding, and can be one of+--+-- - \"US-ASCII\"+--+-- - \"UTF-8\"+--+-- - \"UTF-16\"+--+-- - \"ISO-8859-1\"+newParser :: Maybe String -> IO Parser+newParser enc = do+ ptr <- parserCreate enc+ fptr <- newForeignPtr parserFree ptr+ return $ Parser fptr++unStatus :: CInt -> Bool+unStatus 0 = False+unStatus 1 = True+-- |@parse data False@ feeds mode data into a 'Parser'. The end of the data+-- is indicated by passing True for the final parameter. @parse@ returns+-- False on a parse error.+{#fun XML_Parse as parse+ {withParser* `Parser', `String' &, `Bool'} -> `Bool' unStatus#}++-- |The type of the \"element started\" callback. The first parameter is+-- the element name; the second are the (attribute, value) pairs.+type StartElementHandler = String -> [(String,String)] -> IO ()+-- |The type of the \"element ended\" callback. The parameter is+-- the element name.+type EndElementHandler = String -> IO ()+-- |The type of the \"character data\" callback. The parameter is+-- the character data processed. This callback may be called more than once+-- while processing a single conceptual block of text.+type CharacterDataHandler = String -> IO ()++type CStartElementHandler = Ptr () -> CString -> Ptr CString -> IO ()+foreign import ccall "wrapper"+ mkCStartElementHandler :: CStartElementHandler+ -> IO (FunPtr CStartElementHandler)+wrapStartElementHandler :: StartElementHandler+ -> IO (FunPtr CStartElementHandler)+wrapStartElementHandler handler = mkCStartElementHandler h where+ h ptr cname cattrs = do+ name <- peekCString cname+ cattrlist <- peekArray0 nullPtr cattrs+ attrlist <- mapM peekCString cattrlist+ handler name (pairwise attrlist)+-- |Attach a StartElementHandler to a Parser.+setStartElementHandler :: Parser -> StartElementHandler -> IO ()+setStartElementHandler parser handler = do+ withParser parser $ \p -> do+ handler' <- wrapStartElementHandler handler+ {#call unsafe XML_SetStartElementHandler as ^#} p handler'+++type CEndElementHandler = Ptr () -> CString -> IO ()+foreign import ccall "wrapper"+ mkCEndElementHandler :: CEndElementHandler+ -> IO (FunPtr CEndElementHandler)+wrapEndElementHandler :: EndElementHandler+ -> IO (FunPtr CEndElementHandler)+wrapEndElementHandler handler = mkCEndElementHandler h where+ h ptr cname = do+ name <- peekCString cname+ handler name+-- |Attach an EndElementHandler to a Parser.+setEndElementHandler :: Parser -> EndElementHandler -> IO ()+setEndElementHandler parser handler = do+ withParser parser $ \p -> do+ handler' <- wrapEndElementHandler handler+ {#call unsafe XML_SetEndElementHandler as ^#} p handler'++type CCharacterDataHandler = Ptr () -> CString -> CInt -> IO ()+foreign import ccall "wrapper"+ mkCCharacterDataHandler :: CCharacterDataHandler+ -> IO (FunPtr CCharacterDataHandler)+wrapCharacterDataHandler :: CharacterDataHandler+ -> IO (FunPtr CCharacterDataHandler)+wrapCharacterDataHandler handler = mkCCharacterDataHandler h where+ h ptr cdata len = do+ data_ <- peekCStringLen (cdata, fromIntegral len)+ handler data_+-- |Attach an CharacterDataHandler to a Parser.+setCharacterDataHandler :: Parser -> CharacterDataHandler -> IO ()+setCharacterDataHandler parser handler = do+ withParser parser $ \p -> do+ handler' <- wrapCharacterDataHandler handler+ {#call unsafe XML_SetCharacterDataHandler as ^#} p handler'++pairwise (x1:x2:xs) = (x1,x2) : pairwise xs+pairwise [] = []
+ Text/XML/Expat/IO.hs view
@@ -0,0 +1,164 @@+-- GENERATED by C->Haskell Compiler, version 0.15.1 Rainy Days, 31 Aug 2007 (Haskell)+-- Edit the ORIGNAL .chs file instead!+++{-# LINE 1 "IO.chs" #-}-- hexpat, a Haskell wrapper for expat+-- Copyright (C) 2008 Evan Martin <martine@danga.com>++-- |This module wraps the Expat API directly, with IO.++module Text.XML.Expat.IO (+ -- ** Parser Setup+ Parser, newParser,++ -- ** Parsing+ parse,++ -- ** Parser Callbacks+ StartElementHandler, EndElementHandler, CharacterDataHandler,+ setStartElementHandler, setEndElementHandler, setCharacterDataHandler+) where++import C2HS+++-- Expat functions start with "XML", but C2HS appears to ignore our "as"+-- definitions if they only differ from the symbol in case. So we write out+-- XML_* in most cases anyway... :(++{-# LINE 25 "IO.chs" #-}++-- |Opaque parser type.+type ParserPtr = Ptr ()+newtype Parser = Parser (ForeignPtr ())++withParser :: Parser -> (ParserPtr -> IO a) -> IO a+withParser (Parser fp) = withForeignPtr fp++withOptCString :: Maybe String -> (CString -> IO a) -> IO a+withOptCString Nothing f = f nullPtr+withOptCString (Just str) f = withCString str f++parserCreate :: Maybe String -> IO (ParserPtr)+parserCreate a1 =+ withOptCString a1 $ \a1' -> + parserCreate'_ a1' >>= \res ->+ let {res' = id res} in+ return (res')+{-# LINE 39 "IO.chs" #-}+foreign import ccall "&XML_ParserFree" parserFree :: FunPtr (ParserPtr -> IO ())++-- |Create a 'Parser'. The optional parameter is the default character+-- encoding, and can be one of+--+-- - \"US-ASCII\"+--+-- - \"UTF-8\"+--+-- - \"UTF-16\"+--+-- - \"ISO-8859-1\"+newParser :: Maybe String -> IO Parser+newParser enc = do+ ptr <- parserCreate enc+ fptr <- newForeignPtr parserFree ptr+ return $ Parser fptr++unStatus :: CInt -> Bool+unStatus 0 = False+unStatus 1 = True+-- |@parse data False@ feeds mode data into a 'Parser'. The end of the data+-- is indicated by passing True for the final parameter. @parse@ returns+-- False on a parse error.+parse :: Parser -> String -> Bool -> IO (Bool)+parse a1 a2 a3 =+ withParser a1 $ \a1' -> + withCStringLenIntConv a2 $ \(a2'1, a2'2) -> + let {a3' = cFromBool a3} in + parse'_ a1' a2'1 a2'2 a3' >>= \res ->+ let {res' = unStatus res} in+ return (res')+{-# LINE 65 "IO.chs" #-}++-- |The type of the \"element started\" callback. The first parameter is+-- the element name; the second are the (attribute, value) pairs.+type StartElementHandler = String -> [(String,String)] -> IO ()+-- |The type of the \"element ended\" callback. The parameter is+-- the element name.+type EndElementHandler = String -> IO ()+-- |The type of the \"character data\" callback. The parameter is+-- the character data processed. This callback may be called more than once+-- while processing a single conceptual block of text.+type CharacterDataHandler = String -> IO ()++type CStartElementHandler = Ptr () -> CString -> Ptr CString -> IO ()+foreign import ccall "wrapper"+ mkCStartElementHandler :: CStartElementHandler+ -> IO (FunPtr CStartElementHandler)+wrapStartElementHandler :: StartElementHandler+ -> IO (FunPtr CStartElementHandler)+wrapStartElementHandler handler = mkCStartElementHandler h where+ h ptr cname cattrs = do+ name <- peekCString cname+ cattrlist <- peekArray0 nullPtr cattrs+ attrlist <- mapM peekCString cattrlist+ handler name (pairwise attrlist)+-- |Attach a StartElementHandler to a Parser.+setStartElementHandler :: Parser -> StartElementHandler -> IO ()+setStartElementHandler parser handler = do+ withParser parser $ \p -> do+ handler' <- wrapStartElementHandler handler+ xmlSetstartelementhandler p handler'+++type CEndElementHandler = Ptr () -> CString -> IO ()+foreign import ccall "wrapper"+ mkCEndElementHandler :: CEndElementHandler+ -> IO (FunPtr CEndElementHandler)+wrapEndElementHandler :: EndElementHandler+ -> IO (FunPtr CEndElementHandler)+wrapEndElementHandler handler = mkCEndElementHandler h where+ h ptr cname = do+ name <- peekCString cname+ handler name+-- |Attach an EndElementHandler to a Parser.+setEndElementHandler :: Parser -> EndElementHandler -> IO ()+setEndElementHandler parser handler = do+ withParser parser $ \p -> do+ handler' <- wrapEndElementHandler handler+ xmlSetendelementhandler p handler'++type CCharacterDataHandler = Ptr () -> CString -> CInt -> IO ()+foreign import ccall "wrapper"+ mkCCharacterDataHandler :: CCharacterDataHandler+ -> IO (FunPtr CCharacterDataHandler)+wrapCharacterDataHandler :: CharacterDataHandler+ -> IO (FunPtr CCharacterDataHandler)+wrapCharacterDataHandler handler = mkCCharacterDataHandler h where+ h ptr cdata len = do+ data_ <- peekCStringLen (cdata, fromIntegral len)+ handler data_+-- |Attach an CharacterDataHandler to a Parser.+setCharacterDataHandler :: Parser -> CharacterDataHandler -> IO ()+setCharacterDataHandler parser handler = do+ withParser parser $ \p -> do+ handler' <- wrapCharacterDataHandler handler+ xmlSetcharacterdatahandler p handler'++pairwise (x1:x2:xs) = (x1,x2) : pairwise xs+pairwise [] = []++foreign import ccall unsafe "IO.chs.h XML_ParserCreate"+ parserCreate'_ :: ((Ptr CChar) -> (IO (Ptr ())))++foreign import ccall safe "IO.chs.h XML_Parse"+ parse'_ :: ((Ptr ()) -> ((Ptr CChar) -> (CInt -> (CInt -> (IO CInt)))))++foreign import ccall unsafe "IO.chs.h XML_SetStartElementHandler"+ xmlSetstartelementhandler :: ((Ptr ()) -> ((FunPtr ((Ptr ()) -> ((Ptr CChar) -> ((Ptr (Ptr CChar)) -> (IO ()))))) -> (IO ())))++foreign import ccall unsafe "IO.chs.h XML_SetEndElementHandler"+ xmlSetendelementhandler :: ((Ptr ()) -> ((FunPtr ((Ptr ()) -> ((Ptr CChar) -> (IO ())))) -> (IO ())))++foreign import ccall unsafe "IO.chs.h XML_SetCharacterDataHandler"+ xmlSetcharacterdatahandler :: ((Ptr ()) -> ((FunPtr ((Ptr ()) -> ((Ptr CChar) -> (CInt -> (IO ()))))) -> (IO ())))
+ Text/XML/Expat/Tree.hs view
@@ -0,0 +1,50 @@+-- hexpat, a Haskell wrapper for expat+-- Copyright (C) 2008 Evan Martin <martine@danga.com>++-- |The Expat.Tree module provides a simplified interface to parsing, that+-- returns a tree of the XML structure. (Note that this is not a lazy parse+-- of the document: as soon as the root node is accessed, the entire document+-- is parsed.)++module Text.XML.Expat.Tree (+ Text.XML.Expat.Tree.parse, Node(..)+) where++import Text.XML.Expat.IO as EIO+import Data.IORef+import System.IO.Unsafe (unsafePerformIO)++-- |Simplistic XML tree representation.+data Node = Element { eName :: String, eAttrs :: [(String,String)],+ eChildren :: [Node] }+ | Text String+ deriving Show++modifyChildren :: ([Node] -> [Node]) -> Node -> Node+modifyChildren f node = node { eChildren = f (eChildren node) }++-- |@parse enc doc@ parses XML content @doc@ with optional encoding @enc@,+-- and returns the root 'Node' of the document if there were no parsing errors.+parse :: Maybe String -> String -> Maybe Node+parse enc doc = unsafePerformIO $ runParse where+ runParse = do+ parser <- EIO.newParser enc+ -- We maintain the invariant that the stack always has one element,+ -- whose only child at the end of parsing is the root of the actual tree.+ stack <- newIORef [Element "" [] []]+ EIO.setStartElementHandler parser (\n a -> modifyIORef stack (start n a))+ EIO.setEndElementHandler parser (\n -> modifyIORef stack (end n))+ EIO.setCharacterDataHandler parser (\s -> modifyIORef stack (text s))+ ok <- EIO.parse parser doc True+ if ok+ then do+ [Element _ _ [root]] <- readIORef stack+ return $ Just $ modifyChildren reverse root+ else return Nothing+ start name attrs stack = Element name attrs [] : stack+ text str (cur:rest) = modifyChildren (Text str:) cur : rest+ end name (cur:parent:rest) =+ if eName cur /= name then error "name mismatch" else+ let node = modifyChildren reverse cur in+ modifyChildren (node:) parent : rest+
+ hexpat.cabal view
@@ -0,0 +1,20 @@+Cabal-Version: >= 1.2+Name: hexpat+Version: 0.1+Synopsis: wrapper for expat, the fast XML parser+Category: XML+License: BSD3+License-File: LICENSE+Author: Evan Martin+Maintainer: martine@danga.com+Copyright: (c) 2008 Evan Martin <martine@danga.com>+Homepage: http://neugierig.org/software/darcs/browse/?r=hexpat;a=summary+Extra-Source-Files: C2HS.hs test.hs+Build-Type: Simple++Library+ Build-Depends: base, haskell98+ Exposed-Modules: Text.XML.Expat.IO, Text.XML.Expat.Tree+ Extensions: ForeignFunctionInterface+ Extra-Libraries: expat+
+ test.hs view
@@ -0,0 +1,26 @@+import qualified Text.XML.Expat.IO as EIO+import qualified Text.XML.Expat.Tree as ETree+import Data.Tree++main_eio doc = do+ parser <- EIO.newParser Nothing+ EIO.setStartElementHandler parser startElement+ EIO.parse parser doc True+ putStrLn "ok"+ where+ startElement name attrs = putStrLn $ show name ++ " " ++ show attrs++main_tree doc = do+ let etree = ETree.parse Nothing doc+ --let dtree = toDTree etree+ --putStrLn (drawTree dtree)+ etree `seq` putStrLn "ok"+ where+ toDTree (ETree.Element name attrs kids) =+ Node ("<" ++ name ++ " " ++ show attrs ++ ">") (map toDTree kids)+ toDTree (ETree.Text str) = Node (show str) []++main = do+ let doc = "<foo baz='bah'><bar/><text>some & text</text></foo>"+ xml <- readFile "test.xml"+ main_eio xml