module Codec.Xlsx.Types.Internal.SharedStringTable (
SharedStringTable(..)
, sstConstruct
, sstLookupText
, sstLookupRich
, sstItem
, sstEmpty
) where
import Control.Monad
import qualified Data.Map as Map
import Data.Maybe (mapMaybe)
import qualified Data.Set as Set
import Data.Text (Text)
import Data.Vector (Vector)
import qualified Data.Vector as V
import Numeric.Search.Range (searchFromTo)
import Safe (fromJustNote)
import Text.XML
import Text.XML.Cursor
import Codec.Xlsx.Parser.Internal
import Codec.Xlsx.Types
import Codec.Xlsx.Writer.Internal
newtype SharedStringTable = SharedStringTable {
sstTable :: Vector XlsxText
}
deriving (Show, Eq, Ord)
sstEmpty :: SharedStringTable
sstEmpty = SharedStringTable V.empty
instance ToDocument SharedStringTable where
toDocument = documentFromElement "Shared string table generated by xlsx"
. toElement "sst"
instance ToElement SharedStringTable where
toElement nm SharedStringTable{..} = Element {
elementName = nm
, elementAttributes = Map.empty
, elementNodes = map (NodeElement . toElement "si")
$ V.toList sstTable
}
instance FromCursor SharedStringTable where
fromCursor cur = do
let
items = cur $/ element (n"si") >=> fromCursor
return (SharedStringTable (V.fromList items))
sstConstruct :: [Worksheet] -> SharedStringTable
sstConstruct =
SharedStringTable . V.fromList . uniq . concatMap goSheet
where
goSheet :: Worksheet -> [XlsxText]
goSheet = mapMaybe (_cellValue >=> sstEntry) . Map.elems . _wsCells
sstEntry :: CellValue -> Maybe XlsxText
sstEntry (CellText text) = Just $ XlsxText text
sstEntry (CellRich rich) = Just $ XlsxRichText rich
sstEntry _ = Nothing
uniq :: Ord a => [a] -> [a]
uniq = Set.elems . Set.fromList
sstLookupText :: SharedStringTable -> Text -> Int
sstLookupText sst = sstLookup sst . XlsxText
sstLookupRich :: SharedStringTable -> [RichTextRun] -> Int
sstLookupRich sst = sstLookup sst . XlsxRichText
sstLookup :: SharedStringTable -> XlsxText -> Int
sstLookup SharedStringTable{sstTable = shared} si =
fromJustNote ("SST entry for " ++ show si ++ " not found") $
searchFromTo (\p -> shared V.! p >= si) 0 (V.length shared 1)
sstItem :: SharedStringTable -> Int -> XlsxText
sstItem (SharedStringTable shared) = (V.!) shared