From hughperkins at gmail.com Sun Jul 1 18:01:05 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Sun Jul 1 17:55:07 2007 Subject: [Hs-Generics] xml deserialization using generics? In-Reply-To: <837db430706301017r5cafa61ej4337424c512707cd@mail.gmail.com> References: <837db430706261239p1b4f456an385f31ccde7e4628@mail.gmail.com> <20070627083912.51533AD43@Adric.metnet.fnmoc.navy.mil> <837db430706301017r5cafa61ej4337424c512707cd@mail.gmail.com> Message-ID: <837db430707011501q73b38bbbh4484cd097ce0719a@mail.gmail.com> 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 ++ "") "" ( introspectData 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 ("12test name!") createConfig :: Config -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/generics/attachments/20070702/e6ddd8f6/attachment.htm From hughperkins at gmail.com Sun Jul 1 18:16:11 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Sun Jul 1 18:10:11 2007 Subject: [Hs-Generics] Making a call to a function specified as a string??? Message-ID: <837db430707011516v42e5e2b5pbae9ff3b6d95ea65@mail.gmail.com> Next question: any way to call a function specified as a string? gshow( somefunction ) produces gshow on the output of the function, rather than on the function itself, so not got very far so far. For background, the idea is to be able to serialize a function call to something we can pass over the network ,deserialize on the other end, and process appropriately. One could presumably do this using a generator of some sort. Is this the only option? I can live with using a generator for this; it's the usual way most implementations of this kind of thing work (ICE, WCF, ...); but if we can avoid using a generator, *** and stay strongly typed ***, it's better. For example, in traditional imperative languages, we'd specify an interface - so ensuring we are strongly typed - and then we are free to implement a serialization/deserialization scheme of our choice. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/generics/attachments/20070702/4394c92c/attachment.htm From oleg at pobox.com Tue Jul 3 03:33:21 2007 From: oleg at pobox.com (oleg@pobox.com) Date: Tue Jul 3 03:30:01 2007 Subject: [Hs-Generics] xml deserialization using generics? In-Reply-To: <837db430706301017r5cafa61ej4337424c512707cd@mail.gmail.com> Message-ID: <20070703073321.003D9AD46@Adric.metnet.fnmoc.navy.mil> Hugh Perkins wrote: > Unfortunately I cant seem to run it. It comes up with strange typing > messages when compiling: > *TestDeserialize> serialize P > :1:0: > No instance for (LDat (TL_red [a]) > ... > where P is: > getP = P "Lammel" "Amsterdam" > (for simplicity) > Similar looking errors with genCom, and/or with deserialize. > I guess I need to add an instance or deriving statement to the P class? You have encountered a bit confusing behavior of GHCi. If you put > getP = P "Lammel" "Amsterdam" > t2 = serialize getP into the file Deserialize.hs, which you then load into GHCi, you can type "t2" at the GHCi prompt and see the expected result. OTH, typing "serialize getP" at the GHCi prompt gives the error you reported. This is a well known issue with GHCi: it uses the flags given in the OPTIONS_GHC pragma when interpreting files, but forgets these flags when interpreting expressions typed at the prompt. I think this a bit confusing behavior started since GHC 6.4.0. So, you could place any complex expression in a file and load that into GHCi (Haskell Emacs mode makes this quite convenient), or start your GHCi with appropriate flags (at least, -fglasgow-exts). The third alternative is to help GHCi by defining serialize like the following > serialize1 xs = > gapp (TL_red (concat::[[String]]->[String])) primitive_fields_show xs with the explicit signature for 'concat'. We can now type "serialize1 getP" at the GHCi prompt and get the desired result.