xlsx-0.8.2: src/Codec/Xlsx/Types/Table.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
module Codec.Xlsx.Types.Table where
#ifdef USE_MICROLENS
import Lens.Micro.TH (makeLenses)
#else
import Control.Lens (makeLenses)
#endif
import Control.DeepSeq (NFData)
import Data.Maybe (catMaybes, maybeToList)
import Data.Text (Text)
import GHC.Generics (Generic)
import Text.XML
import Text.XML.Cursor
import Codec.Xlsx.Parser.Internal
import Codec.Xlsx.Types.AutoFilter
import Codec.Xlsx.Types.Common
import Codec.Xlsx.Writer.Internal
-- | Tables are ranges of data in the worksheet that have special
-- behavior applied which allow users to better sort, analyze, format,
-- manage, add, and delete data. Tables and table columns can also be
-- referenced through formulas by the spreadsheet application using
-- friendly names, making formula calculations that use tables much
-- easier to understand and maintain. Tables provide a natural way for
-- working with large sets of tabular data.
--
-- NOTE: as @headerRowCount@ property isn't yet supported it's
-- supposed that it's library user liability to guarantee that the 1st
-- row of 'tblRef' range contains cells with names specified in
-- `tblColumns`
--
-- Section 18.5 \"Tables\" (p. 1728)
-- Section 18.5.1 \"Tables\" (p. 1729)
-- Section 18.5.1.2 "table (Table)" (p. 1730)
data Table = Table
{ tblDisplayName :: Text
-- ^ A string representing the name of the table. This is the name
-- that shall be used in formula references, and displayed in the UI
-- to the spreadsheet user. This name shall not have any spaces in
-- it, and it shall be unique amongst all other displayNames and
-- definedNames in the workbook. The character lengths and
-- restrictions are the same as for definedNames .
, tblName :: Maybe Text
-- ^ A string representing the name of the table that is used to
-- reference the table programmatically through the spreadsheet
-- applications object model. This string shall be unique per table
-- per sheet. It has the same length and character restrictions as
-- for displayName. By default this should be the same as the
-- table's 'tblDisplayName' . This name should also be kept in synch with
-- the displayName when the displayName is updated in the UI by the
-- spreadsheet user.
, tblRef :: CellRef
-- ^ The range on the relevant sheet that the table occupies
-- expressed using A1 style referencing.
, tblColumns :: [TableColumn]
-- ^ columns of this table, specification requires any table to
-- include at least 1 column
, tblAutoFilter :: Maybe AutoFilter
} deriving (Eq, Show, Generic)
instance NFData Table
-- | Single table column
--
-- TODO: styling information
--
-- Section 18.5.1.3 "tableColumn (Table Column)" (p. 1735)
data TableColumn = TableColumn
{ tblcName :: Text
-- ^ A string representing the unique caption of the table
-- column. This is what shall be displayed in the header row in the
-- UI, and is referenced through functions. This name shall be
-- unique per table.
} deriving (Eq, Show, Generic)
instance NFData TableColumn
makeLenses ''Table
{-------------------------------------------------------------------------------
Parsing
-------------------------------------------------------------------------------}
instance FromCursor Table where
fromCursor c = do
tblDisplayName <- fromAttribute "displayName" c
tblName <- maybeAttribute "name" c
tblRef <- fromAttribute "ref" c
tblAutoFilter <- maybeFromElement (n_ "autoFilter") c
let tblColumns =
c $/ element (n_ "tableColumns") &/ element (n_ "tableColumn") >=>
fmap TableColumn . fromAttribute "name"
return Table {..}
{-------------------------------------------------------------------------------
Rendering
-------------------------------------------------------------------------------}
tableToDocument :: Table -> Int -> Document
tableToDocument tbl i =
documentFromElement "Table generated by xlsx" $
tableToElement "table" tbl i
tableToElement :: Name -> Table -> Int -> Element
tableToElement nm Table {..} i = elementList nm attrs subElements
where
attrs =
[ "id" .= i
, "displayName" .= tblDisplayName
, "ref" .= tblRef
] ++
catMaybes
[ "name" .=? tblName
]
subElements =
maybeToList (toElement "autoFilter" <$> tblAutoFilter) ++
[ countedElementList
"tableColumns"
[ leafElement "tableColumn" ["id" .= i', "name" .= tblcName c]
| (i', c) <- zip [(1 :: Int) ..] tblColumns
]
]