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 ++ "" ++ 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 ("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.