xml-conduit-decode-1.0.0.0: Historical cursors & decoding on top of xml-conduit.

Copyright(c) Ben Kolera
LicenseMIT
MaintainerBen Kolera
Stabilityexperimental
Safe HaskellNone
LanguageHaskell2010

Text.XML.Decode

Description

This library extends the functionality of Cursor to allow you to accumulate history as you traverse the structure. This leads to greater context about why your decoder failed when it invariably does.

Here is an example of a decoder:

data BookCategory
  = Haskell
  | Scala
  | Programming
  | FunctionalProgramming
  deriving (Eq,Show)

bookCategoryFromText :: Text -> Maybe BookCategory
bookCategoryFromText Haskell                = Just Haskell
bookCategoryFromText Scala                  = Just Scala
bookCategoryFromText Programming            = Just Programming
bookCategoryFromText "Functional Programming" = Just FunctionalProgramming
bookCategoryFromText _ = Nothing


data LibrarySection
  = Fiction Text       -- Fiction by author first letter(s)
  | NonFiction Double  -- Dewey decimal number
  deriving (Eq,Show)
makePrisms ''LibrarySection

data Book    = Book
  { _bookId           :: Integer
  , _bookName         :: Text
  , _bookSection      :: LibrarySection
  , _bookPublished    :: Day
  , _bookLastBorrowed :: Maybe UTCTime
  , _bookCategories   :: [BookCategory]
  } deriving (Eq,Show)
makeLenses ''Book

data Library = Library
  { _books :: [Book]
  } deriving (Eq,Show)
makeLenses ''Library

instance DecodeCursor BookCategory where
  decode = parseCursor (parseMaybe BookCategory bookCategoryFromText)

instance DecodeCursor LibrarySection where
  decode = decodeChoice
    [ choice (laxElement "fiction") decodeFiction
    , choice (laxElement "non_fiction") decodeNonFiction
    ]
    where
      decodeFiction  c   = Fiction $ parseCursor parseText c
      decodeNonFiction c = NonFiction $ parseCursor parseDouble c

instance DecodeCursor Book where
  decode c = Book
    $ decodeAttr    "id" parseInteger c
    * decodeSingle  (c %/ laxElement "name")
    * decodeSingle  (c %/ laxElement "section")
    * (decodeSingle (c %/ laxElement "published") & toDay)
    * (decodeMay    (c %/ laxElement "lastBorrowed") & fmap toUtcT)
    * decodeMany    (c %/ laxElement "category")

instance DecodeCursor Library where
  decode c = Library
    $ decodeMany ( c %/ laxElement "book" )

If you tried to decode the following XML with a bad value for the section:

library
  id="1"
    nameLearn you a haskell for great good!/name
    section
      reference5.1/reference
    /section
    published2011-04-21/published
    lastBorrowed2015-01-05T16:30:00Z/lastBorrowed
    categoryProgramming/category
    categoryHaskell/category
    categoryFunctional Programming/category
  /book
/library

Then you'd get an error that looks like this:

  Left (
    "Choices Exhausted"
    , [ MoveAxis Child , LaxElement "book"
      , MoveAxis Child , LaxElement "section"
      , Choice
        [ [ MoveAxis Child , LaxElement "fiction" ]
        , [ MoveAxis Child , LaxElement "non_fiction" ]]
        Nothing
      ])

Checkout the tests for more examples!

Documentation