Well, figured out a solution to parsing xml. It's not really pretty, but it works.<br>
<br>
Basically we just convert the incoming xml into a gread compatible format then use gread :-D<br>
<br>
If someone has a more elegant solution, please let me know.<br><br>For the moment, it will only work with Ints and Strings as the children, but it's pretty easy to add new primitive data types, as long as it's pretty easy to make them compatible with gread. You just need to add additional lines to the case statement in
xmlToGShowFormat<br><br>Again, if someone has a more elegant solution, I'd enjoy seeing it, but at least this one works :-D<br>
<br>
module ParseXml<br>
where<br>
<br>
import IO<br>
import Char<br>
import List<br>
import Maybe<br>
import Data.Generics hiding (Unit)<br>
import Text.XML.HXT.Arrow hiding (when)<br>
<br>
data Config = Config{ name :: String, age :: Int } <br>
--data Config = Config{ age :: Int } <br>
deriving( Data, Show, Typeable, Ord, Eq, Read )<br>
<br>
createConfig = Config "qsdfqsdf" 3<br>
--createConfig = Config 3<br>
gshow' :: Data a => a -> String<br>
gshow' t = fromMaybe (showConstr(toConstr t)) (cast t)<br>
<br>
-- helper function from <a href="http://www.defmacro.org/ramblings/haskell-web.html">http://www.defmacro.org/ramblings/haskell-web.html</a><br>
introspectData :: Data a => a -> [(String, String)]<br>
introspectData a = zip fields (gmapQ gshow' a)<br>
where fields = constrFields $ toConstr a<br>
<br>
-- function to create xml string from single-layer Haskell data type<br>
xmlSerialize object = "<" ++ show(toConstr object) ++ ">" ++ <br>
foldr (\(a,b) x -> x ++ "<" ++ a ++ ">" ++ b ++ "</" ++ a ++ ">") "" ( introspectData object )<br>
++ "</" ++ show(toConstr object) ++ ">"<br>
<br>
-- parse xml to HXT tree, and obtain the value of node "fieldname"<br>
-- returns a string<br>
getValue xml fieldname | length(resultlist) > 0 = Just (head resultlist)<br>
| otherwise = Nothing<br>
where resultlist = (runLA ( constA xml >>> xread
>>> deep ( hasName fieldname ) >>> getChildren
>>> getText ))[]<br>
<br>
-- parse templateobject to get list of field names<br>
-- apply these to xml to get list of values<br>
-- return (fieldnames list, value list)<br>
xmlToGShowFormat :: Data a => String -> a -> String<br>
xmlToGShowFormat xml templateobject = <br>
go<br>
where mainconstructorname = (showConstr $ toConstr templateobject)<br>
fields = constrFields $ toConstr templateobject<br>
values = map ( \fieldname -> getValue xml fieldname ) fields<br>
datatypes = gmapQ (dataTypeOf) templateobject<br>
constrs = gmapQ (toConstr) templateobject<br>
datatypereps = gmapQ (dataTypeRep . dataTypeOf) templateobject<br>
fieldtogshowformat (value,datatyperep) = case datatyperep of<br>
IntRep -> "(" ++ fromJust value ++ ")"<br>
_ -> show(fromJust value)<br>
formattedfieldlist = map (fieldtogshowformat) (zip values datatypereps)<br>
go = "(" ++ mainconstructorname ++ " " ++ (concat $ intersperse " " formattedfieldlist ) ++ ")"<br>
<br>
xmlDeserialize xml templateobject = fst $ head $ gread( xmlToGShowFormat xml templateobject)<br>
<br>
dotest = xmlDeserialize (xmlSerialize createConfig) createConfig :: Config<br>
dotest' = xmlDeserialize
("<Config><age>12</age><name>test
name!</name></Config>") createConfig :: Config<br>