-- | -- Maintainer: Henning Guenther -- -- Helper functions to use a Parsec-Parser for XML documents. module Text.ParserCombinators.Parsec.XML (XMLParser ,anyContent ,content ,element ,text ,namedElement ,namedElementWithAttrs ,stringElement ,recurse ,recurseElements ) where import Text.XML.HaXml.Posn import qualified Text.XML.HaXml.Pretty as Pretty import Text.XML.HaXml.Types import Text.ParserCombinators.Parsec import Text.ParserCombinators.Parsec.Pos -- | A Parser for XML 'Content'. type XMLParser a = GenParser (Content Posn) () a getPosn :: Content Posn -> SourcePos getPosn cont = let posn = case cont of CElem _ p -> p CString _ _ p -> p CRef _ p -> p CMisc _ p -> p in newPos (posnFilename posn) (posnLine posn) (posnColumn posn) classifyContent :: Content a -> String classifyContent cont = (case cont of CElem _ _ -> "element" CString _ _ _ -> "string" CRef _ _ -> "reference" CMisc _ _ -> "misc") ++ "(" ++ (show $ Pretty.content cont) ++ ")" -- | Accepts any content. anyContent :: XMLParser (Content Posn) anyContent = content (Just) -- | Accepts content verified by a function. content :: (Content Posn -> Maybe a) -> XMLParser a content f = token classifyContent getPosn f -- | Forces an 'Element' as next token. element :: XMLParser (Element Posn) element = content (\cont -> case cont of CElem el _ -> Just el _ -> Nothing) "element" -- | Forces plain text as next token. text :: XMLParser String text = content (\cont -> case cont of CString _ str _ -> Just str _ -> Nothing) "text-node" -- | Parses an element with given name. Returns the xml 'Attribute's. namedElementWithAttrs :: String -> XMLParser ([Attribute],[Content Posn]) namedElementWithAttrs name = content (\cont -> case cont of CElem (Elem ename attr conts) _ | ename == name -> Just (attr,conts) | otherwise -> Nothing _ -> Nothing) "element \""++name++"\"" -- | As 'namedElementWithAttrs', ony that the attributes are ignored. namedElement :: String -> XMLParser [Content Posn] namedElement name = namedElementWithAttrs name >>= return.snd -- | Parses an element with a given name. The text content is returned. stringElement :: String -> XMLParser String stringElement name = namedElement name >>= recurse (option "" text) -- | Helper function to recurse through an XML document. recurseElements :: XMLParser a -> [Content Posn] -> XMLParser a recurseElements p conts = recurse p [ el | el@(CElem _ _) <- conts ] -- | Helper function to recurse through an XML document. recurse :: XMLParser a -> [Content Posn] -> XMLParser a recurse p conts = do inp <- getInput setInput conts res <- p setInput inp return res