I have some XML things to take care of, and I had hoped to use a nice functional language with combinators. But I'm having trouble getting HaXml to do anything useful. Here is a program that I wrote just to read in the XML and prettyprint it. But it fails with an error message. The 'expat' tool 'xmlwf' claims the XML is well formed, and the XML was generated from gpsbabel, a tool I trust to behave properly. And yet: : nr@curlycoat 10429 ; xmlwf 2006-12-27-backup.gpx : nr@curlycoat 10430 ; $AWD/Main 2006-12-27-backup.gpx Main: Parse error: unexpected EOF Here is Main.hs: module Main where import qualified Text.XML.HaXml as X import qualified Text.XML.HaXml.Parse as XP import qualified Text.XML.HaXml.Pretty as XPP import qualified IO import qualified System load :: String -> IO X.Document load fn = do handle <- IO.openFile fn IO.ReadMode contents <- IO.hGetContents handle IO.hClose handle return $ XP.xmlParse fn contents main = do [xml] <- System.getArgs d <- load xml IO.putStrLn $ show $ XPP.document $ d I'm using HaXml version 1.13.2-5 as distributed by Debian, with GHC 6.6. Does anyone have thoughts or suggestions? Is there software I should prefer to HaXml? (I notice that HaXml does not understand XML Schema, which I seem to be stuck with...) Norman
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Wagner Ferenc wrote:
nr@eecs.harvard.edu (Norman Ramsey) writes:
load :: String -> IO X.Document load fn = do handle <- IO.openFile fn IO.ReadMode contents <- IO.hGetContents handle IO.hClose handle return $ XP.xmlParse fn contents
Try not closing the handle before parsing.
I think it's a little more to it than that. The parsing is performed lazily and therefore it's hard to try to close the handle manually, even if HaXml would parse all of the file at once (unless you force the evaluation). The simplest thing is to use readFile (from the Prelude) instead of using handles. readFile will take care of everything for you when the time is right. load fn = do contents <- readFile fn return $ XP.xmlParse fn contents That's it! Cheers, Lennart Kolmodin -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.5 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFFljzs4txYG4KUCuERAuqkAJ9sBHWqo8cViDoqiYIGaBmBQ2/mngCgiZxG HJT4vGCs/LT/aA6hsjMfYgc= =EoQ5 -----END PGP SIGNATURE-----
The simplest thing is to use readFile (from the Prelude) instead of using handles. readFile will take care of everything for you when the time is right.
Thanks---I'll try it. Somehow my hoogle query missed readFile... undoubtedly because I asked for 'String -> IO String' instead of 'FilePath -> IO String'. Dunno if this is a bug or a feature, since as far as the compiler is concerned, FilePath and String are the same type... Norman
Hi
of 'FilePath -> IO String'. Dunno if this is a bug or a feature, since as far as the compiler is concerned, FilePath and String are the same type...
Consider it a bug. Hoogle currently doesn't support type aliases. Version 4 will support them perfectly. As it turns out for type searching aliases are not merely equal, consider: String -> IO () -- putStr FilePath -> IO () -- createDirectory Here you'd like to get out different answers depend on your question, but in both cases the other should appear in the results too, just a little further down. This is what Hoogle 4 does in the development version. Thanks Neil
Ok, I got it working: module Main where import qualified Text.XML.HaXml as X import qualified Text.XML.HaXml.Parse as XP import qualified Text.XML.HaXml.Pretty as XPP import qualified IO import qualified System load fn = do contents <- readFile fn return $ XP.xmlParse fn contents main = do [xml] <- System.getArgs d <- load xml IO.putStrLn $ show $ XPP.document $ d <?xml version="1.0" encoding="UTF-8"?> <employee> <!-- A list of employees --> <name EmpType="Regular"> <first>Almanzo</first> <last>Wilder</last> </name> <name EmpType="Contract"> <first>Laura</first> <last>Ingalls</last> </name> </employee>
Norman Ramsey wrote:
The simplest thing is to use readFile (from the Prelude) instead of using handles. readFile will take care of everything for you when the time is right.
Thanks---I'll try it. Somehow my hoogle query missed readFile... undoubtedly because I asked for 'String -> IO String' instead of 'FilePath -> IO String'. Dunno if this is a bug or a feature, since as far as the compiler is concerned, FilePath and String are the same type...
There seems to be a misunderstanding here: readFile in itself is not the solution. readFile is defined thus: readFile name = openFile name ReadMode >>= hGetContents and the original code was this: load fn = do handle <- IO.openFile fn IO.ReadMode contents <- IO.hGetContents handle IO.hClose handle return $ XP.xmlParse fn contents Sure, you can replace the openFile/hGetContents pair by readFile, but the real problem is the presence of the hClose. Removing that will solve your problem (but note that you now have no control over when the file is actually closed). Cheers, Simon
My 2 cent: Why does seq not help? See code below. Simon Marlow (Thu, Jan 04, 2007 at 03:08:45PM +0000):
and the original code was this:
load fn = do handle <- IO.openFile fn IO.ReadMode contents <- IO.hGetContents handle IO.hClose handle return $ XP.xmlParse fn contents
Sure, you can replace the openFile/hGetContents pair by readFile, but the real problem is the presence of the hClose. Removing that will solve your problem (but note that you now have no control over when the file is actually closed).
load fn = do handle <- IO.openFile fn IO.ReadMode contents <- IO.hGetContents handle let res = XP.xmlParse fn contents seq res $ IO.hClose handle -- maybe use deepSeq return $ res load fn = do handle <- IO.openFile fn IO.ReadMode contents <- IO.hGetContents handle let len = length contents seq len $ IO.hClose handle return $ XP.xmlParse fn contents Cheers, -- Stefan
On 1/4/07, Stefan Karrmann <S.Karrmann@web.de> wrote:
My 2 cent:
Why does seq not help? See code below.
The short answer is because it only forces the head of the value, not the entire value. You need deepSeq for that.
load fn = do handle <- IO.openFile fn IO.ReadMode contents <- IO.hGetContents handle let len = length contents seq len $ IO.hClose handle return $ XP.xmlParse fn contents
This works, because to get the head of len (an integer) you need the whole of contents. -- Taral <taralx@gmail.com> "You can't prove anything." -- Gödel's Incompetence Theorem
There seems to be a misunderstanding here: readFile in itself is not the solution. readFile is defined thus:
readFile name = openFile name ReadMode >>= hGetContents
and the original code was this:
load fn = do handle <- IO.openFile fn IO.ReadMode contents <- IO.hGetContents handle IO.hClose handle return $ XP.xmlParse fn contents
Sure, you can replace the openFile/hGetContents pair by readFile, but the real problem is the presence of the hClose. Removing that will solve your problem (but note that you now have no control over when the file is actually closed).
Can I just leave it hanging and rely on the garbage collector to close it in the fullness of time? Because of laziness, I believe there's no point in my writing the following:
load fn = do handle <- IO.openFile fn IO.ReadMode contents <- IO.hGetContents handle let xml = XP.xmlParse fn contents IO.hClose handle return xml
Is that correct? Norman
On 1/4/07, Norman Ramsey <nr@eecs.harvard.edu> wrote:
There seems to be a misunderstanding here: readFile in itself is not the solution. readFile is defined thus:
readFile name = openFile name ReadMode >>= hGetContents
and the original code was this:
load fn = do handle <- IO.openFile fn IO.ReadMode contents <- IO.hGetContents handle IO.hClose handle return $ XP.xmlParse fn contents
Sure, you can replace the openFile/hGetContents pair by readFile, but the real problem is the presence of the hClose. Removing that will solve your problem (but note that you now have no control over when the file is actually closed).
Can I just leave it hanging and rely on the garbage collector to close it in the fullness of time?
Actually, hGetContents closes the handle when it gets an EOF. If it never does get EOF (because you never use all of the data), the garbage collector *might* close the handle, but I haven't heard of a garbage collector that was aware of the value of resources other than RAM (that is, they don't go out of their way to run finalizers and free up handles to OS resources). Java has the same problem, though I'm not sure if its file handles *have* finalizers, and Python does too, except the refcounting in CPython right now hides it.
"Samuel Bronson" <naesten@gmail.com> wrote:
Can I just leave it hanging and rely on the garbage collector to close it in the fullness of time?
Actually, hGetContents closes the handle when it gets an EOF.
If it never does get EOF (because you never use all of the data), the garbage collector *might* close the handle, but I haven't heard of a garbage collector that was aware of the value of resources other than RAM
Actually, I'm pretty sure that most Haskell RTS implementations have a finalizer attached to all file handles. Once the file handle is no longer reachable from the program graph (even if its data has not been fully consumed), the GC will close the file (via the finalizer) before reaping the memory associated with the handle. Regards, Malcolm
On 1/10/07, Malcolm Wallace <Malcolm.Wallace@cs.york.ac.uk> wrote:
"Samuel Bronson" <naesten@gmail.com> wrote:
Can I just leave it hanging and rely on the garbage collector to close it in the fullness of time?
Actually, hGetContents closes the handle when it gets an EOF.
If it never does get EOF (because you never use all of the data), the garbage collector *might* close the handle, but I haven't heard of a garbage collector that was aware of the value of resources other than RAM
Actually, I'm pretty sure that most Haskell RTS implementations have a finalizer attached to all file handles. Once the file handle is no longer reachable from the program graph (even if its data has not been fully consumed), the GC will close the file (via the finalizer) before reaping the memory associated with the handle.
Yeah, what I mean is that the garbage collector does not *look* for unreachable filehandles to close, or get run when many filehandles have been allocated. It only runs finalizers when it happens upon things with finalizers, it doesn't have any idea what they are for.
Am Donnerstag, 11. Januar 2007 06:05 schrieb Samuel Bronson:
Yeah, what I mean is that the garbage collector does not *look* for unreachable filehandles to close, or get run when many filehandles have been allocated. It only runs finalizers when it happens upon things with finalizers, it doesn't have any idea what they are for.
What could actually be done for open(2) and similar OS calls is that in case of an EMFILE/ENFILE error condition "enough" GC is triggered that unused file handles are closed, and then the open(2) is retried. This does not solve all problems mentioned, but is a step into the right direction. Memory should not be the only resource GC cares about... Cheers, S.
participants (12)
-
Lennart Kolmodin -
Malcolm Wallace -
Neil Mitchell -
Norman Ramsey -
nr@eecs.harvard.edu -
Samuel Bronson -
Simon Marlow -
Stefan Karrmann -
Sven Panne -
Taral -
Terrence Brannon -
Wagner Ferenc