git.iko.soy/typeable/pandoc
on master help sign in
Made a proper ODT writer.

+ Transformed the old Text.Pandoc.ODT module into a proper writer module, Text.Pandoc.Writers.ODT. + Instead of saveOpenDocumentAsODT, we now have writeODT, which takes a Pandoc document and produces a bytestring. saveOpenDocumentAsODT has been removed. + To extract the images and insert them into the ODT, we now use processPandocM on the Pandoc document rather than a custom XML parser. + Handle the case where the image is remote (or not found) by converting the Image element into an Emph with the label. + Plumbing in pandoc.hs changed slightly to accomodate this, and to allow other writers that live in the IO monad.

commitff4d94e054ae4ff0fbe80920193b99eb325fd8df authorJohn MacFarlane <jgm@berkeley.edu> dateFri 2 Jul 2010, 20:12 (16 years ago) parentee51124
5 files changed+102−117
pandoc.cabal+1−1 src/Text/Pandoc.hs+2 src/Text/Pandoc/ODT.hs−101 src/Text/Pandoc/Writers/ODT.hs+83 src/pandoc.hs+16−15
pandoc.cabal+1−1
@@ -164,7 +164,6 @@ Library
164164 Text.Pandoc.Definition,
165165 Text.Pandoc.CharacterReferences,
166166 Text.Pandoc.Shared,
167− Text.Pandoc.ODT,
168167 Text.Pandoc.Highlighting,
169168 Text.Pandoc.Readers.HTML,
170169 Text.Pandoc.Readers.LaTeX,
@@ -183,6 +182,7 @@ Library
183182 Text.Pandoc.Writers.MediaWiki,
184183 Text.Pandoc.Writers.RTF,
185184 Text.Pandoc.Writers.S5,
185+ Text.Pandoc.Writers.ODT,
186186 Text.Pandoc.Templates
187187 Other-Modules: Text.Pandoc.XML,
188188 Text.Pandoc.UTF8,
src/Text/Pandoc.hs+2
@@ -86,6 +86,7 @@ module Text.Pandoc
8686 , writeMan
8787 , writeMediaWiki
8888 , writeRTF
89+ , writeODT
8990 , prettyPandoc
9091 -- * Writer options used in writers
9192 , WriterOptions (..)
@@ -109,6 +110,7 @@ import Text.Pandoc.Writers.ConTeXt
109110import Text.Pandoc.Writers.Texinfo
110111import Text.Pandoc.Writers.HTML
111112import Text.Pandoc.Writers.S5
113+import Text.Pandoc.Writers.ODT
112114import Text.Pandoc.Writers.Docbook
113115import Text.Pandoc.Writers.OpenDocument
114116import Text.Pandoc.Writers.Man
src/Text/Pandoc/ODT.hsdeleted−101
@@ -1,101 +0,0 @@
1−{-
2−Copyright (C) 2008-2010 John MacFarlane <jgm@berkeley.edu>
3−
4−This program is free software; you can redistribute it and/or modify
5−it under the terms of the GNU General Public License as published by
6−the Free Software Foundation; either version 2 of the License, or
7−(at your option) any later version.
8−
9−This program is distributed in the hope that it will be useful,
10−but WITHOUT ANY WARRANTY; without even the implied warranty of
11−MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12−GNU General Public License for more details.
13−
14−You should have received a copy of the GNU General Public License
15−along with this program; if not, write to the Free Software
16−Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17−-}
18−
19−{- |
20− Module : Text.Pandoc.ODT
21− Copyright : Copyright (C) 2008-2010 John MacFarlane
22− License : GNU GPL, version 2 or above
23−
24− Maintainer : John MacFarlane <jgm@berkeley.edu>
25− Stability : alpha
26− Portability : portable
27−
28−Functions for producing an ODT file from OpenDocument XML.
29−-}
30−module Text.Pandoc.ODT ( saveOpenDocumentAsODT ) where
31−import Data.List ( find )
32−import System.FilePath ( (</>), takeFileName )
33−import qualified Data.ByteString.Lazy as B
34−import Data.ByteString.Lazy.UTF8 ( fromString )
35−import Codec.Archive.Zip
36−import Control.Applicative ( (<$>) )
37−import Text.ParserCombinators.Parsec
38−import System.Time
39−import Paths_pandoc ( getDataFileName )
40−import System.Directory
41−import Control.Monad (liftM)
42−
43−-- | Produce an ODT file from OpenDocument XML.
44−saveOpenDocumentAsODT :: Maybe FilePath -- ^ Path of user data directory
45− -> FilePath -- ^ Pathname of ODT file to be produced
46− -> FilePath -- ^ Relative directory of source file
47− -> Maybe FilePath -- ^ Path specified by --reference-odt
48− -> String -- ^ OpenDocument XML contents
49− -> IO ()
50−saveOpenDocumentAsODT datadir destinationODTPath sourceDirRelative mbRefOdt xml = do
51− refArchive <- liftM toArchive $
52− case mbRefOdt of
53− Just f -> B.readFile f
54− Nothing -> do
55− let defaultODT = getDataFileName "reference.odt" >>= B.readFile
56− case datadir of
57− Nothing -> defaultODT
58− Just d -> do
59− exists <- doesFileExist (d </> "reference.odt")
60− if exists
61− then B.readFile (d </> "reference.odt")
62− else defaultODT
63− -- handle pictures
64− let (newContents, pics) =
65− case runParser pPictures [] "OpenDocument XML contents" xml of
66− Left err -> error $ show err
67− Right x -> x
68− picEntries <- mapM (makePictureEntry sourceDirRelative) pics
69− (TOD epochTime _) <- getClockTime
70− let contentEntry = toEntry "content.xml" epochTime $ fromString newContents
71− let archive = foldr addEntryToArchive refArchive (contentEntry : picEntries)
72− B.writeFile destinationODTPath $ fromArchive archive
73−
74−makePictureEntry :: FilePath -- ^ Relative directory of source file
75− -> (FilePath, String) -- ^ Path and new path of picture
76− -> IO Entry
77−makePictureEntry sourceDirRelative (path, newPath) = do
78− entry <- readEntry [] $ sourceDirRelative </> path
79− return (entry { eRelativePath = newPath })
80−
81−pPictures :: GenParser Char [(FilePath, String)] ([Char], [(FilePath, String)])
82−pPictures = do
83− contents <- concat <$> many (pPicture <|> many1 (noneOf "<") <|> string "<")
84− pics <- getState
85− return (contents, pics)
86−
87−pPicture :: GenParser Char [(FilePath, String)] [Char]
88−pPicture = try $ do
89− string "<draw:image xlink:href=\""
90− path <- manyTill anyChar (char '"')
91− let filename = takeFileName path
92− pics <- getState
93− newPath <- case find (\(o, _) -> o == path) pics of
94− Just (_, new) -> return new
95− Nothing -> do
96− -- get a unique name
97− let dups = length $ (filter (\(o, _) -> takeFileName o == filename)) pics
98− let new = "Pictures/" ++ replicate dups '0' ++ filename
99− updateState ((path, new) :)
100− return new
101− return $ "<draw:image xlink:href=\"" ++ newPath ++ "\""
src/Text/Pandoc/Writers/ODT.hsnew file+83
@@ -0,0 +1,83 @@
1+{-
2+Copyright (C) 2008-2010 John MacFarlane <jgm@berkeley.edu>
3+
4+This program is free software; you can redistribute it and/or modify
5+it under the terms of the GNU General Public License as published by
6+the Free Software Foundation; either version 2 of the License, or
7+(at your option) any later version.
8+
9+This program is distributed in the hope that it will be useful,
10+but WITHOUT ANY WARRANTY; without even the implied warranty of
11+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+GNU General Public License for more details.
13+
14+You should have received a copy of the GNU General Public License
15+along with this program; if not, write to the Free Software
16+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17+-}
18+
19+{- |
20+ Module : Text.Pandoc.Writers.ODT
21+ Copyright : Copyright (C) 2008-2010 John MacFarlane
22+ License : GNU GPL, version 2 or above
23+
24+ Maintainer : John MacFarlane <jgm@berkeley.edu>
25+ Stability : alpha
26+ Portability : portable
27+
28+Conversion of 'Pandoc' documents to ODT.
29+-}
30+module Text.Pandoc.Writers.ODT ( writeODT ) where
31+import Data.IORef
32+import System.FilePath ( (</>), takeExtension )
33+import qualified Data.ByteString.Lazy as B
34+import Data.ByteString.Lazy.UTF8 ( fromString )
35+import Codec.Archive.Zip
36+import System.Time
37+import Paths_pandoc ( getDataFileName )
38+import Text.Pandoc.Shared ( WriterOptions )
39+import Text.Pandoc.Definition
40+import Text.Pandoc.Writers.OpenDocument ( writeOpenDocument )
41+import System.Directory
42+import Control.Monad (liftM)
43+
44+-- | Produce an ODT file from a Pandoc document.
45+writeODT :: Maybe FilePath -- ^ Path of user data directory
46+ -> FilePath -- ^ Relative directory of source file
47+ -> Maybe FilePath -- ^ Path specified by --reference-odt
48+ -> WriterOptions -- ^ Writer options
49+ -> Pandoc -- ^ Document to convert
50+ -> IO B.ByteString
51+writeODT datadir sourceDirRelative mbRefOdt opts doc = do
52+ refArchive <- liftM toArchive $
53+ case mbRefOdt of
54+ Just f -> B.readFile f
55+ Nothing -> do
56+ let defaultODT = getDataFileName "reference.odt" >>= B.readFile
57+ case datadir of
58+ Nothing -> defaultODT
59+ Just d -> do
60+ exists <- doesFileExist (d </> "reference.odt")
61+ if exists
62+ then B.readFile (d </> "reference.odt")
63+ else defaultODT
64+ -- handle pictures
65+ picEntriesRef <- newIORef ([] :: [Entry])
66+ doc' <- processWithM (transformPic sourceDirRelative picEntriesRef) doc
67+ let newContents = writeOpenDocument opts doc'
68+ (TOD epochtime _) <- getClockTime
69+ let contentEntry = toEntry "content.xml" epochtime $ fromString newContents
70+ picEntries <- readIORef picEntriesRef
71+ let archive = foldr addEntryToArchive refArchive (contentEntry : picEntries)
72+ return $ fromArchive archive
73+
74+transformPic :: FilePath -> IORef [Entry] -> Inline -> IO Inline
75+transformPic sourceDirRelative entriesRef (Image lab (src,tit)) = do
76+ entries <- readIORef entriesRef
77+ let newsrc = "Pictures/" ++ show (length entries) ++ takeExtension src
78+ catch (readEntry [] (sourceDirRelative </> src) >>= \entry ->
79+ modifyIORef entriesRef (entry{ eRelativePath = newsrc } :) >>
80+ return (Image lab (newsrc, tit)))
81+ (\_ -> return (Emph lab))
82+transformPic _ _ x = return x
83+
src/pandoc.hs+16−15
@@ -30,7 +30,6 @@ writers.
3030-}
3131module Main where
3232import Text.Pandoc
33−import Text.Pandoc.ODT
3433import Text.Pandoc.Writers.S5 (s5HeaderIncludes)
3534import Text.Pandoc.Shared ( tabFilter, ObfuscationMethod (..), readDataFile )
3635#ifdef _HIGHLIGHTING
@@ -53,7 +52,8 @@ import Text.Pandoc.Biblio
5352import Control.Monad (when, unless, liftM)
5453import Network.HTTP (simpleHTTP, mkRequest, getResponseBody, RequestMethod(..))
5554import Network.URI (parseURI, isURI)
56−import Data.ByteString.Lazy.UTF8 (toString)
55+import qualified Data.ByteString.Lazy as B
56+import Data.ByteString.Lazy.UTF8 (toString, fromString)
5757import Codec.Binary.UTF8.String (decodeString)
5858
5959copyrightMessage :: String
@@ -108,7 +108,7 @@ writers = [("native" , writeDoc)
108108 ,("s5" , writeS5String)
109109 ,("docbook" , writeDocbook)
110110 ,("opendocument" , writeOpenDocument)
111− ,("odt" , writeOpenDocument)
111+ ,("odt" , \_ _ -> "")
112112 ,("latex" , writeLaTeX)
113113 ,("latex+lhs" , writeLaTeX)
114114 ,("context" , writeConTeXt)
@@ -658,6 +658,10 @@ main = do
658658 Nothing -> return ()
659659
660660 let sources = if ignoreArgs then [] else args
661+
662+ let sourceDirRelative = if null sources
663+ then ""
664+ else takeDirectory (head sources)
661665
662666 datadir <- case mbDataDir of
663667 Nothing -> catch
@@ -682,8 +686,11 @@ main = do
682686 Nothing -> error ("Unknown reader: " ++ readerName')
683687
684688 writer <- case (lookup writerName' writers) of
685− Just r -> return r
686− Nothing -> error ("Unknown writer: " ++ writerName')
689+ Just _ | writerName' == "odt" -> return
690+ (writeODT datadir sourceDirRelative referenceODT)
691+ Just r -> return $ \o d ->
692+ return $ fromString (r o d)
693+ Nothing -> error ("Unknown writer: " ++ writerName')
687694
688695 templ <- getDefaultTemplate datadir writerName'
689696 let defaultTemplate = case templ of
@@ -762,10 +769,6 @@ main = do
762769 "Specify an output file using the -o option.")
763770 exitWith $ ExitFailure 5
764771
765− let sourceDirRelative = if null sources
766− then ""
767− else takeDirectory (head sources)
768−
769772 let readSources [] = mapM readSource ["-"]
770773 readSources srcs = mapM readSource srcs
771774 readSource "-" = UTF8.getContents
@@ -788,10 +791,8 @@ main = do
788791 return doc'
789792#endif
790793
791− let writerOutput = writer writerOptions doc'' ++ "\n"
794+ writerOutput <- writer writerOptions doc''
792795
793− case writerName' of
794− "odt" -> saveOpenDocumentAsODT datadir outputFile sourceDirRelative referenceODT writerOutput
795− _ -> if outputFile == "-"
796− then UTF8.putStr writerOutput
797− else UTF8.writeFile outputFile writerOutput
796+ if outputFile == "-"
797+ then B.putStrLn writerOutput
798+ else B.writeFile outputFile writerOutput