开发者

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" 开发者_JAVA百科/>
    <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.


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


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


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"}]}])]


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)


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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