Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ff539de
Change type alias for CellMap
jappeace Jan 27, 2021
aadd86c
Try seeing if we can list everything in the test data
jappeace Jan 27, 2021
a3440b6
Loop trough the entire thing
jappeace Jan 28, 2021
28284ae
Split of go into seperate function
jappeace Jan 28, 2021
aa2f4a7
Don't print the bytestring
jappeace Jan 28, 2021
e3d7a41
I'm finding out it aint ordered
jappeace Jan 29, 2021
8bf96d9
Go a long way towards completion
jappeace Jan 29, 2021
35c2c9f
Use coerce for free speed
jappeace Feb 10, 2021
4a70c01
Do some rundimentary parsing
jappeace Feb 10, 2021
67ce372
Add styling the binary to see what's going on
jappeace Feb 15, 2021
60ddd8a
Filter out the formula
jappeace Feb 24, 2021
a370951
Add string table parsing, cleanup warnings
jappeace Feb 24, 2021
8690e0a
THis only get's the last string (lol)
jappeace Feb 24, 2021
3efcde5
Fix shared string bug
jappeace Mar 4, 2021
ad2ac8e
Filter empty rows
jappeace Mar 4, 2021
f546cf2
Try allow user to use sideffect to lookup string
jappeace Mar 5, 2021
f311d69
Revert "Try allow user to use sideffect to lookup string"
jappeace Mar 5, 2021
f7b049a
Make a conduit out of shared string instead of use state monad
jappeace Mar 5, 2021
209b2b2
Try fix tests after that Cellmap change
jappeace Mar 8, 2021
85bc369
Revert "Try fix tests after that Cellmap change"
jappeace Mar 8, 2021
aa6a590
Revert "Change type alias for CellMap"
jappeace Mar 8, 2021
d2b3abd
Fix the tests
jappeace Mar 8, 2021
70390dd
Remove MonadIO constraint, throw errors with monadthrow
jappeace Mar 9, 2021
e75fe0f
Remove several redundant constraints
jappeace Mar 9, 2021
f7e6041
Add haskcallstack, but it's not a good idea after reading the docs
jappeace Mar 9, 2021
a7d0d37
Revert "Add haskcallstack, but it's not a good idea after reading the…
jappeace Mar 9, 2021
f48f1ef
Add bool parse support
jappeace Mar 9, 2021
fdfa1cf
Add some docs
jappeace Mar 9, 2021
59a65f2
Show the issue with a test
jappeace Mar 9, 2021
4d72357
Fix tests for shared strings
jappeace Mar 11, 2021
a79d336
Add nix flake template
awkure Apr 19, 2021
f515585
Add stylish haskell to nix shell and fix shell
awkure Apr 21, 2021
558cd56
Update streaming parser and add docs
awkure Apr 21, 2021
93e9107
add simple xlsx data
awkure May 17, 2021
7f5c98b
Update streaming benchmark
awkure May 17, 2021
606488b
Add streaming parser tests
awkure May 17, 2021
1049345
Update stack.yaml to include nothunks
markflorisson May 17, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
TAGS
cabal-dev
dist
dist-newstyle
*sandbox*
#*#
*.*~
specs
samples
.stack-work
*.lock
*.lock

# nix
result
result-doc
31 changes: 31 additions & 0 deletions Streamin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Simple xlsx parser/writer, only basic functionality at the moment

This is a draft PR so ya'll can see what I'm doing and have an opportunity to voice concerns early.

I'm going to do reading from stream first (our company needs both reading and writing).
I'll work on writing stream support once the reading is implemented.

Okay the strat is to index by

```
SheetItem = {
cellRow
allKnownSheetStaticProps
}

XslxItem = {
sheetItem
allKnownStaticProps
}

result :: Conduit
ByteString -- Input
XslxItem -- Output
m
```

So the conduit pipes gets bytestring chuncks and produces XslxItems which contain a single excell row.
Nested within a sheet, nested within an excell item.
If we can figure out other properties before starting the stream we'll just add that information to the pipeline and copy it.

https://hackage.haskell.org/package/xml-conduit-1.9.0.0/docs/Text-XML-Stream-Parse.html
76 changes: 76 additions & 0 deletions benchmarks/Stream.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module Main (main) where

import Codec.Xlsx
import Codec.Xlsx.Parser.Stream
import Conduit
import qualified Conduit as C
import Criterion.Main
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LB
import qualified Data.Conduit.Combinators as C
import Data.Function
import qualified Data.Map as Map
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.IO as Text
import Debug.Trace
import Prelude hiding (foldl)

