{-# LANGUAGE OverloadedStrings #-} module Codec.Xlsx.Types.Common ( CellRef , SqRef (..) , XlsxText (..) ) 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) {------------------------------------------------------------------------------- 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 {------------------------------------------------------------------------------- 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 !" 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)