develhevel
develhevel

Reputation: 3281

How to access some XML data with Haskell (using HaXml)?

I want to get access to the data of an XML file like

<?xml version="1.0"?>
<MY>
  <Foo id="1" name="test">
    <Argument name="a" />
  </Foo>
  <Foo id="2" name="test2">
    <Argument name="a" />
    <Argument name="b" />
  </Foo>
  <Other id="2" name="someOther"/>
</MY>

I want e.g. to read out each Foo with its Arguments, how can I do this with Haskell? (I would like to use the HaXml module)

I don't know where to start.

Upvotes: 7

Views: 2510

Answers (5)

Jackie
Jackie

Reputation: 218

There is a tutorial introduction to haxml, my answer comes a little late, but I think the tutorial describes how to parse a XML very similar to the one you provided in your question.

A very simplistic implementation of how to read the XML would be:

c <- fReadXml "your.xml" :: IO ANYContent
print c

Upvotes: 0

Dmitry Olshansky
Dmitry Olshansky

Reputation: 483

With xml-conduit you can do it very simple and straightforward:

{-# LANGUAGE OverloadedStrings #-}

import Data.Conduit
import qualified Text.XML.Stream.Parse as XP
import Data.String(fromString)

parseFile fileName = runResourceT $ XP.parseFile XP.def (fromString fn) 
                                  $$ parseXML

parseXML = XP.force $ XP.tagNoAttr "MY"
         $ XP.many 
         $ XP.tagName "foo" (mapM XP.requiredAttr ["id", "name"]) 
                            $ \(~[i,n]) -> return (i,n)

Upvotes: 1

Dfr
Dfr

Reputation: 4185

Yes, documentation is a big cons about haskell. I wonder why haskell people hate documenting their code so much. No need for fat papers, few usage examples is usually more than enough.

Also small example of HaXML usage available here: http://book.realworldhaskell.org/read/extended-example-web-client-programming.html

Upvotes: 5

mrsteve
mrsteve

Reputation: 4142

I cannot find up to date documentation and examples for haXml.

There is however some documentation for HXT available. I know that's probably an overkill for your example, but anyway.

If you want to use tagsoup, perhaps the following answers might help:
xml-tree parser (Haskell) for graph-library
In Haskell how do you extract strings from an XML document?

Here is the documentation an examples for HXT:
http://www.haskell.org/haskellwiki/HXT/Conversion_of_Haskell_data_from/to_XML
http://www.haskell.org/haskellwiki/HXT
http://www.haskell.org/haskellwiki/HXT/Practical
http://en.wikibooks.org/wiki/Haskell/XML

Now the code using HXT. (warning I am not sure if this is the correct way)

I followed the tutorial: http://www.haskell.org/haskellwiki/HXT/Conversion_of_Haskell_data_from/to_XML

you need your xml file as "data.xml"

import Data.Map (Map, fromList, toList)
import Text.XML.HXT.Core


type Foos = Map String [Foo]

data Foo = Foo
     { 
       fooId :: String 
     , fooName :: String
     , arguments :: [Argument]  
     } 
          deriving (Show, Eq)



data Argument = Argument
      { argName  :: String
      }
           deriving (Show, Eq)

instance XmlPickler Foo where
  xpickle = xpFoo


instance XmlPickler Argument where
  xpickle = xpArgument

-- WHY do we need this?? no clue            
instance XmlPickler Char where
    xpickle = xpPrim

-- this could be wrong
xpFoos :: PU Foos
xpFoos
  = xpWrap (fromList
          , toList
          ) $
  xpList $
      xpElem "MY" $ 
      xpickle

xpFoo :: PU Foo
xpFoo
  = xpElem "Foo" $
     xpWrap ( uncurry3 Foo
            , \ f -> (fooId f
                      , fooName f
                      , arguments f
                     )  
           ) $          
    xpTriple (xpAttr "id" xpText) 
              (xpAttr "name" xpText)
              (xpList xpickle)


xpArgument :: PU Argument
xpArgument
    = xpElem "Argument" $
       xpWrap ( \ ((a)) -> Argument a
               , \ t -> (argName t)
              ) $
       (xpAttr "name" xpText )


main    :: IO ()
main
     = do
       runX ( xunpickleDocument xpFoos
                                [ withValidate no
                                , withTrace 1
                                , withRemoveWS yes
                                , withPreserveComment no
                                ] "data.xml"
         >>>
             arrIO ( \ x -> do {print x ; return x}) 
            )
       return ()

RESULT (you need you xml example as "data.xml"):

-- (1) getXmlContents
-- (1) readDocument: "data.xml" (mime type: "text/xml" ) will be processed
-- (1) readDocument: "data.xml" processed
fromList [("",[Foo {fooId = "1", fooName = "test", arguments = [Argument {argName = "a"}]},
Foo {fooId = "2", fooName = "test2", arguments = [Argument {argName = "a"},
Argument     {argName = "b"}]}])]

Upvotes: 3

augustss
augustss

Reputation: 23014

For simple tasks you might want to consider the tagsoup package.

Upvotes: 5

Related Questions