[Hs-Generics] xml deserialization using generics?
Hugh Perkins
hughperkins at gmail.com
Sun Jul 1 18:01:05 EDT 2007
Well, figured out a solution to parsing xml. It's not really pretty, but it
works.
Basically we just convert the incoming xml into a gread compatible format
then use gread :-D
If someone has a more elegant solution, please let me know.
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
Again, if someone has a more elegant solution, I'd enjoy seeing it, but at
least this one works :-D
module ParseXml
where
import IO
import Char
import List
import Maybe
import Data.Generics hiding (Unit)
import Text.XML.HXT.Arrow hiding (when)
data Config = Config{ name :: String, age :: Int }
--data Config = Config{ age :: Int }
deriving( Data, Show, Typeable, Ord, Eq, Read )
createConfig = Config "qsdfqsdf" 3
--createConfig = Config 3
gshow' :: Data a => a -> String
gshow' t = fromMaybe (showConstr(toConstr t)) (cast t)
-- helper function from http://www.defmacro.org/ramblings/haskell-web.html
introspectData :: Data a => a -> [(String, String)]
introspectData a = zip fields (gmapQ gshow' a)
where fields = constrFields $ toConstr a
-- function to create xml string from single-layer Haskell data type
xmlSerialize object = "<" ++ show(toConstr object) ++ ">" ++
foldr (\(a,b) x -> x ++ "<" ++ a ++ ">" ++ b ++ "</" ++ a ++ ">") "" (
introspectData object )
++ "</" ++ show(toConstr object) ++ ">"
-- parse xml to HXT tree, and obtain the value of node "fieldname"
-- returns a string
getValue xml fieldname | length(resultlist) > 0 = Just (head resultlist)
| otherwise = Nothing
where resultlist = (runLA ( constA xml >>> xread >>> deep ( hasName
fieldname ) >>> getChildren >>> getText ))[]
-- parse templateobject to get list of field names
-- apply these to xml to get list of values
-- return (fieldnames list, value list)
xmlToGShowFormat :: Data a => String -> a -> String
xmlToGShowFormat xml templateobject =
go
where mainconstructorname = (showConstr $ toConstr templateobject)
fields = constrFields $ toConstr templateobject
values = map ( \fieldname -> getValue xml fieldname ) fields
datatypes = gmapQ (dataTypeOf) templateobject
constrs = gmapQ (toConstr) templateobject
datatypereps = gmapQ (dataTypeRep . dataTypeOf) templateobject
fieldtogshowformat (value,datatyperep) = case datatyperep of
IntRep -> "(" ++ fromJust value ++ ")"
_ -> show(fromJust value)
formattedfieldlist = map (fieldtogshowformat) (zip values
datatypereps)
go = "(" ++ mainconstructorname ++ " " ++ (concat $ intersperse " "
formattedfieldlist ) ++ ")"
xmlDeserialize xml templateobject = fst $ head $ gread( xmlToGShowFormat xml
templateobject)
dotest = xmlDeserialize (xmlSerialize createConfig) createConfig :: Config
dotest' = xmlDeserialize ("<Config><age>12</age><name>test
name!</name></Config>") createConfig :: Config
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/generics/attachments/20070702/e6ddd8f6/attachment.htm
More information about the Generics
mailing list