diff --git a/Data/OpenDataTable.hs b/Data/OpenDataTable.hs
new file mode 100644
--- /dev/null
+++ b/Data/OpenDataTable.hs
@@ -0,0 +1,281 @@
+{-# LANGUAGE TemplateHaskell #-}
+
+module Data.OpenDataTable
+       ( Binding(..)
+       , Delete(..)
+       , Function(..)
+       , FunctionType(..)
+       , Input(..)
+       , InputInfo(..)
+       , InputType(..)
+       , Insert(..)
+       , NextPage(..)
+       , Meta(..)
+       , OpenDataTable(..)
+       , Paging(..)
+       , PagingModel(..)
+       , PagingSize(..)
+       , PagingStart(..)
+       , PagingTotal(..)
+       , ParamType(..)
+       , Product(..)
+       , SecurityLevel(..)
+       , Select(..)
+       , Update(..) ) where
+
+import Language.Haskell.TH.Lift (deriveLift)
+
+import Text.Read
+import Text.ParserCombinators.ReadP hiding (choice)
+
+strValMap = map (\(x, y) -> lift $ string x >> return y)
+
+data OpenDataTable
+  = OpenDataTable
+    { openDataTableXmlns         :: Maybe String
+    , openDataTableSecurityLevel :: Maybe SecurityLevel
+    , openDataTableHttps         :: Maybe Bool
+    , openDataTableMeta          :: Meta
+    , openDataTableExecute       :: Maybe String
+    , openDataTableBindings      :: [Binding]
+    } deriving (Read, Show, Eq)
+
+data SecurityLevel
+  = SecurityLevelAny | SecurityLevelApp | SecurityLevelUser
+  deriving (Eq)
+
+instance Read SecurityLevel where
+  readPrec = choice $ strValMap
+             [ ("any", SecurityLevelAny)
+             , ("app", SecurityLevelApp)
+             , ("user", SecurityLevelUser) ]
+
+instance Show SecurityLevel where
+  showsPrec _ SecurityLevelAny  = showString "any"
+  showsPrec _ SecurityLevelApp  = showString "app"
+  showsPrec _ SecurityLevelUser = showString "user"
+
+data Meta
+  = Meta
+    { metaAuthor           :: Maybe String
+    , metaDescription      :: Maybe String
+    , metaDocumentationURL :: Maybe String
+    , metaApiKeyURL        :: Maybe String
+    , metaSampleQuery      :: [String]
+    } deriving (Read, Show, Eq)
+
+data Binding
+  = SelectBinding Select
+  | InsertBinding Insert
+  | UpdateBinding Update
+  | DeleteBinding Delete
+  | FunctionBinding Function
+  deriving (Read, Show, Eq)
+
+data Select
+  = Select
+    { selectItemPath                :: Maybe String
+    , selectProduces                :: Maybe Product
+    , selectPollingFrequencySeconds :: Maybe Integer
+    , selectUrl                     :: Maybe String
+    , selectInputs                  :: [Input]
+    , selectExecute                 :: Maybe String
+    , selectPaging                  :: Maybe Paging
+    }  deriving (Read, Show, Eq)
+
+data Paging
+  = Paging
+    { pagingModel    :: Maybe PagingModel
+    , pagingMatrix   :: Maybe Bool
+    , pagingPageSize :: Maybe PagingSize
+    , pagingStart    :: Maybe PagingStart
+    , pagingTotal    :: Maybe PagingTotal
+    , pagingNextPage :: Maybe NextPage
+    } deriving (Read, Show, Eq)
+
+data PagingModel
+  = PagingModelOffset | PagingModelPage | PagingModelURL
+  deriving (Eq)
+
+instance Read PagingModel where
+  readPrec = choice $ strValMap
+             [ ("offset", PagingModelOffset)
+             , ("page", PagingModelPage)
+             , ("url", PagingModelURL) ]
+
+instance Show PagingModel where
+  showsPrec _ PagingModelOffset  = showString "offset"
+  showsPrec _ PagingModelPage  = showString "page"
+  showsPrec _ PagingModelURL = showString "url"
+
+data PagingSize
+  = PagingSize
+    { pagingSizeId  :: String
+    , pagingSizeMax :: Integer
+    } deriving (Read, Show, Eq)
+
+data PagingStart
+  = PagingStart
+    { pagingStartId      :: String
+    , pagingStartDefault :: Integer
+    } deriving (Read, Show, Eq)
+
+data PagingTotal
+  = PagingTotal
+    { pagingTotalDefault :: Integer
+    } deriving (Read, Show, Eq)
+
+data NextPage
+  = NextPage
+    { nextPagePath :: String
+    } deriving (Read, Show, Eq)
+
+data Insert
+  = Insert
+    { insertItemPath                :: Maybe String
+    , insertPollingFrequencySeconds :: Maybe Integer
+    , insertProduces                :: Maybe Product
+    , insertUrls                    :: [String]
+    , insertInputs                  :: [Input]
+    }  deriving (Read, Show, Eq)
+
+data Update
+  = Update
+    { updateItemPath                :: Maybe String
+    , updatePollingFrequencySeconds :: Maybe Integer
+    , updateProduces                :: Maybe Product
+    , updateUrls                    :: [String]
+    , updateInputs                  :: [Input]
+    }  deriving (Read, Show, Eq)
+
+data Delete
+  = Delete
+    { deleteItemPath                :: Maybe String
+    , deletePollingFrequencySeconds :: Maybe Integer
+    , deleteProduces                :: Maybe Product
+    , deleteUrls                    :: [String]
+    , deleteInputs                  :: [Input]
+    }  deriving (Read, Show, Eq)
+
+data Product
+  = ProductXML | ProductJSON
+  deriving (Eq)
+
+instance Read Product where
+  readPrec = choice $ strValMap
+             [ ("XML", ProductXML)
+             , ("JSON", ProductJSON) ]
+
+instance Show Product where
+  showsPrec _ ProductXML  = showString "XML"
+  showsPrec _ ProductJSON = showString "JSON"
+
+data Function
+  = Function
+    { functionName :: Maybe String
+    , functionType :: FunctionType
+    } deriving (Read, Show, Eq)
+
+data FunctionType
+  = FunctionTypeStream | FunctionTypeReduce
+  deriving (Eq)
+
+instance Read FunctionType where
+  readPrec = choice $ strValMap
+             [ ("stream", FunctionTypeStream)
+             , ("reduce", FunctionTypeReduce) ]
+
+instance Show FunctionType where
+  showsPrec _ FunctionTypeStream = showString "stream"
+  showsPrec _ FunctionTypeReduce = showString "reduce"
+
+data Input
+  = InputKey InputInfo
+  | InputValue InputInfo
+  | InputMap InputInfo
+  deriving (Read, Show, Eq)
+
+data InputInfo
+  = InputInfo
+    { inputInfoId            :: String
+    , inputInfoAs            :: Maybe String
+    , inputInfoType          :: InputType
+    , inputInfoParamType     :: ParamType
+    , inputInfoRequired      :: Bool
+    , inputInfoDefault       :: Maybe String
+    , inputInfoPrivate       :: Maybe Bool
+    , inputInfoConst         :: Maybe Bool
+    , inputInfoBatchable     :: Maybe Bool
+    , inputInfoMaxBatchItems :: Maybe Integer
+    } deriving (Read, Show, Eq)
+
+data InputType =
+  InputTypeBool   |
+  InputTypeDate   |
+  InputTypeDouble |
+  InputTypeFloat  |
+  InputTypeInt    |
+  InputTypeString
+  deriving (Eq)
+
+instance Read InputType where
+  readPrec = choice $ strValMap
+             [ ("xs:bool", InputTypeBool)
+             , ("xs:boolean", InputTypeBool)
+             , ("xs:date", InputTypeDate)
+             , ("xs:double", InputTypeDouble)
+             , ("xs:float", InputTypeFloat)
+             , ("xs:int", InputTypeInt)
+             , ("xs:integer", InputTypeInt)
+             , ("xs:number", InputTypeDouble)
+             , ("xs:string", InputTypeString)]
+
+instance Show InputType where
+  showsPrec _ InputTypeBool   = showString "xs:bool"
+  showsPrec _ InputTypeDate   = showString "xs:date"
+  showsPrec _ InputTypeDouble = showString "xs:double"
+  showsPrec _ InputTypeFloat  = showString "xs:float"
+  showsPrec _ InputTypeInt    = showString "xs:int"
+  showsPrec _ InputTypeString = showString "xs:string"
+
+data ParamType
+  = ParamTypeQuery | ParamTypeMatrix | ParamTypeHeader
+  | ParamTypePath  | ParamTypeVariable
+  deriving (Eq)
+
+instance Read ParamType where
+  readPrec = choice $ strValMap
+             [ ("query", ParamTypeQuery)
+             , ("matrix", ParamTypeMatrix)
+             , ("header", ParamTypeHeader)
+             , ("path", ParamTypePath)
+             , ("variable", ParamTypeVariable) ]
+
+instance Show ParamType where
+  showsPrec _ ParamTypeQuery = showString "query"
+  showsPrec _ ParamTypeMatrix = showString "matrix"
+  showsPrec _ ParamTypeHeader = showString "header"
+  showsPrec _ ParamTypePath = showString "path"
+  showsPrec _ ParamTypeVariable = showString "variable"
+
+$(deriveLift ''OpenDataTable)
+$(deriveLift ''SecurityLevel)
+$(deriveLift ''Delete)
+$(deriveLift ''Meta)
+$(deriveLift ''Binding)
+$(deriveLift ''Select)
+$(deriveLift ''Paging)
+$(deriveLift ''PagingModel)
+$(deriveLift ''PagingSize)
+$(deriveLift ''PagingStart)
+$(deriveLift ''PagingTotal)
+$(deriveLift ''NextPage)
+$(deriveLift ''Insert)
+$(deriveLift ''Update)
+$(deriveLift ''Product)
+$(deriveLift ''Function)
+$(deriveLift ''FunctionType)
+$(deriveLift ''Input)
+$(deriveLift ''InputInfo)
+$(deriveLift ''InputType)
+$(deriveLift ''ParamType)
diff --git a/Data/OpenDataTable/Parser.hs b/Data/OpenDataTable/Parser.hs
new file mode 100644
--- /dev/null
+++ b/Data/OpenDataTable/Parser.hs
@@ -0,0 +1,269 @@
+{-# LANGUAGE Arrows  #-}
+
+module Data.OpenDataTable.Parser
+       ( parseBindings
+       , parseInput
+       , parseInputInfo
+       , parsePaging
+       , parsePagingNextPage
+       , parsePagingPageSize
+       , parsePagingStart
+       , parsePagingTotal
+       , parseMeta
+       , parseOpenDataTable
+       , parseSelect ) where
+
+import Text.Read
+import Data.Maybe
+
+import Text.XML.HXT.Core (arr, deep, constA, isElem, orElse, returnA,
+                          isA, listA, getText, none,
+                          hasName, getChildren,  getAttrValue0,
+                          (<<<),  (>>>),
+                          XmlTree, ArrowXml, ArrowList, ArrowChoice)
+
+import Data.OpenDataTable
+
+readBoolMaybe :: String -> Maybe Bool
+readBoolMaybe "true"  = Just True
+readBoolMaybe "false" = Just False
+readBoolMaybe _       = Nothing
+
+atTag :: ArrowXml a => String -> a XmlTree XmlTree
+atTag tag = deep (isElem >>> hasName tag)
+
+atOptionalTag :: ArrowXml a => String -> a XmlTree (Maybe XmlTree)
+atOptionalTag tag = deep (isElem >>> hasName tag >>> arr Just)
+                `orElse` (constA Nothing)
+
+text :: ArrowXml a => a XmlTree String
+text = getChildren >>> getText
+
+textAtTag :: ArrowXml a => String -> a XmlTree String
+textAtTag tag = atTag tag >>> text
+
+getList :: ArrowXml a => String -> a XmlTree c -> a XmlTree [c]
+getList tag cont = listA ( atTag tag >>> cont)
+
+getOptionalList :: (ArrowChoice a, ArrowXml a) =>
+                   String -> a XmlTree b -> a (Maybe XmlTree) [b]
+getOptionalList tag cont =
+  proc x -> do
+    case x of
+      Nothing -> returnA -< []
+      Just xml -> returnA  <<< getList tag cont -< xml
+
+significant :: String -> Bool
+significant = not . all (`elem` " \n\r\t")
+
+optionalAttr :: ArrowXml a => String -> a XmlTree (Maybe String)
+optionalAttr attr =
+  (getAttrValue0 attr >>> isA significant >>> arr Just)
+  `orElse` (constA Nothing)
+
+optionalTextAtTag :: ArrowXml a => String -> a XmlTree (Maybe String)
+optionalTextAtTag tag =
+  (textAtTag tag >>> arr Just)
+  `orElse` (constA Nothing)
+
+optionalTextAtOptionalTag :: (ArrowChoice a, ArrowXml a) =>
+                             String -> a (Maybe XmlTree) (Maybe String)
+optionalTextAtOptionalTag tag =
+  proc mx -> do
+    case mx of
+     Nothing -> returnA -< Nothing
+     Just x -> optionalTextAtTag tag -< x
+
+readOptionalAttrVal :: (ArrowChoice a, ArrowList a) =>
+                       (b -> Maybe c) -> a (Maybe b) (Maybe c)
+readOptionalAttrVal reader =
+  proc x -> do
+    case x of
+      Nothing   -> returnA -< Nothing
+      Just attr -> do
+        let mRead = reader attr
+        case mRead of
+          Nothing  -> none    -< Nothing
+          Just val -> returnA -< Just val
+
+readOptionalAttr :: (ArrowList a, ArrowChoice a, Read c) =>
+                    a (Maybe String) (Maybe c)
+readOptionalAttr = readOptionalAttrVal readMaybe
+
+readOptionalAttrBool :: (ArrowList a, ArrowChoice a) =>
+                        a (Maybe String) (Maybe Bool)
+readOptionalAttrBool = readOptionalAttrVal readBoolMaybe
+
+readAttrVal :: (ArrowChoice a, ArrowList a) => (b -> Maybe c) -> a b c
+readAttrVal reader =
+  proc x -> do
+    let mRead = reader x
+    case mRead of
+      Nothing ->  none    -< Nothing
+      Just val -> returnA -< val
+
+readAttr :: (ArrowChoice a, ArrowList a, Read b) =>
+            a String b
+readAttr = readAttrVal readMaybe
+
+readAttrBool :: (ArrowChoice a, ArrowList a) =>
+                a String Bool
+readAttrBool = readAttrVal readBoolMaybe
+
+parseOpenDataTable :: (ArrowXml a, ArrowChoice a) =>
+                  a XmlTree OpenDataTable
+parseOpenDataTable =
+  proc x -> do
+    mHttps        <- optionalAttr "https"             -< x
+    https         <- readOptionalAttr                 -< mHttps
+    xmlns         <- optionalAttr "xmlns"             -< x
+    securityLevel <- readOptionalAttr
+                     <<< optionalAttr "securityLevel" -< x
+    meta          <- parseMeta                        -< x
+    mExecute      <- optionalAttr "execute"           -< x
+    execute       <- readOptionalAttr                 -< mExecute
+    bindings      <- parseBindings                    -< x
+    returnA -< OpenDataTable
+      xmlns
+      securityLevel
+      https
+      meta
+      execute
+      bindings
+
+parseMeta :: (ArrowXml a) => a XmlTree Meta
+parseMeta =
+  proc x -> do
+    meta             <- atTag "meta"                          -< x
+    author           <- optionalTextAtTag "author"            -< meta
+    apiKeyUrl        <- optionalTextAtTag "apiKeyUrl"         -< meta
+    description      <- optionalTextAtTag "description"       -< meta
+    sampleQueries    <- getList "sampleQuery" text            -< meta
+    documentationUrl <- optionalTextAtTag "documentationURL"  -< meta
+    returnA -< Meta
+      author
+      description
+      documentationUrl
+      apiKeyUrl
+      sampleQueries
+
+parseBindings :: (ArrowXml a, ArrowChoice a) => a XmlTree [Binding]
+parseBindings =
+  proc x -> do
+    bindings <- atTag "bindings"                       -< x
+    selects  <- listA (atTag "select" >>> parseSelect) -< bindings
+    returnA -< SelectBinding `fmap` selects
+
+parseSelect :: (ArrowXml a, ArrowChoice a) => a XmlTree Select
+parseSelect =
+  proc x -> do
+    itemPath                <- optionalAttr "itemPath"                    -< x
+    produces                <- readOptionalAttr
+                               <<< optionalAttr "produces"                -< x
+    pollingFrequencySeconds <- readOptionalAttr
+                               <<< optionalAttr "pollingFrequencySeconds" -< x
+    url                     <- optionalTextAtOptionalTag "url"
+                               <<< atOptionalTag "urls"                   -< x
+    inputs                  <- parseInput                                 -< x
+    execute                 <- optionalTextAtTag "execute"                -< x
+    paging                  <- (arr Just <<< parsePaging)
+                               `orElse` (constA Nothing)                  -< x
+    returnA -< Select
+      itemPath
+      produces
+      pollingFrequencySeconds
+      url
+      inputs
+      execute
+      paging
+
+parseInput :: (ArrowXml a, ArrowChoice a) => a XmlTree [Input]
+parseInput =
+  proc x -> do
+    inputs <- atOptionalTag "inputs"               -< x
+    keys   <- getOptionalList "key" parseInputInfo -< inputs
+    returnA -< InputKey `fmap` keys
+
+parseInputInfo :: (ArrowXml a, ArrowChoice a) => a XmlTree InputInfo
+parseInputInfo =
+  proc x -> do
+    id            <- getAttrValue0 "id"                               -< x
+    as            <- optionalAttr "as"                                -< x
+    typ           <- readAttr
+                     <<< getAttrValue0 "type"                         -< x
+    paramType     <- readAttr <<< getAttrValue0 "paramType"           -< x
+    required      <- readOptionalAttrBool <<< optionalAttr "required" -< x
+    def           <- optionalAttr "default"                           -< x
+    private       <- readOptionalAttrBool
+                     <<< optionalAttr "private"                       -< x
+    const         <- readOptionalAttrBool
+                     <<< optionalAttr "const"                         -< x
+    batchable     <- readOptionalAttrBool
+                     <<< optionalAttr "batchable"                     -< x
+    maxBatchItems <- readOptionalAttr
+                     <<< optionalAttr "maxBatchItems"                 -< x
+    returnA -< InputInfo
+      id
+      as
+      typ
+      paramType
+      (fromMaybe False required)
+      def
+      private
+      const
+      batchable
+      maxBatchItems
+
+parsePaging :: (ArrowXml a, ArrowChoice a) => a XmlTree Paging
+parsePaging =
+  proc x -> do
+    paging    <- atTag "paging"                   -< x
+    mModel    <- optionalAttr "model"             -< paging
+    model     <- readOptionalAttr                 -< mModel
+    matrix    <- readOptionalAttrBool
+                 <<< optionalAttr "matrix"        -< paging
+    pageSize  <- (arr Just <<< parsePagingPageSize)
+                 `orElse` (constA Nothing)        -< paging
+    pageStart <- (arr Just <<< parsePagingStart)
+                 `orElse` (constA Nothing)        -< paging
+    pageTotal <- (arr Just <<< parsePagingTotal)
+                 `orElse` (constA Nothing)        -< paging
+    nextPage  <- (arr Just <<< parsePagingNextPage)
+                 `orElse` (constA Nothing)        -< paging
+    returnA -< Paging
+      model
+      matrix
+      pageSize
+      pageStart
+      pageTotal
+      nextPage
+
+parsePagingPageSize :: ArrowXml a => a XmlTree PagingSize
+parsePagingPageSize =
+  proc x -> do
+    pageSize <- atTag "pagesize"    -< x
+    id       <- getAttrValue0 "id"  -< pageSize
+    max      <- getAttrValue0 "max" -< pageSize
+    returnA -< PagingSize id $ read max
+
+parsePagingStart :: ArrowXml a => a XmlTree PagingStart
+parsePagingStart =
+  proc x -> do
+    pagingStart <- atTag "start"           -< x
+    id          <- getAttrValue0 "id"      -< pagingStart
+    def         <- getAttrValue0 "default" -< pagingStart
+    returnA -< PagingStart id $ read def
+
+parsePagingTotal :: ArrowXml a => a XmlTree PagingTotal
+parsePagingTotal =
+  proc x -> do
+    pagingTotal <- atTag "total"           -< x
+    def         <- getAttrValue0 "default" -< pagingTotal
+    returnA -< PagingTotal $ read def
+
+parsePagingNextPage :: ArrowXml a => a XmlTree NextPage
+parsePagingNextPage =
+  proc x -> do
+    nextPage <- atTag "nextpage"    -< x
+    path     <- getAttrValue0 "path" -< nextPage
+    returnA -< NextPage path
diff --git a/Data/OpenDataTable/Pickle.hs b/Data/OpenDataTable/Pickle.hs
new file mode 100644
--- /dev/null
+++ b/Data/OpenDataTable/Pickle.hs
@@ -0,0 +1,142 @@
+module Data.OpenDataTable.Pickle
+       () where
+
+import Text.XML.HXT.Core
+import Text.XML.HXT.Arrow.Pickle.Schema
+
+import Data.OpenDataTable
+
+instance XmlPickler OpenDataTable where
+  xpickle = xpOpenDataTable
+
+xpOpenDataTable :: PU OpenDataTable
+xpOpenDataTable
+  = xpWrap ( \ ((xmlns, securityLevel, https, meta, execute, bindings)) ->
+              OpenDataTable xmlns securityLevel https meta execute bindings
+           , \ ot -> (openDataTableXmlns ot, openDataTableSecurityLevel ot,
+                     openDataTableHttps ot, openDataTableMeta ot,
+                     openDataTableExecute ot, openDataTableBindings ot)) $
+    xpElem "table" $
+    xp6Tuple
+    (xpOption $ xpAddFixedAttr "xmlns" "http://query.yahooapis.com/v1/schema/table.xsd" xpText)
+    (xpOption $ xpAttr "securityLevel" xpPrim)
+    (xpOption $ xpAttr "https" xpPrim)
+    xpMeta
+    (xpOption (xpElem "execute" $ xpTextDT scString))
+    xpBindings
+
+instance XmlPickler Meta where
+  xpickle = xpMeta
+
+xpMeta :: PU Meta
+xpMeta
+  = xpElem "meta" $
+    xpWrap ( \ ((aut, des, doc, sam, api)) -> Meta api aut doc des sam
+           , \ m -> (metaAuthor m, metaDescription m, metaDocumentationURL m,
+                     metaSampleQuery m, metaApiKeyURL m)) $
+    xp5Tuple
+    (xpOption $ xpElem "author" xpText)
+    (xpOption $ xpElem "description" xpText)
+    (xpOption $ xpElem "documentationURL" xpText)
+    (xpList $ xpElem "sampleQuery" xpText)
+    (xpOption $ xpElem "apiKeyUrl" xpText)
+
+xpBindings :: PU [Binding]
+xpBindings = xpElem "bindings" $
+             xpList xpBinding
+
+instance XmlPickler Binding where
+  xpickle = xpBinding
+
+xpBinding :: PU Binding
+xpBinding = xpWrap ( SelectBinding, \ (SelectBinding s) -> s ) $
+            xpickle
+
+instance XmlPickler Select where
+  xpickle = xpSelect
+
+xpSelect :: PU Select
+xpSelect = xpElem "select" $
+           xpWrap ( \ ((ite, pro, pol, url, inp, exe, pag)) ->
+                     Select ite pro pol url inp exe pag,
+                    \ s -> (selectItemPath s, selectProduces s,
+                            selectPollingFrequencySeconds s,
+                            selectUrl s, selectInputs s,
+                            selectExecute s, selectPaging s) ) $
+           xp7Tuple
+           (xpOption (xpAttr "itemPath" xpText))
+           (xpOption (xpAttr "produces" xpPrim))
+           (xpOption (xpAttr "pollingFrequencySeconds" xpPrim))
+           (xpOption (xpElem "urls" $ xpElem "url" xpText))
+           (xpElem "inputs" $ xpList $ xpInput)
+           (xpOption (xpElem "execute" $ xpTextDT scString))
+           (xpElem "paging" xpickle)
+
+xpInput :: PU Input
+xpInput = xpWrap ( InputKey, \ (InputKey i) -> i ) $
+          xpElem "key" xpickle
+
+instance XmlPickler InputInfo where
+  xpickle = xpInputInfo
+
+xpInputInfo :: PU InputInfo
+xpInputInfo = xpWrap ( \ ((id, as, typ, par, req, def, pri, con, bat, max)) ->
+                        InputInfo id as typ par req def pri con bat max,
+                       \ i -> (inputInfoId i, inputInfoAs i, inputInfoType i,
+                               inputInfoParamType i, inputInfoRequired i,
+                               inputInfoDefault i, inputInfoPrivate i,
+                               inputInfoConst i, inputInfoBatchable i,
+                               inputInfoMaxBatchItems i)) $
+              xp10Tuple
+              (xpAttr "id" xpText)
+              (xpOption $ xpAttr "as" xpText)
+              (xpAttr "type" xpPrim)
+              (xpAttr "paramType" xpPrim)
+              (xpAttr "required" xpPrim)
+              (xpOption $ xpAttr "default" xpText)
+              (xpOption $ xpAttr "private" xpPrim)
+              (xpOption $ xpAttr "const" xpPrim)
+              (xpOption $ xpAttr "batchable" xpPrim)
+              (xpOption $ xpAttr "maxBatchItems" xpPrim)
+
+instance XmlPickler Paging where
+  xpickle = xpPaging
+
+xpPaging :: PU Paging
+xpPaging = xpWrap ( \ ((mod, mat, siz, sta, tot, nex)) ->
+                   Paging mod mat siz sta tot nex,
+                  \ p -> (pagingModel p, pagingMatrix p, pagingPageSize p,
+                          pagingStart p, pagingTotal p, pagingNextPage p)) $
+         xp6Tuple
+         (xpOption $ xpAttr "model" xpPrim)
+         (xpOption $ xpAttr "matrix" xpPrim)
+         (xpOption $ xpickle)
+         (xpOption $ xpickle)
+         (xpOption $ xpickle)
+         (xpOption $ xpickle)
+
+instance XmlPickler PagingSize where
+  xpickle = xpElem "pagesize" $
+            xpWrap ( \ ((id, max)) -> PagingSize id max,
+                     \ ps -> (pagingSizeId ps, pagingSizeMax ps)) $
+            xpPair
+            (xpAttr "id" xpText)
+            (xpAttr "max" xpPrim)
+
+instance XmlPickler PagingStart where
+  xpickle = xpElem "start" $
+            xpWrap ( \ ((id, def)) -> PagingStart id def,
+                     \ ps -> (pagingStartId ps, pagingStartDefault ps)) $
+            xpPair
+            (xpAttr "id" xpText)
+            (xpAttr "default" xpPrim)
+
+instance XmlPickler PagingTotal where
+  xpickle = xpElem "total" $
+            xpWrap ( PagingTotal, pagingTotalDefault) $
+            (xpAttr "default" xpPrim)
+
+instance XmlPickler NextPage where
+  xpickle = xpElem "nextpage" $
+            xpWrap ( NextPage, nextPagePath) $
+            (xpAttr "path" xpText)
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2014, Fabian Bergmark
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/opendatatable.cabal b/opendatatable.cabal
new file mode 100644
--- /dev/null
+++ b/opendatatable.cabal
@@ -0,0 +1,32 @@
+name:              opendatatable
+version:           0.0.0
+synopsis:          A library for working with Open Data Tables
+description:       Open Data Table definition, parser and pickler.
+homepage:          https://github.com/fabianbergmark/OpenDataTable
+category:          Web
+author:            Fabian Bergmark
+maintainer:        fabian.bergmark@gmail.com
+license:           BSD2
+license-file:      LICENSE
+cabal-version:     >= 1.10
+build-type:        Simple
+
+extra-source-files: LICENSE
+
+source-repository head
+  type:     git
+  location: https://github.com/fabianbergmark/OpenDataTable.git
+
+library
+    default-language: Haskell2010
+
+    exposed-modules: Data.OpenDataTable
+                     Data.OpenDataTable.Parser
+                     Data.OpenDataTable.Pickle
+
+    ghc-options: -fno-warn-orphans -fno-warn-unused-binds -fno-warn-unused-matches
+
+    build-depends: base             == 4.*
+                 , template-haskell == 2.9.*
+                 , th-lift          == 0.6.*
+                 , hxt              == 9.3.*
