Translate xml to json, and due to using of tagstream-conduit, it can parse malformed xml.
And when combined with aeson's parsing facility, you can use it to parse xml to your haskell data type.
XML
<test "k1"="v1" "k2"="v2"> aaa <p>bbb</p> ccc </test>
JSON
{"test":{"p":"bbb" ,"__attributes":{"k2":"v2","k1":"v1"} ,"__values":["\n ccc\n","aaa\n "] } ,"__values":["\n"] }
XML
<books> <book> <name>foo</name> <author>Jim</author> </book> <book> <name>bar</name> <author>Jake</author> </book> </books>
JSON
{"__values":["\n"] ,"books":{"book":[{"author":"Jim" ,"name":"foo" ,"__values":["\n ","\n "] } ,{"author":"Jake" ,"name":"bar" ,"__values":["\n ","\n "] } ] ,"__values":["\n","\n "] } }
(You can find real example code in tests/Test.hs)
Say you want to parse following xml
<users> <count>100</count> <user> <name>foo</name> <addr>foo addr</addr> </user> <user> <name>bar</name> <addr>bar addr</addr> </user> </users>
And You have follow haskell data type
data User = User { name :: Text , addr :: Text } deriving (Eq) data UserList = UserList { userList :: [User] , userCount :: Int } deriving (Eq)
You want to parse xml into this data type, you can define FromJSON instance for them like this
instance FromJSON User where parseJSON (Object o) = User <$> o .: "name" <*> o .: "addr" parseJSON o = typeMismatch "User" o instance FromJSON UserList where parseJSON (Object o) = do root <- o .: "users" UserList <$> root .: "user" <*> (fmap read (root .: "count")) where parseUserList (Array a) = mapM parseJSON (V.toList a) parseUserList o = typeMismatch "UserList.userList" o parseJSON o = typeMismatch "UserList" o
Then you can use parseXML provided by this library to parse the xml bytestring to your data type:
a <- parseXML xml_string assert $ a == UserList [User "foo" "foo addr", User "bar" "bar addr"] 100