-- | A streaming XML parser, using a method known as SAX. SAX isn't really a -- standard, but an implementation, so it's just an \"SAX-like\" parser. -- This module allows you parse an XML document without having to evaluate -- it as a whole. This is needed for protocols like jabber, which use xml -- streams for communication. module Text.XML.HaXml.SAX ( SaxElement(..) , saxParse ) where import Text.XML.HaXml.Types import Text.XML.HaXml.Parse import Text.XML.HaXml.Lex import Text.ParserCombinators.Poly.NoLeak.State data SaxElement = SaxDocTypeDecl DocTypeDecl -- ^ A doctype declaration occured(\<!DOCTYPE\>) | SaxProcessingInstruction ProcessingInstruction -- ^ A processing instruction occured (\<??\>) | SaxComment String -- ^ A comment occured (\<!-- --\>) | SaxElementOpen Name [Attribute] -- ^ An element was opened (\<\>) | SaxElementClose Name -- ^ An element was closed (\<\/\>) | SaxElementTag Name [Attribute] -- ^ An element without content occured (\<\/\>) | SaxCharData CharData -- ^ Some string data occured | SaxReference Reference -- ^ A reference occured -- | @saxParse file content@ takes a filename and the string content of that -- file and generates a stream of @SaxElement@s. If an error occurs, the -- parsing stops and a string is returned using the @Maybe@ type. saxParse :: String -- ^ The filename -> String -- ^ The content of the file -> ([SaxElement],Maybe String) -- ^ A tuple of the parsed elements and @Nothing@, if no -- error occured, or @Just@ @String@ if an error occured. saxParse file cntnt = parseStream sax emptySTs (xmlLex file cntnt) parseStream :: Parser s t a -> s -> [t] -> ([a], Maybe String) parseStream _ _ [] = ([],Nothing) parseStream p state toks = case runParser p state toks of (Left err, _, _) -> ([],Just err) (Right res, nstate, rest) -> (res:moreres, err) where (moreres,err) = parseStream p nstate rest sax :: XParser SaxElement sax = oneOf [ saxelementopen , saxelementclose , saxprocessinginstruction , saxcomment , saxdoctypedecl , saxreference , saxchardata ] `adjustErr` (++("\nLooking for a SAX event:\n" ++" elem-open, elem-close, PI, comment, DTD, ref, or chardata")) saxelementopen :: XParser SaxElement saxelementopen = do tok TokAnyOpen (ElemTag n as) <- elemtag (( do tok TokEndClose return (SaxElementTag n as)) `onFail` ( do tok TokAnyClose return (SaxElementOpen n as)) `onFail` fail "missing > or /> in element tag") saxelementclose :: XParser SaxElement saxelementclose = do tok TokEndOpen n <- name tok TokAnyClose return (SaxElementClose n) saxcomment :: XParser SaxElement saxcomment = comment >>= return . SaxComment saxchardata :: XParser SaxElement saxchardata = (cdsect >>= return . SaxCharData) `onFail` (chardata >>= return . SaxCharData) saxreference :: XParser SaxElement saxreference = reference >>= return . SaxReference saxdoctypedecl :: XParser SaxElement saxdoctypedecl = doctypedecl >>= return . SaxDocTypeDecl saxprocessinginstruction :: XParser SaxElement saxprocessinginstruction = fmap SaxProcessingInstruction processinginstruction