diff --git a/src/Codec/Xlsx/Formatted.hs b/src/Codec/Xlsx/Formatted.hs index ef2ce049..6fb9d45c 100644 --- a/src/Codec/Xlsx/Formatted.hs +++ b/src/Codec/Xlsx/Formatted.hs @@ -57,6 +57,7 @@ import Data.Tuple (swap) import GHC.Generics (Generic) import Prelude hiding (mapM) import Safe (headNote, fromJustNote) +import Control.Monad (unless, guard, forM) import Codec.Xlsx.Types diff --git a/src/Codec/Xlsx/Parser.hs b/src/Codec/Xlsx/Parser.hs index 3b96659e..19567e9e 100644 --- a/src/Codec/Xlsx/Parser.hs +++ b/src/Codec/Xlsx/Parser.hs @@ -28,7 +28,7 @@ import Lens.Micro #else import Control.Lens hiding ((<.>), element, views) #endif -import Control.Monad (join, void) +import Control.Monad (join, void, liftM4) import Control.Monad.Except (catchError, throwError) import Data.Bool (bool) import Data.ByteString (ByteString) @@ -45,7 +45,7 @@ import qualified Data.Text as T import Data.Traversable import GHC.Generics (Generic) import Prelude hiding (sequence) -import Safe +import Safe (headNote) import System.FilePath.Posix import Text.XML as X import Text.XML.Cursor hiding (bool) @@ -112,11 +112,12 @@ toXlsxEitherBase parseSheet bs = do (wfs, names, cacheSources, dateBase) <- readWorkbook ar sheets <- forM wfs $ \wf -> do sheet <- parseSheet ar sst contentTypes cacheSources wf - return . (wfName wf,) . (wsState .~ wfState wf) $ sheet + return . (wfName wf,) . (wsSheetId .~ wfSheetId wf) . (wsState .~ wfState wf) $ sheet CustomProperties customPropMap <- getCustomProperties ar return $ Xlsx sheets (getStyles ar) names customPropMap dateBase data WorksheetFile = WorksheetFile { wfName :: Text + , wfSheetId :: Int , wfState :: SheetState , wfPath :: FilePath } @@ -206,6 +207,7 @@ extractSheetFast ar sst contentTypes caches wf = do , _wsPivotTables = [] , _wsTables = [] , _wsState = wfState wf + , _wsSheetId = wfSheetId wf , .. } , tableIds @@ -503,6 +505,7 @@ extractSheet ar sst contentTypes caches wf = do mProtection sharedFormulas (wfState wf) + (wfSheetId wf) extractCellValue :: SharedStringTable -> Text -> Cursor -> [CellValue] extractCellValue sst t cur @@ -656,7 +659,7 @@ readWorkbook ar = do sheets <- sequence $ cur $/ element (n_ "sheets") &/ element (n_ "sheet") >=> - liftA3 (worksheetFile wbPath wbRels) <$> attribute "name" <*> fromAttributeDef "state" def <*> + liftM4 (worksheetFile wbPath wbRels) <$> attribute "name" <*> fromAttribute "sheetId" <*> fromAttributeDef "state" def <*> fromAttribute (odr "id") let cacheRefs = cur $/ element (n_ "pivotCaches") &/ element (n_ "pivotCache") >=> @@ -689,9 +692,9 @@ getTable ar fp = do cur <- xmlCursorRequired ar fp headErr (InvalidFile fp "Couldn't parse drawing") (fromCursor cur) -worksheetFile :: FilePath -> Relationships -> Text -> SheetState -> RefId -> Parser WorksheetFile -worksheetFile parentPath wbRels name visibility rId = - WorksheetFile name visibility <$> lookupRelPath parentPath wbRels rId +worksheetFile :: FilePath -> Relationships -> Text -> Int -> SheetState -> RefId -> Parser WorksheetFile +worksheetFile parentPath wbRels name sheetId visibility rId = + WorksheetFile name sheetId visibility <$> lookupRelPath parentPath wbRels rId getRels :: Zip.Archive -> FilePath -> Parser Relationships getRels ar fp = do diff --git a/src/Codec/Xlsx/Parser/Stream.hs b/src/Codec/Xlsx/Parser/Stream.hs index 4ee5cc78..d25a3be6 100644 --- a/src/Codec/Xlsx/Parser/Stream.hs +++ b/src/Codec/Xlsx/Parser/Stream.hs @@ -85,6 +85,7 @@ import Lens.Micro.TH import Control.Lens #endif import Codec.Xlsx.Parser.Internal +import Control.Monad (when, void, unless) import Control.Monad.Catch import Control.Monad.Except import Control.Monad.Reader diff --git a/src/Codec/Xlsx/Types.hs b/src/Codec/Xlsx/Types.hs index 58c6dd7e..250e78f0 100644 --- a/src/Codec/Xlsx/Types.hs +++ b/src/Codec/Xlsx/Types.hs @@ -47,6 +47,7 @@ module Codec.Xlsx.Types ( , wsProtection , wsSharedFormulas , wsState + , wsSheetId -- ** Cells , Cell.cellValue , Cell.cellStyle @@ -284,6 +285,7 @@ data Worksheet = Worksheet , _wsProtection :: Maybe SheetProtection , _wsSharedFormulas :: Map SharedFormulaIndex SharedFormulaOptions , _wsState :: SheetState + , _wsSheetId :: Int } deriving (Eq, Show, Generic) instance NFData Worksheet @@ -307,6 +309,7 @@ instance Default Worksheet where , _wsProtection = Nothing , _wsSharedFormulas = M.empty , _wsState = def + , _wsSheetId = 1 } -- | Raw worksheet styles, for structured implementation see 'StyleSheet' diff --git a/src/Codec/Xlsx/Writer/Stream.hs b/src/Codec/Xlsx/Writer/Stream.hs index 0c10ea5c..11e1da9c 100644 --- a/src/Codec/Xlsx/Writer/Stream.hs +++ b/src/Codec/Xlsx/Writer/Stream.hs @@ -71,6 +71,7 @@ import Text.XML (toXMLElement) import qualified Text.XML as TXML import Text.XML.Stream.Render import Text.XML.Unresolved (elementToEvents) +import Control.Monad (void, when, unless) upsertSharedStrings :: MonadState SharedStringState m => Row -> m [(Text,Int)] @@ -264,7 +265,7 @@ writeSst sharedStrings' = doc (n_ "sst") $ ) $ sortBy (\(_, i) (_, y :: Int) -> compare i y) $ Map.toList sharedStrings' writeEvents :: PrimMonad m => ConduitT Event Builder m () -writeEvents = renderBuilder (def {rsPretty=False}) +writeEvents = renderBuilder def sheetViews :: forall m . MonadReader SheetWriteSettings m => forall i . ConduitT i Event m () sheetViews = do diff --git a/test/TestXlsx.hs b/test/TestXlsx.hs index 1ca4bb77..9fd4ce1a 100644 --- a/test/TestXlsx.hs +++ b/test/TestXlsx.hs @@ -40,12 +40,12 @@ testXlsx = Xlsx sheets minimalStyles definedNames customProperties DateBase1904 , ("with pivot table", pvSheet) , ("cellrange DV source", foreignDvSourceSheet) -- "foreign" sheet holding validation data , ("cellrange DV test", foreignDvTestSheet) -- applies validation using foreign cell ranges - , ("hidden sheet", def & wsState .~ Hidden & cellValueAt (1,1) ?~ CellText "I'm hidden!") - , ("VERY hidden sheet", def & wsState .~ VeryHidden & cellValueAt (1,1) ?~ CellText "I'm VERY hidden!!") + , ("hidden sheet", def & wsState .~ Hidden & cellValueAt (1,1) ?~ CellText "I'm hidden!" & wsSheetId .~ 6) + , ("VERY hidden sheet", def & wsState .~ VeryHidden & cellValueAt (1,1) ?~ CellText "I'm VERY hidden!!" & wsSheetId .~ 7) ] sheet1 = Worksheet cols rowProps testCellMap1 drawing ranges sheetViews pageSetup cFormatting validations [] (Just autoFilter) - tables (Just protection) sharedFormulas def + tables (Just protection) sharedFormulas def 1 sharedFormulas = M.fromList [ (SharedFormulaIndex 0, SharedFormulaOptions (CellRef "A5:C5") (Formula "A4")) @@ -71,12 +71,13 @@ testXlsx = Xlsx sheets minimalStyles definedNames customProperties DateBase1904 { _sprScenarios = False , _sprLegacyPassword = Just $ legacyPassword "hard password" } - sheet2 = def & wsCells .~ testCellMap2 - foreignDvSourceSheet = def & wsCells .~ cellRangeDvSourceMap + sheet2 = def & wsCells .~ testCellMap2 & wsSheetId .~ 2 + foreignDvSourceSheet = def & wsCells .~ cellRangeDvSourceMap & wsSheetId .~ 4 foreignDvTestSheet = def & wsDataValidations .~ foreignValidations & wsCells . at (1, 1) ?~ (def & cellValue ?~ CellText ("Hi! try " <> unCellRef testForeignDvRange)) - pvSheet = sheetWithPvCells & wsPivotTables .~ [testPivotTable] + & wsSheetId .~ 5 + pvSheet = sheetWithPvCells & wsPivotTables .~ [testPivotTable] & wsSheetId .~ 3 sheetWithPvCells = def & wsCells .~ testPivotSrcCells rowProps = M.fromList [(1, RowProps { rowHeight = Just (CustomHeight 50) , rowStyle = Just 3