xlsx-0.2.4: src/Codec/Xlsx/Types/Common.hs
{-# LANGUAGE OverloadedStrings #-}
module Codec.Xlsx.Types.Common
( CellRef
, SqRef (..)
, XlsxText (..)
, Formula (..)
) where
import qualified Data.Map as Map
import Data.Text (Text)
import qualified Data.Text as T
import Text.XML
import Text.XML.Cursor
import Codec.Xlsx.Parser.Internal
import Codec.Xlsx.Types.RichText
import Codec.Xlsx.Writer.Internal
-- | Excel cell reference (e.g. @E3@)
-- See 18.18.62 @ST_Ref@ (p. 2482)
type CellRef = Text
newtype SqRef = SqRef [CellRef]
deriving (Eq, Ord, Show)
-- | Common type containing either simple string or rich formatted text.
-- Used in @si@, @comment@ and @is@ elements
--
-- E.g. @si@ spec says: "If the string is just a simple string with formatting applied
-- at the cell level, then the String Item (si) should contain a single text
-- element used to express the string. However, if the string in the cell is
-- more complex - i.e., has formatting applied at the character level - then the
-- string item shall consist of multiple rich text runs which collectively are
-- used to express the string.". So we have either a single "Text" field, or
-- else a list of "RichTextRun"s, each of which is some "Text" with layout
-- properties.
--
-- TODO: Currently we do not support @phoneticPr@ (Phonetic Properties, 18.4.3,
-- p. 1723) or @rPh@ (Phonetic Run, 18.4.6, p. 1725).
--
-- Section 18.4.8, "si (String Item)" (p. 1725)
--
-- See @CT_Rst@, p. 3903
data XlsxText = XlsxText Text
| XlsxRichText [RichTextRun]
deriving (Show, Eq, Ord)
-- | A formula
--
-- See 18.18.35 "ST_Formula (Formula)" (p. 2457)
newtype Formula = Formula {unFormula :: Text}
deriving (Eq, Ord, Show)
{-------------------------------------------------------------------------------
Parsing
-------------------------------------------------------------------------------}
-- | See @CT_Rst@, p. 3903
instance FromCursor XlsxText where
fromCursor cur = do
let
ts = cur $/ element (n"t") >=> contentOrEmpty
contentOrEmpty c = case c $/ content of
[t] -> [t]
[] -> [""]
_ -> error "invalid item: more than one text nodes under <t>!"
rs = cur $/ element (n"r") >=> fromCursor
case (ts,rs) of
([t], []) ->
return $ XlsxText t
([], _:_) ->
return $ XlsxRichText rs
_ ->
fail "invalid item"
instance FromAttrVal SqRef where
fromAttrVal t = readSuccess (SqRef $ T.split (== ' ') t)
-- | See @ST_Formula@, p. 3873
instance FromCursor Formula where
fromCursor cur = [Formula . T.concat $ cur $/ content]
{-------------------------------------------------------------------------------
Rendering
-------------------------------------------------------------------------------}
-- | See @CT_Rst@, p. 3903
instance ToElement XlsxText where
toElement nm si = Element {
elementName = nm
, elementAttributes = Map.empty
, elementNodes = map NodeElement $
case si of
XlsxText text -> [elementContent "t" text]
XlsxRichText rich -> map (toElement "r") rich
}
-- | A sequence of cell references, space delimited.
-- See 18.18.76, "ST_Sqref (Reference Sequence)", p. 2488.
instance ToAttrVal SqRef where
toAttrVal (SqRef refs) = T.intercalate " " refs
-- | See @ST_Formula@, p. 3873
instance ToElement Formula where
toElement nm (Formula txt) = elementContent nm txt