git.iko.soy/typeable/pandoc
on master help sign in
Add Text.Pandoc.Readers.CSV (readCSV).

This adds csv as an input format. The CSV table is converted into a pandoc simple table. Closes #6100.

commitf9514ccb9e6efbd33ad84fcc1dfef20603affc4c authorJohn MacFarlane <jgm@berkeley.edu> dateFri 31 Jan 2020, 21:14 (7 years ago) parentcef30e7
6 files changed+134−2
MANUAL.txt+2 pandoc.cabal+3−2 src/Text/Pandoc/App/FormatHeuristics.hs+1 src/Text/Pandoc/Readers.hs+3 src/Text/Pandoc/Readers/CSV.hs+108 test/command/csv.md+17
MANUAL.txt+2
@@ -227,6 +227,7 @@ header when requesting a document from a URL:
227227 ::: {#input-formats}
228228 - `commonmark` ([CommonMark] Markdown)
229229 - `creole` ([Creole 1.0])
230+ - `csv` ([CSV] table)
230231 - `docbook` ([DocBook])
231232 - `docx` ([Word docx])
232233 - `dokuwiki` ([DokuWiki markup])
@@ -467,6 +468,7 @@ header when requesting a document from a URL:
467468[TikiWiki markup]: https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax
468469[Haddock markup]: https://www.haskell.org/haddock/doc/html/ch03s08.html
469470[Creole 1.0]: http://www.wikicreole.org/wiki/Creole1.0
471+[CSV]: https://tools.ietf.org/html/rfc4180
470472[roff man]: https://man.cx/groff_man(7)
471473[roff ms]: https://man.cx/groff_ms(7)
472474[Haskell]: https://www.haskell.org
pandoc.cabal+3−2
@@ -1,5 +1,5 @@
11name: pandoc
2−version: 2.9.1.1
2+version: 2.9.2
33cabal-version: 2.0
44build-type: Simple
55license: GPL-2
@@ -21,7 +21,7 @@ description: Pandoc is a Haskell library for converting from one markup
2121 TikiWiki markup, Jira markup, Creole 1.0, Haddock markup,
2222 OPML, Emacs Org-Mode, Emacs Muse, txt2tags, ipynb (Jupyter
2323 notebooks), Vimwiki, Word Docx, ODT, EPUB, FictionBook2,
24− roff man, and Textile, and it can write Markdown,
24+ roff man, Textile, and CSV, and it can write Markdown,
2525 reStructuredText, XHTML, HTML 5, LaTeX, ConTeXt, DocBook,
2626 JATS, OPML, TEI, OpenDocument, ODT, Word docx,
2727 PowerPoint pptx, RTF, MediaWiki, DokuWiki, XWiki,
@@ -503,6 +503,7 @@ library
503503 Text.Pandoc.Readers.FB2,
504504 Text.Pandoc.Readers.DokuWiki,
505505 Text.Pandoc.Readers.Ipynb,
506+ Text.Pandoc.Readers.CSV,
506507 Text.Pandoc.Writers,
507508 Text.Pandoc.Writers.Native,
508509 Text.Pandoc.Writers.Docbook,
src/Text/Pandoc/App/FormatHeuristics.hs+1
@@ -75,5 +75,6 @@ formatFromFilePath x =
7575 ".wiki" -> Just "mediawiki"
7676 ".xhtml" -> Just "html"
7777 ".ipynb" -> Just "ipynb"
78+ ".csv" -> Just "csv"
7879 ['.',y] | y `elem` ['1'..'9'] -> Just "man"
7980 _ -> Nothing
src/Text/Pandoc/Readers.hs+3
@@ -51,6 +51,7 @@ module Text.Pandoc.Readers
5151 , readMuse
5252 , readFB2
5353 , readIpynb
54+ , readCSV
5455 -- * Miscellaneous
5556 , getReader
5657 , getDefaultExtensions
@@ -95,6 +96,7 @@ import Text.Pandoc.Readers.TWiki
9596import Text.Pandoc.Readers.Txt2Tags
9697import Text.Pandoc.Readers.Vimwiki
9798import Text.Pandoc.Readers.Man
99+import Text.Pandoc.Readers.CSV
98100import qualified Text.Pandoc.UTF8 as UTF8
99101import Text.Parsec.Error
100102
@@ -136,6 +138,7 @@ readers = [ ("native" , TextReader readNative)
136138 ,("man" , TextReader readMan)
137139 ,("fb2" , TextReader readFB2)
138140 ,("ipynb" , TextReader readIpynb)
141+ ,("csv" , TextReader readCSV)
139142 ]
140143
141144-- | Retrieve reader, extensions based on formatSpec (format+extensions).
src/Text/Pandoc/Readers/CSV.hsnew file+108
@@ -0,0 +1,108 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE ScopedTypeVariables #-}
5+{-# LANGUAGE ViewPatterns #-}
6+{- |
7+ Module : Text.Pandoc.Readers.RST
8+ Copyright : Copyright (C) 2006-2019 John MacFarlane
9+ License : GNU GPL, version 2 or above
10+
11+ Maintainer : John MacFarlane <jgm@berkeley.edu>
12+ Stability : alpha
13+ Portability : portable
14+
15+Conversion from CSV to a 'Pandoc' table.
16+-}
17+module Text.Pandoc.Readers.CSV ( readCSV ) where
18+import Prelude
19+import Data.Text (Text)
20+import qualified Data.Text as T
21+import Text.Pandoc.Definition
22+import qualified Text.Pandoc.Builder as B
23+import Text.Parsec
24+import Text.Parsec.Text (Parser)
25+import Text.Pandoc.Class (PandocMonad)
26+import Text.Pandoc.Shared (crFilter)
27+import Text.Pandoc.Error
28+import Text.Pandoc.Options (ReaderOptions(..))
29+import Control.Monad.Except (throwError)
30+
31+readCSV :: PandocMonad m
32+ => ReaderOptions -- ^ Reader options
33+ -> Text -- ^ Text to parse (assuming @'\n'@ line endings)
34+ -> m Pandoc
35+readCSV opts s = do
36+ let columns = readerColumns opts
37+ case parse pCSV "input" (crFilter s) of
38+ Right (r:rs) -> return $ B.doc $ B.table capt (zip aligns widths) hdrs rows
39+ where capt = mempty
40+ numcols = length r
41+ hdrs = map (B.plain . B.text) r
42+ rows = map (map (B.plain . B.text)) rs
43+ maximum' [] = 0
44+ maximum' xs = maximum xs
45+ aligns = replicate numcols AlignDefault
46+ widths = replicate numcols 0
47+ Right [] -> return $ B.doc mempty
48+ Left e -> throwError $ PandocParsecError s e
49+
50+{- from RFC 4180
51+
52+ The ABNF grammar [2] appears as follows:
53+
54+ file = [header CRLF] record *(CRLF record) [CRLF]
55+
56+ header = name *(COMMA name)
57+
58+ record = field *(COMMA field)
59+
60+ name = field
61+
62+ field = (escaped / non-escaped)
63+
64+ escaped = DQUOTE *(TEXTDATA / COMMA / CR / LF / 2DQUOTE) DQUOTE
65+
66+ non-escaped = *TEXTDATA
67+
68+ COMMA = %x2C
69+
70+ CR = %x0D ;as per section 6.1 of RFC 2234 [2]
71+
72+ DQUOTE = %x22 ;as per section 6.1 of RFC 2234 [2]
73+
74+ LF = %x0A ;as per section 6.1 of RFC 2234 [2]
75+
76+ CRLF = CR LF ;as per section 6.1 of RFC 2234 [2]
77+
78+ TEXTDATA = %x20-21 / %x23-2B / %x2D-7E
79+-}
80+
81+pCSV :: Parser [[Text]]
82+pCSV = many pRecord
83+
84+pRecord :: Parser [Text]
85+pRecord = do
86+ x <- pField
87+ xs <- many $ pComma >> pField
88+ () <$ newline <|> eof
89+ return (x:xs)
90+
91+pField :: Parser Text
92+pField = pEscaped <|> pUnescaped
93+
94+pComma :: Parser Char
95+pComma = char ','
96+
97+pUnescaped :: Parser Text
98+pUnescaped = T.strip . T.pack <$> many1 (noneOf "\n\r\",")
99+
100+pEscaped :: Parser Text
101+pEscaped = do
102+ char '"'
103+ t <- T.pack <$> many (pDoubledQuote <|> noneOf "\"")
104+ char '"'
105+ return t
106+
107+pDoubledQuote :: Parser Char
108+pDoubledQuote = try $ char '"' >> char '"'
test/command/csv.mdnew file+17
@@ -0,0 +1,17 @@
1+```
2+% pandoc -f csv -t native
3+Fruit,Price,Quantity
4+Apple,25 cents,33
5+"""Navel"" Orange","35 cents",22
6+^D
7+[Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
8+ [[Plain [Str "Fruit"]]
9+ ,[Plain [Str "Price"]]
10+ ,[Plain [Str "Quantity"]]]
11+ [[[Plain [Str "Apple"]]
12+ ,[Plain [Str "25",Space,Str "cents"]]
13+ ,[Plain [Str "33"]]]
14+ ,[[Plain [Str "\"Navel\"",Space,Str "Orange"]]
15+ ,[Plain [Str "35",Space,Str "cents"]]
16+ ,[Plain [Str "22"]]]]]
17+```