celVal :: CellValue -> Text
celVal = \case
CellText x -> x
CellDouble x -> Text.pack $ show x
CellBool x -> Text.pack $ show x
CellRich x -> Text.pack $ show x
CellError x -> Text.pack $ show x

format :: SheetItem -> Text
format x = Text.pack $ show (_si_sheet x, _si_row_index x, maybe "" celVal . _cellValue <$> _si_cell_row x)

parseFileStream :: FilePath -> IO ()
parseFileStream filepath = do
input <-
sourceFile filepath
& readXlsxC
& runResourceT
_ <- runResourceT $ runConduit (parseConduit input)
pure ()
where
parseConduit
:: Monad m
=> ConduitM a SheetItem m ()
-> ConduitM a Void m [SheetItem]
parseConduit input =
input
.| C.filter (("sheet1.xml" ==) . _si_sheet)
.| C.foldl (\a b -> a <> [b]) []

parseFile :: FilePath -> IO ()
parseFile filepath = do
contents <- LB.readFile filepath
let !_ = toXlsx contents
pure ()

parseFileFast :: FilePath -> IO ()
parseFileFast filepath = do
contents <- LB.readFile filepath
let !_ = toXlsxFast contents
pure ()

main :: IO ()
main = let
files =
[ "data/simple.xlsx"
, "data/testInput.xlsx"
, "data/6000.rows.x.26.cols.xlsx"
]
benchFiles parse filename = bench ("parsing " <> filename) . nfIO $ parse filename
in defaultMain
[ bgroup "stream" $ benchFiles parseFileStream <$> files
, bgroup "canonical" $ benchFiles parseFile <$> files
, bgroup "canonical fast" $ benchFiles parseFileFast <$> files
]
7 changes: 7 additions & 0 deletions cabal.project.local
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
with-compiler: ghc-8.8.4
optimization: 2
ignore-project: False
library-profiling: False
executable-profiling: False
tests: True
benchmarks: True
Binary file added data/simple.xlsx
Binary file not shown.
3 changes: 3 additions & 0 deletions default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(import (fetchTarball https://github.com/edolstra/flake-compat/archive/master.tar.gz) {
src = ./.;
}).defaultNix
61 changes: 61 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 43 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
description = "xlsx";

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs";
flake-utils.url = "github:numtide/flake-utils/5466c5bbece17adaab2d82fae80b46e807611bf3";
gitignore = {
url = "github:hercules-ci/gitignore.nix/211907489e9f198594c0eb0ca9256a1949c9d412";
flake = false;
};
};

outputs = { self, nixpkgs, flake-utils, gitignore }:
flake-utils.lib.eachDefaultSystem (system:
let
packageName = "xlsx";
compiler = "ghc884";

pkgs = nixpkgs.legacyPackages.${system};
jailbreakUnbreak = pkg:
pkgs.haskell.lib.doJailbreak (pkg.overrideAttrs (_: { meta = { }; }));

gitignore = pkgs.nix-gitignore.gitignoreSourcePure [ ./.gitignore ];

in {
packages.${packageName} =
pkgs.haskell.packages.${compiler}.callCabal2nix packageName (gitignore ./.) rec { };

defaultPackage = self.packages.${system}.${packageName};

devShell = pkgs.mkShell {
buildInputs = with pkgs; [
haskell-language-server
stylish-haskell
ghcid
zlib
cabal-install
];
inputsFrom = builtins.attrValues self.packages.${system};
# shellHook = "cabal v2-repl";
};
});
}
1 change: 1 addition & 0 deletions shell.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(import ./.).devShell."${builtins.currentSystem}"
4 changes: 2 additions & 2 deletions src/Codec/Xlsx/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ import Codec.Xlsx.Types.PivotTable.Internal
toXlsx :: L.ByteString -> Xlsx
toXlsx = either (error . show) id . toXlsxEither

data ParseError = InvalidZipArchive
data ParseError = InvalidZipArchive String
| MissingFile FilePath
| InvalidFile FilePath Text
| InvalidRef FilePath RefId
Expand Down Expand Up @@ -106,7 +106,7 @@ toXlsxEitherBase ::
-> L.ByteString
-> Parser Xlsx
toXlsxEitherBase parseSheet bs = do
ar <- left (const InvalidZipArchive) $ Zip.toArchiveOrFail bs
ar <- left InvalidZipArchive $ Zip.toArchiveOrFail bs
sst <- getSharedStrings ar
contentTypes <- getContentTypes ar
(wfs, names, cacheSources, dateBase) <- readWorkbook ar
Expand Down
Loading