git.iko.soy/typeable/pandoc
on master help sign in
Add new unexported module T.P.XMLParser.
8ca1916John MacFarlane
MANUAL.txt+1
@@ -1464,6 +1464,7 @@ Nonzero exit codes have the following meanings:
1464 24 PandocCiteprocError
1464 24 PandocCiteprocError
1465 31 PandocEpubSubdirectoryError
1465 31 PandocEpubSubdirectoryError
1466 43 PandocPDFError
1466 43 PandocPDFError
1467+ 44 PandocXMLError
1467 47 PandocPDFProgramNotFoundError
1468 47 PandocPDFProgramNotFoundError
1468 61 PandocHttpError
1469 61 PandocHttpError
1469 62 PandocShouldNeverHappenError
1470 62 PandocShouldNeverHappenError
pandoc.cabal+2
@@ -493,6 +493,7 @@ library
493 unicode-transforms >= 0.3 && < 0.4,
493 unicode-transforms >= 0.3 && < 0.4,
494 unordered-containers >= 0.2 && < 0.3,
494 unordered-containers >= 0.2 && < 0.3,
495 xml >= 1.3.12 && < 1.4,
495 xml >= 1.3.12 && < 1.4,
496+ xml-conduit >= 1.7 && < 1.10,
496 zip-archive >= 0.2.3.4 && < 0.5,
497 zip-archive >= 0.2.3.4 && < 0.5,
497 zlib >= 0.5 && < 0.7
498 zlib >= 0.5 && < 0.7
498 if os(windows) && arch(i386)
499 if os(windows) && arch(i386)
@@ -686,6 +687,7 @@ library
686 Text.Pandoc.Lua.PandocLua,
687 Text.Pandoc.Lua.PandocLua,
687 Text.Pandoc.Lua.Util,
688 Text.Pandoc.Lua.Util,
688 Text.Pandoc.Lua.Walk,
689 Text.Pandoc.Lua.Walk,
690+ Text.Pandoc.XMLParser,
689 Text.Pandoc.CSS,
691 Text.Pandoc.CSS,
690 Text.Pandoc.CSV,
692 Text.Pandoc.CSV,
691 Text.Pandoc.RoffChar,
693 Text.Pandoc.RoffChar,
src/Text/Pandoc/Error.hs+3
@@ -48,6 +48,7 @@ data PandocError = PandocIOError Text IOError
48 | PandocFailOnWarningError
48 | PandocFailOnWarningError
49 | PandocPDFProgramNotFoundError Text
49 | PandocPDFProgramNotFoundError Text
50 | PandocPDFError Text
50 | PandocPDFError Text
51+ | PandocXMLError Text Text
51 | PandocFilterError Text Text
52 | PandocFilterError Text Text
52 | PandocLuaError Text
53 | PandocLuaError Text
53 | PandocCouldNotFindDataFileError Text
54 | PandocCouldNotFindDataFileError Text
@@ -103,6 +104,8 @@ handleError (Left e) =
103 PandocPDFProgramNotFoundError pdfprog -> err 47 $
104 PandocPDFProgramNotFoundError pdfprog -> err 47 $
104 pdfprog <> " not found. Please select a different --pdf-engine or install " <> pdfprog
105 pdfprog <> " not found. Please select a different --pdf-engine or install " <> pdfprog
105 PandocPDFError logmsg -> err 43 $ "Error producing PDF.\n" <> logmsg
106 PandocPDFError logmsg -> err 43 $ "Error producing PDF.\n" <> logmsg
107+ PandocXMLError fp logmsg -> err 44 $ "Invalid XML" <>
108+ (if T.null fp then "" else " in " <> fp) <> ":\n" <> logmsg
106 PandocFilterError filtername msg -> err 83 $ "Error running filter " <>
109 PandocFilterError filtername msg -> err 83 $ "Error running filter " <>
107 filtername <> ":\n" <> msg
110 filtername <> ":\n" <> msg
108 PandocLuaError msg -> err 84 $ "Error running Lua:\n" <> msg
111 PandocLuaError msg -> err 84 $ "Error running Lua:\n" <> msg
src/Text/Pandoc/ImageSize.hs+4−1
@@ -45,7 +45,9 @@ import Text.Pandoc.Definition
45import Text.Pandoc.Options
45import Text.Pandoc.Options
46import qualified Text.Pandoc.UTF8 as UTF8
46import qualified Text.Pandoc.UTF8 as UTF8
47import qualified Text.XML.Light as Xml
47import qualified Text.XML.Light as Xml
48+import Text.Pandoc.XMLParser (parseXMLElement)
48import qualified Data.Text as T
49import qualified Data.Text as T
50+import qualified Data.Text.Lazy as TL
49import qualified Data.Text.Encoding as TE
51import qualified Data.Text.Encoding as TE
50import Control.Applicative
52import Control.Applicative
51import qualified Data.Attoparsec.ByteString.Char8 as A
53import qualified Data.Attoparsec.ByteString.Char8 as A
@@ -327,7 +329,8 @@ getSize img =
327
329
328svgSize :: WriterOptions -> ByteString -> Maybe ImageSize
330svgSize :: WriterOptions -> ByteString -> Maybe ImageSize
329svgSize opts img = do
331svgSize opts img = do
330− doc <- Xml.parseXMLDoc $ UTF8.toString img
332+ doc <- either (const mzero) return $ parseXMLElement
333+ $ TL.fromStrict $ UTF8.toText img
331 let viewboxSize = do
334 let viewboxSize = do
332 vb <- Xml.findAttrBy (== Xml.QName "viewBox" Nothing Nothing) doc
335 vb <- Xml.findAttrBy (== Xml.QName "viewBox" Nothing Nothing) doc
333 [_,_,w,h] <- mapM safeRead (T.words (T.pack vb))
336 [_,_,w,h] <- mapM safeRead (T.words (T.pack vb))
src/Text/Pandoc/Readers/DocBook.hs+33−19
@@ -12,7 +12,7 @@ Conversion of DocBook XML to 'Pandoc' document.
12-}
12-}
13module Text.Pandoc.Readers.DocBook ( readDocBook ) where
13module Text.Pandoc.Readers.DocBook ( readDocBook ) where
14import Control.Monad.State.Strict
14import Control.Monad.State.Strict
15−import Data.Char (isSpace, toUpper)
15+import Data.Char (isSpace, toUpper, isLetter)
16import Data.Default
16import Data.Default
17import Data.Either (rights)
17import Data.Either (rights)
18import Data.Foldable (asum)
18import Data.Foldable (asum)
@@ -21,7 +21,10 @@ import Data.List (intersperse,elemIndex)
21import Data.Maybe (fromMaybe,mapMaybe)
21import Data.Maybe (fromMaybe,mapMaybe)
22import Data.Text (Text)
22import Data.Text (Text)
23import qualified Data.Text as T
23import qualified Data.Text as T
24+import qualified Data.Text.Lazy as TL
25+import Control.Monad.Except (throwError)
24import Text.HTML.TagSoup.Entity (lookupEntity)
26import Text.HTML.TagSoup.Entity (lookupEntity)
27+import Text.Pandoc.Error (PandocError(..))
25import Text.Pandoc.Builder
28import Text.Pandoc.Builder
26import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
29import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
27import Text.Pandoc.Options
30import Text.Pandoc.Options
@@ -29,6 +32,7 @@ import Text.Pandoc.Logging (LogMessage(..))
29import Text.Pandoc.Shared (crFilter, safeRead, extractSpaces)
32import Text.Pandoc.Shared (crFilter, safeRead, extractSpaces)
30import Text.TeXMath (readMathML, writeTeX)
33import Text.TeXMath (readMathML, writeTeX)
31import Text.XML.Light
34import Text.XML.Light
35+import Text.Pandoc.XMLParser (parseXMLContents)
32
36
33{-
37{-
34
38
@@ -537,22 +541,25 @@ instance Default DBState where
537
541
538readDocBook :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
542readDocBook :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
539readDocBook _ inp = do
543readDocBook _ inp = do
544+ tree <- either (throwError . PandocXMLError "") (return . normalizeTree) $
540− let tree = normalizeTree . parseXML . handleInstructions $ crFilter inp
545+ parseXMLContents (TL.fromStrict . handleInstructions $ crFilter inp)
541 (bs, st') <- flip runStateT (def{ dbContent = tree }) $ mapM parseBlock tree
546 (bs, st') <- flip runStateT (def{ dbContent = tree }) $ mapM parseBlock tree
542 return $ Pandoc (dbMeta st') (toList . mconcat $ bs)
547 return $ Pandoc (dbMeta st') (toList . mconcat $ bs)
543
548
544−-- We treat <?asciidoc-br?> specially (issue #1236), converting it
549+-- We treat certain processing instructions by converting them to tags
545−-- to <br/>, since xml-light doesn't parse the instruction correctly.
550+-- beginning "pi-".
546−-- Other xml instructions are simply removed from the input stream.
547handleInstructions :: Text -> Text
551handleInstructions :: Text -> Text
548−handleInstructions = T.pack . handleInstructions' . T.unpack
552+handleInstructions t =
549−
553+ let (x,y) = T.breakOn "<?" t
550−handleInstructions' :: String -> String
554+ in if T.null y
551−handleInstructions' ('<':'?':'a':'s':'c':'i':'i':'d':'o':'c':'-':'b':'r':'?':'>':xs) = '<':'b':'r':'/':'>': handleInstructions' xs
555+ then x
552−handleInstructions' xs = case break (=='<') xs of
556+ else
553− (ys, []) -> ys
557+ let (w,z) = T.breakOn "?>" y
554− ([], '<':zs) -> '<' : handleInstructions' zs
558+ in (if T.takeWhile (\c -> isLetter c || c == '-')
559+ (T.drop 2 w) `elem` ["asciidoc-br", "dbfo"]
560+ then x <> "<pi-" <> T.drop 2 w <> "/>"
561+ else x <> w <> T.take 2 z) <>
555− (ys, zs) -> ys ++ handleInstructions' zs
562+ handleInstructions (T.drop 2 z)
556
563
557getFigure :: PandocMonad m => Element -> DB m Blocks
564getFigure :: PandocMonad m => Element -> DB m Blocks
558getFigure e = do
565getFigure e = do
@@ -892,7 +899,11 @@ parseBlock (Elem e) =
892 "subtitle" -> return mempty -- handled in parent element
899 "subtitle" -> return mempty -- handled in parent element
893 _ -> skip >> getBlocks e
900 _ -> skip >> getBlocks e
894 where skip = do
901 where skip = do
895− lift $ report $ IgnoredElement $ T.pack $ qName (elName e)
902+ let qn = T.pack $ qName $ elName e
903+ let name = if "pi-" `T.isPrefixOf` qn
904+ then "<?" <> qn <> "?>"
905+ else qn
906+ lift $ report $ IgnoredElement name
896 return mempty
907 return mempty
897
908
898 codeBlockWithLang = do
909 codeBlockWithLang = do
@@ -964,7 +975,7 @@ parseBlock (Elem e) =
964 cs -> map toAlignment cs
975 cs -> map toAlignment cs
965 let parseWidth s = safeRead (T.filter (\x -> (x >= '0' && x <= '9')
976 let parseWidth s = safeRead (T.filter (\x -> (x >= '0' && x <= '9')
966 || x == '.') s)
977 || x == '.') s)
967− let textWidth = case filterChild (named "?dbfo") e of
978+ let textWidth = case filterChild (named "pi-dbfo") e of
968 Just d -> case attrValue "table-width" d of
979 Just d -> case attrValue "table-width" d of
969 "" -> 1.0
980 "" -> 1.0
970 w -> fromMaybe 100.0 (parseWidth w) / 100.0
981 w -> fromMaybe 100.0 (parseWidth w) / 100.0
@@ -1165,12 +1176,15 @@ parseInline (Elem e) =
1165 "title" -> return mempty
1176 "title" -> return mempty
1166 "affiliation" -> skip
1177 "affiliation" -> skip
1167 -- Note: this isn't a real docbook tag; it's what we convert
1178 -- Note: this isn't a real docbook tag; it's what we convert
1168− -- <?asciidor-br?> to in handleInstructions, above. A kludge to
1179+ -- <?asciidor-br?> to in handleInstructions, above.
1169− -- work around xml-light's inability to parse an instruction.
1170− "br" -> return linebreak
1180+ "pi-asciidoc-br" -> return linebreak
1171 _ -> skip >> innerInlines id
1181 _ -> skip >> innerInlines id
1172 where skip = do
1182 where skip = do
1173− lift $ report $ IgnoredElement $ T.pack $ qName (elName e)
1183+ let qn = T.pack $ qName $ elName e
1184+ let name = if "pi-" `T.isPrefixOf` qn
1185+ then "<?" <> qn <> "?>"
1186+ else qn
1187+ lift $ report $ IgnoredElement name
1174 return mempty
1188 return mempty
1175
1189
1176 innerInlines f = extractSpaces f . mconcat <$>
1190 innerInlines f = extractSpaces f . mconcat <$>
src/Text/Pandoc/Readers/Docx/Parse.hs+14−7
@@ -74,6 +74,7 @@ import Text.TeXMath.Readers.OMML (readOMML)
74import Text.TeXMath.Unicode.Fonts (Font (..), getUnicode, textToFont)
74import Text.TeXMath.Unicode.Fonts (Font (..), getUnicode, textToFont)
75import Text.XML.Light
75import Text.XML.Light
76import qualified Text.XML.Light.Cursor as XMLC
76import qualified Text.XML.Light.Cursor as XMLC
77+import Text.Pandoc.XMLParser (parseXMLElement)
77
78
78data ReaderEnv = ReaderEnv { envNotes :: Notes
79data ReaderEnv = ReaderEnv { envNotes :: Notes
79 , envComments :: Comments
80 , envComments :: Comments
@@ -343,10 +344,16 @@ archiveToDocxWithWarnings archive = do
343 Right doc -> Right (Docx doc, stateWarnings st)
344 Right doc -> Right (Docx doc, stateWarnings st)
344 Left e -> Left e
345 Left e -> Left e
345
346
347+parseXMLFromEntry :: Entry -> Maybe Element
348+parseXMLFromEntry entry =
349+ case parseXMLElement (UTF8.toTextLazy (fromEntry entry)) of
350+ Left _ -> Nothing
351+ Right el -> Just el
352+
346getDocumentXmlPath :: Archive -> Maybe FilePath
353getDocumentXmlPath :: Archive -> Maybe FilePath
347getDocumentXmlPath zf = do
354getDocumentXmlPath zf = do
348 entry <- findEntryByPath "_rels/.rels" zf
355 entry <- findEntryByPath "_rels/.rels" zf
349− relsElem <- (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
356+ relsElem <- parseXMLFromEntry entry
350 let rels = filterChildrenName (\n -> qName n == "Relationship") relsElem
357 let rels = filterChildrenName (\n -> qName n == "Relationship") relsElem
351 rel <- find (\e -> findAttr (QName "Type" Nothing Nothing) e ==
358 rel <- find (\e -> findAttr (QName "Type" Nothing Nothing) e ==
352 Just "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument")
359 Just "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument")
@@ -362,7 +369,7 @@ archiveToDocument :: Archive -> D Document
362archiveToDocument zf = do
369archiveToDocument zf = do
363 docPath <- asks envDocXmlPath
370 docPath <- asks envDocXmlPath
364 entry <- maybeToD $ findEntryByPath docPath zf
371 entry <- maybeToD $ findEntryByPath docPath zf
365− docElem <- maybeToD $ (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
372+ docElem <- maybeToD $ parseXMLFromEntry entry
366 let namespaces = elemToNameSpaces docElem
373 let namespaces = elemToNameSpaces docElem
367 bodyElem <- maybeToD $ findChildByName namespaces "w" "body" docElem
374 bodyElem <- maybeToD $ findChildByName namespaces "w" "body" docElem
368 let bodyElem' = fromMaybe bodyElem (walkDocument namespaces bodyElem)
375 let bodyElem' = fromMaybe bodyElem (walkDocument namespaces bodyElem)
@@ -401,9 +408,9 @@ constructBogusParStyleData stName = ParStyle
401archiveToNotes :: Archive -> Notes
408archiveToNotes :: Archive -> Notes
402archiveToNotes zf =
409archiveToNotes zf =
403 let fnElem = findEntryByPath "word/footnotes.xml" zf
410 let fnElem = findEntryByPath "word/footnotes.xml" zf
404− >>= (parseXMLDoc . UTF8.toStringLazy . fromEntry)
411+ >>= parseXMLFromEntry
405 enElem = findEntryByPath "word/endnotes.xml" zf
412 enElem = findEntryByPath "word/endnotes.xml" zf
406− >>= (parseXMLDoc . UTF8.toStringLazy . fromEntry)
413+ >>= parseXMLFromEntry
407 fn_namespaces = maybe [] elemToNameSpaces fnElem
414 fn_namespaces = maybe [] elemToNameSpaces fnElem
408 en_namespaces = maybe [] elemToNameSpaces enElem
415 en_namespaces = maybe [] elemToNameSpaces enElem
409 ns = unionBy (\x y -> fst x == fst y) fn_namespaces en_namespaces
416 ns = unionBy (\x y -> fst x == fst y) fn_namespaces en_namespaces
@@ -415,7 +422,7 @@ archiveToNotes zf =
415archiveToComments :: Archive -> Comments
422archiveToComments :: Archive -> Comments
416archiveToComments zf =
423archiveToComments zf =
417 let cmtsElem = findEntryByPath "word/comments.xml" zf
424 let cmtsElem = findEntryByPath "word/comments.xml" zf
418− >>= (parseXMLDoc . UTF8.toStringLazy . fromEntry)
425+ >>= parseXMLFromEntry
419 cmts_namespaces = maybe [] elemToNameSpaces cmtsElem
426 cmts_namespaces = maybe [] elemToNameSpaces cmtsElem
420 cmts = elemToComments cmts_namespaces <$> (cmtsElem >>= walkDocument cmts_namespaces)
427 cmts = elemToComments cmts_namespaces <$> (cmtsElem >>= walkDocument cmts_namespaces)
421 in
428 in
@@ -445,7 +452,7 @@ filePathToRelationships :: Archive -> FilePath -> FilePath -> [Relationship]
445filePathToRelationships ar docXmlPath fp
452filePathToRelationships ar docXmlPath fp
446 | Just relType <- filePathToRelType fp docXmlPath
453 | Just relType <- filePathToRelType fp docXmlPath
447 , Just entry <- findEntryByPath fp ar
454 , Just entry <- findEntryByPath fp ar
448− , Just relElems <- (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry =
455+ , Just relElems <- parseXMLFromEntry entry =
449 mapMaybe (relElemToRelationship relType) $ elChildren relElems
456 mapMaybe (relElemToRelationship relType) $ elChildren relElems
450filePathToRelationships _ _ _ = []
457filePathToRelationships _ _ _ = []
451
458
@@ -527,7 +534,7 @@ archiveToNumbering' zf =
527 case findEntryByPath "word/numbering.xml" zf of
534 case findEntryByPath "word/numbering.xml" zf of
528 Nothing -> Just $ Numbering [] [] []
535 Nothing -> Just $ Numbering [] [] []
529 Just entry -> do
536 Just entry -> do
530− numberingElem <- (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
537+ numberingElem <- parseXMLFromEntry entry
531 let namespaces = elemToNameSpaces numberingElem
538 let namespaces = elemToNameSpaces numberingElem
532 numElems = findChildrenByName namespaces "w" "num" numberingElem
539 numElems = findChildrenByName namespaces "w" "num" numberingElem
533 absNumElems = findChildrenByName namespaces "w" "abstractNum" numberingElem
540 absNumElems = findChildrenByName namespaces "w" "abstractNum" numberingElem
src/Text/Pandoc/Readers/Docx/Parse/Styles.hs+16−12
@@ -53,6 +53,7 @@ import Data.Coerce
53import Text.Pandoc.Readers.Docx.Util
53import Text.Pandoc.Readers.Docx.Util
54import qualified Text.Pandoc.UTF8 as UTF8
54import qualified Text.Pandoc.UTF8 as UTF8
55import Text.XML.Light
55import Text.XML.Light
56+import Text.Pandoc.XMLParser (parseXMLElement)
56
57
57newtype CharStyleId = CharStyleId T.Text
58newtype CharStyleId = CharStyleId T.Text
58 deriving (Show, Eq, Ord, IsString, FromStyleId)
59 deriving (Show, Eq, Ord, IsString, FromStyleId)
@@ -135,19 +136,22 @@ defaultRunStyle = RunStyle { isBold = Nothing
135 , rParentStyle = Nothing
136 , rParentStyle = Nothing
136 }
137 }
137
138
139+archiveToStyles'
138−archiveToStyles' :: (Ord k1, Ord k2, ElemToStyle a1, ElemToStyle a2) =>
140+ :: (Ord k1, Ord k2, ElemToStyle a1, ElemToStyle a2)
139− (a1 -> k1) -> (a2 -> k2) -> Archive -> (M.Map k1 a1, M.Map k2 a2)
141+ => (a1 -> k1) -> (a2 -> k2) -> Archive -> (M.Map k1 a1, M.Map k2 a2)
140archiveToStyles' conv1 conv2 zf =
142archiveToStyles' conv1 conv2 zf =
141− let stylesElem = findEntryByPath "word/styles.xml" zf >>=
143+ case findEntryByPath "word/styles.xml" zf of
142− (parseXMLDoc . UTF8.toStringLazy . fromEntry)
144+ Nothing -> (M.empty, M.empty)
143− in
145+ Just entry ->
144− case stylesElem of
146+ case parseXMLElement . UTF8.toTextLazy . fromEntry $ entry of
145− Nothing -> (M.empty, M.empty)
147+ Left _ -> (M.empty, M.empty)
146− Just styElem ->
148+ Right styElem ->
147− let namespaces = elemToNameSpaces styElem
149+ let namespaces = elemToNameSpaces styElem
148− in
150+ in
151+ ( M.fromList $ map (\r -> (conv1 r, r)) $
149− ( M.fromList $ map (\r -> (conv1 r, r)) $ buildBasedOnList namespaces styElem Nothing,
152+ buildBasedOnList namespaces styElem Nothing,
153+ M.fromList $ map (\p -> (conv2 p, p)) $
150− M.fromList $ map (\p -> (conv2 p, p)) $ buildBasedOnList namespaces styElem Nothing)
154+ buildBasedOnList namespaces styElem Nothing)
151
155
152isBasedOnStyle :: (ElemToStyle a, FromStyleId (StyleId a)) => NameSpaces -> Element -> Maybe a -> Bool
156isBasedOnStyle :: (ElemToStyle a, FromStyleId (StyleId a)) => NameSpaces -> Element -> Maybe a -> Bool
153isBasedOnStyle ns element parentStyle
157isBasedOnStyle ns element parentStyle
src/Text/Pandoc/Readers/EPUB.hs+11−6
@@ -17,7 +17,7 @@ module Text.Pandoc.Readers.EPUB
17 (readEPUB)
17 (readEPUB)
18 where
18 where
19
19
20−import Codec.Archive.Zip (Archive (..), Entry, findEntryByPath, fromEntry,
20+import Codec.Archive.Zip (Archive (..), Entry(..), findEntryByPath, fromEntry,
21 toArchiveOrFail)
21 toArchiveOrFail)
22import Control.DeepSeq (NFData, deepseq)
22import Control.DeepSeq (NFData, deepseq)
23import Control.Monad (guard, liftM, liftM2, mplus)
23import Control.Monad (guard, liftM, liftM2, mplus)
@@ -41,9 +41,10 @@ import Text.Pandoc.MIME (MimeType)
41import Text.Pandoc.Options (ReaderOptions (..))
41import Text.Pandoc.Options (ReaderOptions (..))
42import Text.Pandoc.Readers.HTML (readHtml)
42import Text.Pandoc.Readers.HTML (readHtml)
43import Text.Pandoc.Shared (addMetaField, collapseFilePath, escapeURI)
43import Text.Pandoc.Shared (addMetaField, collapseFilePath, escapeURI)
44−import qualified Text.Pandoc.UTF8 as UTF8 (toStringLazy)
44+import qualified Text.Pandoc.UTF8 as UTF8 (toTextLazy)
45import Text.Pandoc.Walk (query, walk)
45import Text.Pandoc.Walk (query, walk)
46import Text.XML.Light
46import Text.XML.Light
47+import Text.Pandoc.XMLParser (parseXMLElement)
47
48
48type Items = M.Map String (FilePath, MimeType)
49type Items = M.Map String (FilePath, MimeType)
49
50
@@ -181,7 +182,7 @@ renameMeta s = T.pack s
181getManifest :: PandocMonad m => Archive -> m (String, Element)
182getManifest :: PandocMonad m => Archive -> m (String, Element)
182getManifest archive = do
183getManifest archive = do
183 metaEntry <- findEntryByPathE ("META-INF" </> "container.xml") archive
184 metaEntry <- findEntryByPathE ("META-INF" </> "container.xml") archive
184− docElem <- (parseXMLDocE . UTF8.toStringLazy . fromEntry) metaEntry
185+ docElem <- parseXMLDocE metaEntry
185 let namespaces = mapMaybe attrToNSPair (elAttribs docElem)
186 let namespaces = mapMaybe attrToNSPair (elAttribs docElem)
186 ns <- mkE "xmlns not in namespaces" (lookup "xmlns" namespaces)
187 ns <- mkE "xmlns not in namespaces" (lookup "xmlns" namespaces)
187 as <- fmap (map attrToPair . elAttribs)
188 as <- fmap (map attrToPair . elAttribs)
@@ -190,7 +191,7 @@ getManifest archive = do
190 let rootdir = dropFileName manifestFile
191 let rootdir = dropFileName manifestFile
191 --mime <- lookup "media-type" as
192 --mime <- lookup "media-type" as
192 manifest <- findEntryByPathE manifestFile archive
193 manifest <- findEntryByPathE manifestFile archive
193− (rootdir,) <$> (parseXMLDocE . UTF8.toStringLazy . fromEntry $ manifest)
194+ (rootdir,) <$> parseXMLDocE manifest
194
195
195-- Fixup
196-- Fixup
196
197
@@ -284,8 +285,12 @@ findEntryByPathE :: PandocMonad m => FilePath -> Archive -> m Entry
284findEntryByPathE (normalise . unEscapeString -> path) a =
285findEntryByPathE (normalise . unEscapeString -> path) a =
285 mkE ("No entry on path: " ++ path) $ findEntryByPath path a
286 mkE ("No entry on path: " ++ path) $ findEntryByPath path a
286
287
287−parseXMLDocE :: PandocMonad m => String -> m Element
288+parseXMLDocE :: PandocMonad m => Entry -> m Element
288−parseXMLDocE doc = mkE "Unable to parse XML doc" $ parseXMLDoc doc
289+parseXMLDocE entry =
290+ either (throwError . PandocXMLError fp) return $ parseXMLElement doc
291+ where
292+ doc = UTF8.toTextLazy . fromEntry $ entry
293+ fp = T.pack $ eRelativePath entry
289
294
290findElementE :: PandocMonad m => QName -> Element -> m Element
295findElementE :: PandocMonad m => QName -> Element -> m Element
291findElementE e x = mkE ("Unable to find element: " ++ show e) $ findElement e x
296findElementE e x = mkE ("Unable to find element: " ++ show e) $ findElement e x
src/Text/Pandoc/Readers/FB2.hs+6−4
@@ -32,6 +32,7 @@ import Data.List (intersperse)
32import qualified Data.Map as M
32import qualified Data.Map as M
33import Data.Text (Text)
33import Data.Text (Text)
34import qualified Data.Text as T
34import qualified Data.Text as T
35+import qualified Data.Text.Lazy as TL
35import Data.Default
36import Data.Default
36import Data.Maybe
37import Data.Maybe
37import Text.HTML.TagSoup.Entity (lookupEntity)
38import Text.HTML.TagSoup.Entity (lookupEntity)
@@ -42,6 +43,7 @@ import Text.Pandoc.Logging
42import Text.Pandoc.Options
43import Text.Pandoc.Options
43import Text.Pandoc.Shared (crFilter)
44import Text.Pandoc.Shared (crFilter)
44import Text.XML.Light
45import Text.XML.Light
46+import Text.Pandoc.XMLParser (parseXMLElement)
45
47
46type FB2 m = StateT FB2State m
48type FB2 m = StateT FB2State m
47
49
@@ -64,10 +66,10 @@ instance HasMeta FB2State where
64
66
65readFB2 :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
67readFB2 :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
66readFB2 _ inp =
68readFB2 _ inp =
67− case parseXMLDoc $ crFilter inp of
69+ case parseXMLElement $ TL.fromStrict $ crFilter inp of
68− Nothing -> throwError $ PandocParseError "Not an XML document"
70+ Left msg -> throwError $ PandocXMLError "" msg
69− Just e -> do
71+ Right el -> do
70− (bs, st) <- runStateT (parseRootElement e) def
72+ (bs, st) <- runStateT (parseRootElement el) def
71 let authors = if null $ fb2Authors st
73 let authors = if null $ fb2Authors st
72 then id
74 then id
73 else setMeta "author" (map text $ reverse $ fb2Authors st)
75 else setMeta "author" (map text $ reverse $ fb2Authors st)
src/Text/Pandoc/Readers/JATS.hs+7−2
@@ -14,6 +14,8 @@ Conversion of JATS XML to 'Pandoc' document.
14
14
15module Text.Pandoc.Readers.JATS ( readJATS ) where
15module Text.Pandoc.Readers.JATS ( readJATS ) where
16import Control.Monad.State.Strict
16import Control.Monad.State.Strict
17+import Control.Monad.Except (throwError)
18+import Text.Pandoc.Error (PandocError(..))
17import Data.Char (isDigit, isSpace, toUpper)
19import Data.Char (isDigit, isSpace, toUpper)
18import Data.Default
20import Data.Default
19import Data.Generics
21import Data.Generics
@@ -22,6 +24,7 @@ import qualified Data.Map as Map
22import Data.Maybe (maybeToList, fromMaybe)
24import Data.Maybe (maybeToList, fromMaybe)
23import Data.Text (Text)
25import Data.Text (Text)
24import qualified Data.Text as T
26import qualified Data.Text as T
27+import qualified Data.Text.Lazy as TL
25import Text.HTML.TagSoup.Entity (lookupEntity)
28import Text.HTML.TagSoup.Entity (lookupEntity)
26import Text.Pandoc.Builder
29import Text.Pandoc.Builder
27import Text.Pandoc.Class.PandocMonad (PandocMonad)
30import Text.Pandoc.Class.PandocMonad (PandocMonad)
@@ -29,6 +32,7 @@ import Text.Pandoc.Options
29import Text.Pandoc.Shared (crFilter, safeRead, extractSpaces)
32import Text.Pandoc.Shared (crFilter, safeRead, extractSpaces)
30import Text.TeXMath (readMathML, writeTeX)
33import Text.TeXMath (readMathML, writeTeX)
31import Text.XML.Light
34import Text.XML.Light
35+import Text.Pandoc.XMLParser (parseXMLContents)
32import qualified Data.Set as S (fromList, member)
36import qualified Data.Set as S (fromList, member)
33import Data.Set ((\\))
37import Data.Set ((\\))
34
38
@@ -51,8 +55,9 @@ instance Default JATSState where
51
55
52readJATS :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
56readJATS :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
53readJATS _ inp = do
57readJATS _ inp = do
58+ tree <- either (throwError . PandocXMLError "")
54− let tree = normalizeTree . parseXML
59+ (return . normalizeTree) $
55− $ T.unpack $ crFilter inp
60+ parseXMLContents (TL.fromStrict $ crFilter inp)
56 (bs, st') <- flip runStateT (def{ jatsContent = tree }) $ mapM parseBlock tree
61 (bs, st') <- flip runStateT (def{ jatsContent = tree }) $ mapM parseBlock tree
57 return $ Pandoc (jatsMeta st') (toList . mconcat $ bs)
62 return $ Pandoc (jatsMeta st') (toList . mconcat $ bs)
58
63
src/Text/Pandoc/Readers/OPML.hs+8−2
@@ -19,14 +19,18 @@ import Data.Generics
19import Data.Maybe (fromMaybe)
19import Data.Maybe (fromMaybe)
20import Data.Text (Text)
20import Data.Text (Text)
21import qualified Data.Text as T
21import qualified Data.Text as T
22+import qualified Data.Text.Lazy as TL
22import Text.HTML.TagSoup.Entity (lookupEntity)
23import Text.HTML.TagSoup.Entity (lookupEntity)
23import Text.Pandoc.Builder
24import Text.Pandoc.Builder
24import Text.Pandoc.Class.PandocMonad (PandocMonad)
25import Text.Pandoc.Class.PandocMonad (PandocMonad)
25import Text.Pandoc.Options
26import Text.Pandoc.Options
27+import Text.Pandoc.Error (PandocError(..))
26import Text.Pandoc.Readers.HTML (readHtml)
28import Text.Pandoc.Readers.HTML (readHtml)
27import Text.Pandoc.Readers.Markdown (readMarkdown)
29import Text.Pandoc.Readers.Markdown (readMarkdown)
28import Text.Pandoc.Shared (crFilter, blocksToInlines')
30import Text.Pandoc.Shared (crFilter, blocksToInlines')
29import Text.XML.Light
31import Text.XML.Light
32+import Text.Pandoc.XMLParser (parseXMLContents)
33+import Control.Monad.Except (throwError)
30
34
31type OPML m = StateT OPMLState m
35type OPML m = StateT OPMLState m
32
36
@@ -49,8 +53,10 @@ instance Default OPMLState where
49readOPML :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
53readOPML :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
50readOPML opts inp = do
54readOPML opts inp = do
51 (bs, st') <- runStateT
55 (bs, st') <- runStateT
52− (mapM parseBlock $ normalizeTree $
56+ (case parseXMLContents (TL.fromStrict (crFilter inp)) of
57+ Left msg -> throwError $ PandocXMLError "" msg
58+ Right ns -> mapM parseBlock $ normalizeTree ns)
53− parseXML (T.unpack (crFilter inp))) def{ opmlOptions = opts }
59+ def{ opmlOptions = opts }
54 return $
60 return $
55 setTitle (opmlDocTitle st') $
61 setTitle (opmlDocTitle st') $
56 setAuthors (opmlDocAuthors st') $
62 setAuthors (opmlDocAuthors st') $
src/Text/Pandoc/Readers/Odt.hs+14−10
@@ -15,6 +15,7 @@ module Text.Pandoc.Readers.Odt ( readOdt ) where
15
15
16import Codec.Archive.Zip
16import Codec.Archive.Zip
17import qualified Text.XML.Light as XML
17import qualified Text.XML.Light as XML
18+import Text.Pandoc.XMLParser (parseXMLElement)
18
19
19import qualified Data.ByteString.Lazy as B
20import qualified Data.ByteString.Lazy as B
20
21
@@ -66,18 +67,18 @@ bytesToOdt bytes = case toArchiveOrFail bytes of
66
67
67--
68--
68archiveToOdt :: Archive -> Either PandocError (Pandoc, MediaBag)
69archiveToOdt :: Archive -> Either PandocError (Pandoc, MediaBag)
69−archiveToOdt archive = either (Left. PandocParseError) Right $ do
70+archiveToOdt archive = do
70− let onFailure msg Nothing = Left msg
71+ let onFailure msg Nothing = Left $ PandocParseError msg
71 onFailure _ (Just x) = Right x
72 onFailure _ (Just x) = Right x
72 contentEntry <- onFailure "Could not find content.xml"
73 contentEntry <- onFailure "Could not find content.xml"
73 (findEntryByPath "content.xml" archive)
74 (findEntryByPath "content.xml" archive)
74 stylesEntry <- onFailure "Could not find styles.xml"
75 stylesEntry <- onFailure "Could not find styles.xml"
75 (findEntryByPath "styles.xml" archive)
76 (findEntryByPath "styles.xml" archive)
76− contentElem <- onFailure "Could not find content element"
77− (entryToXmlElem contentEntry)
77+ contentElem <- entryToXmlElem contentEntry
78− stylesElem <- onFailure "Could not find styles element"
79− (entryToXmlElem stylesEntry)
78+ stylesElem <- entryToXmlElem stylesEntry
79+ styles <- either
80− styles <- either (\_ -> Left "Could not read styles") Right
80+ (\_ -> Left $ PandocParseError "Could not read styles")
81+ Right
81 (chooseMax (readStylesAt stylesElem ) (readStylesAt contentElem))
82 (chooseMax (readStylesAt stylesElem ) (readStylesAt contentElem))
82 let filePathIsOdtMedia :: FilePath -> Bool
83 let filePathIsOdtMedia :: FilePath -> Bool
83 filePathIsOdtMedia fp =
84 filePathIsOdtMedia fp =
@@ -85,10 +86,13 @@ archiveToOdt archive = either (Left. PandocParseError) Right $ do
85 in (dir == "Pictures/") || (dir /= "./" && name == "content.xml")
86 in (dir == "Pictures/") || (dir /= "./" && name == "content.xml")
86 let media = filteredFilesFromArchive archive filePathIsOdtMedia
87 let media = filteredFilesFromArchive archive filePathIsOdtMedia
87 let startState = readerState styles media
88 let startState = readerState styles media
88− either (\_ -> Left "Could not convert opendocument") Right
89+ either (\_ -> Left $ PandocParseError "Could not convert opendocument") Right
89 (runConverter' read_body startState contentElem)
90 (runConverter' read_body startState contentElem)
90
91
91
92
92--
93--
93−entryToXmlElem :: Entry -> Maybe XML.Element
94+entryToXmlElem :: Entry -> Either PandocError XML.Element
94−entryToXmlElem = XML.parseXMLDoc . UTF8.toStringLazy . fromEntry
95+entryToXmlElem entry =
96+ case parseXMLElement . UTF8.toTextLazy . fromEntry $ entry of
97+ Right x -> Right x
98+ Left msg -> Left $ PandocXMLError (T.pack $ eRelativePath entry) msg
src/Text/Pandoc/Writers/EPUB.hs+10−3
@@ -55,8 +55,9 @@ import Text.Pandoc.Walk (query, walk, walkM)
55import Text.Pandoc.Writers.HTML (writeHtmlStringForEPUB)
55import Text.Pandoc.Writers.HTML (writeHtmlStringForEPUB)
56import Text.Printf (printf)
56import Text.Printf (printf)
57import Text.XML.Light (Attr (..), Element (..), Node (..), QName (..),
57import Text.XML.Light (Attr (..), Element (..), Node (..), QName (..),
58− add_attrs, lookupAttr, node, onlyElems, parseXML,
58+ add_attrs, lookupAttr, node, onlyElems,
59 ppElement, showElement, strContent, unode, unqual)
59 ppElement, showElement, strContent, unode, unqual)
60+import Text.Pandoc.XMLParser (parseXMLContents)
60import Text.Pandoc.XML (escapeStringForXML)
61import Text.Pandoc.XML (escapeStringForXML)
61import Text.DocTemplates (FromContext(lookupContext), Context(..),
62import Text.DocTemplates (FromContext(lookupContext), Context(..),
62 ToContext(toVal), Val(..))
63 ToContext(toVal), Val(..))
@@ -160,7 +161,12 @@ mkEntry path content = do
160getEPUBMetadata :: PandocMonad m => WriterOptions -> Meta -> E m EPUBMetadata
161getEPUBMetadata :: PandocMonad m => WriterOptions -> Meta -> E m EPUBMetadata
161getEPUBMetadata opts meta = do
162getEPUBMetadata opts meta = do
162 let md = metadataFromMeta opts meta
163 let md = metadataFromMeta opts meta
163− let elts = maybe [] (onlyElems . parseXML) $ writerEpubMetadata opts
164+ elts <- case writerEpubMetadata opts of
165+ Nothing -> return []
166+ Just t -> case parseXMLContents (TL.fromStrict t) of
167+ Left msg -> throwError $
168+ PandocXMLError "epub metadata" msg
169+ Right ns -> return (onlyElems ns)
164 let md' = foldr addMetadataFromXML md elts
170 let md' = foldr addMetadataFromXML md elts
165 let addIdentifier m =
171 let addIdentifier m =
166 if null (epubIdentifier m)
172 if null (epubIdentifier m)
@@ -836,7 +842,8 @@ pandocToEPUB version opts doc = do
836 : case subs of
842 : case subs of
837 [] -> []
843 [] -> []
838 (_:_) -> [unode "ol" ! [("class","toc")] $ subs]
844 (_:_) -> [unode "ol" ! [("class","toc")] $ subs]
839− where titElements = parseXML titRendered
845+ where titElements = either (const []) id $
846+ parseXMLContents (TL.fromStrict titRendered)
840 titRendered = case P.runPure
847 titRendered = case P.runPure
841 (writeHtmlStringForEPUB version
848 (writeHtmlStringForEPUB version
842 opts{ writerTemplate = Nothing
849 opts{ writerTemplate = Nothing
src/Text/Pandoc/Writers/FB2.hs+8−3
@@ -19,7 +19,7 @@ FictionBook is an XML-based e-book format. For more information see:
19module Text.Pandoc.Writers.FB2 (writeFB2) where
19module Text.Pandoc.Writers.FB2 (writeFB2) where
20
20
21import Control.Monad (zipWithM)
21import Control.Monad (zipWithM)
22−import Control.Monad.Except (catchError)
22+import Control.Monad.Except (catchError, throwError)
23import Control.Monad.State.Strict (StateT, evalStateT, get, gets, lift, liftM, modify)
23import Control.Monad.State.Strict (StateT, evalStateT, get, gets, lift, liftM, modify)
24import Data.ByteString.Base64 (encode)
24import Data.ByteString.Base64 (encode)
25import Data.Char (isAscii, isControl, isSpace)
25import Data.Char (isAscii, isControl, isSpace)
@@ -27,16 +27,18 @@ import Data.Either (lefts, rights)
27import Data.List (intercalate)
27import Data.List (intercalate)
28import Data.Text (Text, pack)
28import Data.Text (Text, pack)
29import qualified Data.Text as T
29import qualified Data.Text as T
30+import qualified Data.Text.Lazy as TL
30import qualified Data.Text.Encoding as TE
31import qualified Data.Text.Encoding as TE
31import Network.HTTP (urlEncode)
32import Network.HTTP (urlEncode)
32import Text.XML.Light
33import Text.XML.Light
33import qualified Text.XML.Light as X
34import qualified Text.XML.Light as X
34import qualified Text.XML.Light.Cursor as XC
35import qualified Text.XML.Light.Cursor as XC
35−import qualified Text.XML.Light.Input as XI
36+import Text.Pandoc.XMLParser (parseXMLContents)
36
37
37import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
38import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
38import qualified Text.Pandoc.Class.PandocMonad as P
39import qualified Text.Pandoc.Class.PandocMonad as P
39import Text.Pandoc.Definition
40import Text.Pandoc.Definition
41+import Text.Pandoc.Error (PandocError(..))
40import Text.Pandoc.Logging
42import Text.Pandoc.Logging
41import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..), def)
43import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..), def)
42import Text.Pandoc.Shared (capitalize, isURI, orderedListMarkers,
44import Text.Pandoc.Shared (capitalize, isURI, orderedListMarkers,
@@ -307,7 +309,10 @@ blockToXml (CodeBlock _ s) = return . spaceBeforeAfter .
307 map (el "p" . el "code" . T.unpack) . T.lines $ s
309 map (el "p" . el "code" . T.unpack) . T.lines $ s
308blockToXml (RawBlock f str) =
310blockToXml (RawBlock f str) =
309 if f == Format "fb2"
311 if f == Format "fb2"
310− then return $ XI.parseXML str
312+ then
313+ case parseXMLContents (TL.fromStrict str) of
314+ Left msg -> throwError $ PandocXMLError "" msg
315+ Right nds -> return nds
311 else return []
316 else return []
312blockToXml (Div _ bs) = cMapM blockToXml bs
317blockToXml (Div _ bs) = cMapM blockToXml bs
313blockToXml (BlockQuote bs) = list . el "cite" <$> cMapM blockToXml bs
318blockToXml (BlockQuote bs) = list . el "cite" <$> cMapM blockToXml bs
src/Text/Pandoc/Writers/ODT.hs+16−13
@@ -13,7 +13,7 @@ Conversion of 'Pandoc' documents to ODT.
13-}
13-}
14module Text.Pandoc.Writers.ODT ( writeODT ) where
14module Text.Pandoc.Writers.ODT ( writeODT ) where
15import Codec.Archive.Zip
15import Codec.Archive.Zip
16−import Control.Monad.Except (catchError)
16+import Control.Monad.Except (catchError, throwError)
17import Control.Monad.State.Strict
17import Control.Monad.State.Strict
18import qualified Data.ByteString.Lazy as B
18import qualified Data.ByteString.Lazy as B
19import Data.Generics (everywhere', mkT)
19import Data.Generics (everywhere', mkT)
@@ -27,6 +27,7 @@ import Text.Pandoc.BCP47 (Lang (..), getLang, renderLang)
27import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang)
27import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang)
28import qualified Text.Pandoc.Class.PandocMonad as P
28import qualified Text.Pandoc.Class.PandocMonad as P
29import Text.Pandoc.Definition
29import Text.Pandoc.Definition
30+import Text.Pandoc.Error (PandocError(..))
30import Text.Pandoc.ImageSize
31import Text.Pandoc.ImageSize
31import Text.Pandoc.Logging
32import Text.Pandoc.Logging
32import Text.Pandoc.MIME (extensionFromMimeType, getMimeType)
33import Text.Pandoc.MIME (extensionFromMimeType, getMimeType)
@@ -35,10 +36,11 @@ import Text.DocLayout
35import Text.Pandoc.Shared (stringify, pandocVersion, tshow)
36import Text.Pandoc.Shared (stringify, pandocVersion, tshow)
36import Text.Pandoc.Writers.Shared (lookupMetaString, lookupMetaBlocks,
37import Text.Pandoc.Writers.Shared (lookupMetaString, lookupMetaBlocks,
37 fixDisplayMath)
38 fixDisplayMath)
38−import Text.Pandoc.UTF8 (fromStringLazy, fromTextLazy, toStringLazy)
39+import Text.Pandoc.UTF8 (fromStringLazy, fromTextLazy, toTextLazy)
39import Text.Pandoc.Walk
40import Text.Pandoc.Walk
40import Text.Pandoc.Writers.OpenDocument (writeOpenDocument)
41import Text.Pandoc.Writers.OpenDocument (writeOpenDocument)
41import Text.Pandoc.XML
42import Text.Pandoc.XML
43+import Text.Pandoc.XMLParser (parseXMLElement)
42import Text.TeXMath
44import Text.TeXMath
43import Text.XML.Light
45import Text.XML.Light
44
46
@@ -172,17 +174,18 @@ updateStyleWithLang :: PandocMonad m => Maybe Lang -> Archive -> O m Archive
172updateStyleWithLang Nothing arch = return arch
174updateStyleWithLang Nothing arch = return arch
173updateStyleWithLang (Just lang) arch = do
175updateStyleWithLang (Just lang) arch = do
174 epochtime <- floor `fmap` lift P.getPOSIXTime
176 epochtime <- floor `fmap` lift P.getPOSIXTime
175− return arch{ zEntries = [if eRelativePath e == "styles.xml"
177+ entries <- mapM (\e -> if eRelativePath e == "styles.xml"
176− then case parseXMLDoc
178+ then case parseXMLElement
177− (toStringLazy (fromEntry e)) of
179+ (toTextLazy (fromEntry e)) of
178− Nothing -> e
180+ Left msg -> throwError $
179− Just d ->
181+ PandocXMLError "styles.xml" msg
182+ Right d -> return $
180− toEntry "styles.xml" epochtime
183+ toEntry "styles.xml" epochtime
181− ( fromStringLazy
184+ ( fromStringLazy
182− . ppTopElement
185+ . ppTopElement
183− . addLang lang $ d )
186+ . addLang lang $ d )
184− else e
185− | e <- zEntries arch] }
187+ else return e) (zEntries arch)
188+ return arch{ zEntries = entries }
186
189
187addLang :: Lang -> Element -> Element
190addLang :: Lang -> Element -> Element
188addLang lang = everywhere' (mkT updateLangAttr)
191addLang lang = everywhere' (mkT updateLangAttr)
src/Text/Pandoc/Writers/OOXML.hs+5−4
@@ -35,6 +35,7 @@ import qualified Data.Text as T
35import Text.Pandoc.Class.PandocMonad (PandocMonad)
35import Text.Pandoc.Class.PandocMonad (PandocMonad)
36import qualified Text.Pandoc.UTF8 as UTF8
36import qualified Text.Pandoc.UTF8 as UTF8
37import Text.XML.Light as XML
37import Text.XML.Light as XML
38+import Text.Pandoc.XMLParser (parseXMLElement)
38
39
39mknode :: Node t => String -> [(String,String)] -> t -> Element
40mknode :: Node t => String -> [(String,String)] -> t -> Element
40mknode s attrs =
41mknode s attrs =
@@ -62,10 +63,10 @@ parseXml refArchive distArchive relpath =
62 findEntryByPath relpath distArchive of
63 findEntryByPath relpath distArchive of
63 Nothing -> throwError $ PandocSomeError $
64 Nothing -> throwError $ PandocSomeError $
64 T.pack relpath <> " missing in reference file"
65 T.pack relpath <> " missing in reference file"
65− Just e -> case parseXMLDoc . UTF8.toStringLazy . fromEntry $ e of
66+ Just e -> case parseXMLElement . UTF8.toTextLazy . fromEntry $ e of
66− Nothing -> throwError $ PandocSomeError $
67+ Left msg ->
67− T.pack relpath <> " corrupt in reference file"
68+ throwError $ PandocXMLError (T.pack relpath) msg
68− Just d -> return d
69+ Right d -> return d
69
70
70-- Copied from Util
71-- Copied from Util
71
72
src/Text/Pandoc/Writers/Powerpoint/Output.hs+3−1
@@ -29,6 +29,7 @@ import Data.Time.Clock (UTCTime)
29import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds, posixSecondsToUTCTime)
29import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds, posixSecondsToUTCTime)
30import System.FilePath.Posix (splitDirectories, splitExtension, takeExtension)
30import System.FilePath.Posix (splitDirectories, splitExtension, takeExtension)
31import Text.XML.Light
31import Text.XML.Light
32+import Text.Pandoc.XMLParser (parseXMLElement)
32import Text.Pandoc.Definition
33import Text.Pandoc.Definition
33import qualified Text.Pandoc.UTF8 as UTF8
34import qualified Text.Pandoc.UTF8 as UTF8
34import Text.Pandoc.Class.PandocMonad (PandocMonad)
35import Text.Pandoc.Class.PandocMonad (PandocMonad)
@@ -77,7 +78,8 @@ getPresentationSize :: Archive -> Archive -> Maybe (Integer, Integer)
77getPresentationSize refArchive distArchive = do
78getPresentationSize refArchive distArchive = do
78 entry <- findEntryByPath "ppt/presentation.xml" refArchive `mplus`
79 entry <- findEntryByPath "ppt/presentation.xml" refArchive `mplus`
79 findEntryByPath "ppt/presentation.xml" distArchive
80 findEntryByPath "ppt/presentation.xml" distArchive
80− presElement <- parseXMLDoc $ UTF8.toStringLazy $ fromEntry entry
81+ presElement <- either (const Nothing) return $
82+ parseXMLElement $ UTF8.toTextLazy $ fromEntry entry
81 let ns = elemToNameSpaces presElement
83 let ns = elemToNameSpaces presElement
82 sldSize <- findChild (elemName ns "p" "sldSz") presElement
84 sldSize <- findChild (elemName ns "p" "sldSz") presElement
83 cxS <- findAttr (QName "cx" Nothing Nothing) sldSize
85 cxS <- findAttr (QName "cx" Nothing Nothing) sldSize
src/Text/Pandoc/XMLParser.hsnew file+66
@@ -0,0 +1,66 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{- |
3+ Module : Text.Pandoc.XMLParser
4+ Copyright : Copyright (C) 2021 John MacFarlane
5+ License : GNU GPL, version 2 or above
6+
7+ Maintainer : John MacFarlane <jgm@berkeley.edu>
8+ Stability : alpha
9+ Portability : portable
10+
11+Bridge to allow using xml-conduit's parser with xml-light's types.
12+-}
13+module Text.Pandoc.XMLParser
14+ ( parseXMLElement
15+ , parseXMLContents
16+ , module Text.XML.Light.Types
17+ ) where
18+
19+import qualified Control.Exception as E
20+import qualified Text.XML as Conduit
21+import Text.XML.Unresolved (InvalidEventStream(..))
22+import qualified Text.XML.Light as Light
23+import Text.XML.Light.Types
24+import qualified Data.Text as T
25+import qualified Data.Text.Lazy as TL
26+import qualified Data.Map as M
27+import Data.Maybe (mapMaybe)
28+
29+-- Drop in replacement for parseXMLDoc in xml-light.
30+parseXMLElement :: TL.Text -> Either T.Text Light.Element
31+parseXMLElement t =
32+ elementToElement . Conduit.documentRoot <$>
33+ either (Left . T.pack . E.displayException) Right
34+ (Conduit.parseText Conduit.def{ Conduit.psRetainNamespaces = True } t)
35+
36+parseXMLContents :: TL.Text -> Either T.Text [Light.Content]
37+parseXMLContents t =
38+ case Conduit.parseText Conduit.def{ Conduit.psRetainNamespaces = True } t of
39+ Left e ->
40+ case E.fromException e of
41+ Just (ContentAfterRoot _) ->
42+ elContent <$> parseXMLElement ("<wrapper>" <> t <> "</wrapper>")
43+ _ -> Left . T.pack . E.displayException $ e
44+ Right x -> Right [Light.Elem . elementToElement . Conduit.documentRoot $ x]
45+
46+elementToElement :: Conduit.Element -> Light.Element
47+elementToElement (Conduit.Element name attribMap nodes) =
48+ Light.Element (nameToQname name) attrs (mapMaybe nodeToContent nodes) Nothing
49+ where
50+ attrs = map (\(n,v) -> Light.Attr (nameToQname n) (T.unpack v)) $
51+ M.toList attribMap
52+ nameToQname (Conduit.Name localName mbns mbpref) =
53+ case mbpref of
54+ Nothing | "xmlns:" `T.isPrefixOf` localName ->
55+ Light.QName (T.unpack $ T.drop 6 localName) (T.unpack <$> mbns)
56+ (Just "xmlns")
57+ _ -> Light.QName (T.unpack localName) (T.unpack <$> mbns)
58+ (T.unpack <$> mbpref)
59+
60+nodeToContent :: Conduit.Node -> Maybe Light.Content
61+nodeToContent (Conduit.NodeElement el) =
62+ Just (Light.Elem (elementToElement el))
63+nodeToContent (Conduit.NodeContent t) =
64+ Just (Light.Text (Light.CData Light.CDataText (T.unpack t) Nothing))
65+nodeToContent _ = Nothing
66+
test/Tests/Readers/JATS.hs+1
@@ -88,6 +88,7 @@ tests = [ testGroup "inline code"
88 "<p>\n\
88 "<p>\n\
89 \ <inline-formula><alternatives>\n\
89 \ <inline-formula><alternatives>\n\
90 \ <tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\
90 \ <tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\
91+ \ </alternatives></inline-formula>\n\
91 \</p>"
92 \</p>"
92 =?> para (math "\\sigma|_{\\{x\\}}")
93 =?> para (math "\\sigma|_{\\{x\\}}")
93 , test jats "math ml only" $
94 , test jats "math ml only" $
test/command/5321.md+2−2
@@ -4,7 +4,7 @@
4 <caption>
4 <caption>
5 <p>bar</p>
5 <p>bar</p>
6 </caption>
6 </caption>
7− <graphic xlink:href="foo.png" xlink:alt-text="baz">
7+ <graphic xlink:href="foo.png" xlink:alt-text="baz" />
8</fig>
8</fig>
9^D
9^D
10[Para [Image ("fig-1",[],[]) [Str "bar"] ("foo.png","fig:")]]
10[Para [Image ("fig-1",[],[]) [Str "bar"] ("foo.png","fig:")]]
@@ -17,7 +17,7 @@
17 <title>foo</title>
17 <title>foo</title>
18 <p>bar</p>
18 <p>bar</p>
19 </caption>
19 </caption>
20− <graphic xlink:href="foo.png" xlink:alt-text="baz">
20+ <graphic xlink:href="foo.png" xlink:alt-text="baz" />
21</fig>
21</fig>
22^D
22^D
23[Para [Image ("fig-1",[],[]) [Str "foo",LineBreak,Str "bar"] ("foo.png","fig:")]]
23[Para [Image ("fig-1",[],[]) [Str "foo",LineBreak,Str "bar"] ("foo.png","fig:")]]
test/docbook-reader.docbook+6−1
@@ -1,6 +1,11 @@
1<?xml version="1.0" encoding="utf-8" ?>
1<?xml version="1.0" encoding="utf-8" ?>
2<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
2<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
3− "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
3+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"
4+[
5+<!ENTITY GHC "GHC" >
6+<!ENTITY let "LET" >
7+<!ENTITY case "CASE" >
8+]>
4<article>
9<article>
5 <articleinfo>
10 <articleinfo>
6 <title>Pandoc Test Suite</title>
11 <title>Pandoc Test Suite</title>
test/docx/golden/block_quotes.docx

Binary file not shown.

test/docx/golden/codeblock.docx

Binary file not shown.

test/docx/golden/comments.docx

Binary file not shown.

test/docx/golden/custom_style_no_reference.docx

Binary file not shown.

test/docx/golden/custom_style_preserve.docx

Binary file not shown.

test/docx/golden/custom_style_reference.docx

Binary file not shown.

test/docx/golden/definition_list.docx

Binary file not shown.

test/docx/golden/document-properties-short-desc.docx

Binary file not shown.

test/docx/golden/document-properties.docx

Binary file not shown.

test/docx/golden/headers.docx

Binary file not shown.

test/docx/golden/image.docx

Binary file not shown.

test/docx/golden/inline_code.docx

Binary file not shown.

test/docx/golden/inline_formatting.docx

Binary file not shown.

test/docx/golden/inline_images.docx

Binary file not shown.

test/docx/golden/link_in_notes.docx

Binary file not shown.

test/docx/golden/links.docx

Binary file not shown.

test/docx/golden/lists.docx

Binary file not shown.

test/docx/golden/lists_continuing.docx

Binary file not shown.

test/docx/golden/lists_multiple_initial.docx

Binary file not shown.

test/docx/golden/lists_restarting.docx

Binary file not shown.

test/docx/golden/nested_anchors_in_header.docx

Binary file not shown.

test/docx/golden/notes.docx

Binary file not shown.

test/docx/golden/raw-blocks.docx

Binary file not shown.

test/docx/golden/raw-bookmarks.docx

Binary file not shown.

test/docx/golden/table_one_row.docx

Binary file not shown.

test/docx/golden/table_with_list_cell.docx

Binary file not shown.

test/docx/golden/tables.docx

Binary file not shown.

test/docx/golden/track_changes_deletion.docx

Binary file not shown.

test/docx/golden/track_changes_insertion.docx

Binary file not shown.

test/docx/golden/track_changes_move.docx

Binary file not shown.

test/docx/golden/track_changes_scrubbed_metadata.docx

Binary file not shown.

test/docx/golden/unicode.docx

Binary file not shown.

test/docx/golden/verbatim_subsuper.docx

Binary file not shown.

test/jats-reader.native+1−1
@@ -1,4 +1,4 @@
1−Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Space,Str "MacFarlane"]]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
1+Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Space,Str "MacFarlane"],MetaInlines [Str "Anonymous"]]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
2[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber's",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
2[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber's",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
3,Header 1 ("headers",[],[]) [Str "Headers"]
3,Header 1 ("headers",[],[]) [Str "Headers"]
4,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",SoftBreak,Link ("",[],[]) [Str "embedded",SoftBreak,Str "link"] ("/url","")]
4,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",SoftBreak,Link ("",[],[]) [Str "embedded",SoftBreak,Str "link"] ("/url","")]
test/jats-reader.xml+1
@@ -20,6 +20,7 @@
20 <surname>MacFarlane</surname>
20 <surname>MacFarlane</surname>
21 <given-names>John</given-names>
21 <given-names>John</given-names>
22 </name>
22 </name>
23+ </contrib>
23 <contrib contrib-type="author">
24 <contrib contrib-type="author">
24 <name>
25 <name>
25 <surname>Anonymous</surname>
26 <surname>Anonymous</surname>
test/pptx/code-custom.pptx

Binary file not shown.

test/pptx/code-custom_templated.pptx

Binary file not shown.

test/pptx/code.pptx

Binary file not shown.

test/pptx/code_templated.pptx

Binary file not shown.

test/pptx/document-properties-short-desc.pptx

Binary file not shown.

test/pptx/document-properties-short-desc_templated.pptx

Binary file not shown.

test/pptx/document-properties.pptx

Binary file not shown.

test/pptx/document-properties_templated.pptx

Binary file not shown.

test/pptx/endnotes.pptx

Binary file not shown.

test/pptx/endnotes_templated.pptx

Binary file not shown.

test/pptx/endnotes_toc.pptx

Binary file not shown.

test/pptx/endnotes_toc_templated.pptx

Binary file not shown.

test/pptx/images.pptx

Binary file not shown.

test/pptx/images_templated.pptx

Binary file not shown.

test/pptx/inline_formatting.pptx

Binary file not shown.

test/pptx/inline_formatting_templated.pptx

Binary file not shown.

test/pptx/lists.pptx

Binary file not shown.

test/pptx/lists_templated.pptx

Binary file not shown.

test/pptx/raw_ooxml.pptx

Binary file not shown.

test/pptx/raw_ooxml_templated.pptx

Binary file not shown.

test/pptx/remove_empty_slides.pptx

Binary file not shown.

test/pptx/remove_empty_slides_templated.pptx

Binary file not shown.

test/pptx/slide_breaks.pptx

Binary file not shown.

test/pptx/slide_breaks_slide_level_1.pptx

Binary file not shown.

test/pptx/slide_breaks_slide_level_1_templated.pptx

Binary file not shown.

test/pptx/slide_breaks_templated.pptx

Binary file not shown.

test/pptx/slide_breaks_toc.pptx

Binary file not shown.

test/pptx/slide_breaks_toc_templated.pptx

Binary file not shown.

test/pptx/speaker_notes.pptx

Binary file not shown.

test/pptx/speaker_notes_after_metadata.pptx

Binary file not shown.

test/pptx/speaker_notes_after_metadata_templated.pptx

Binary file not shown.

test/pptx/speaker_notes_afterheader.pptx

Binary file not shown.

test/pptx/speaker_notes_afterheader_templated.pptx

Binary file not shown.

test/pptx/speaker_notes_afterseps.pptx

Binary file not shown.

test/pptx/speaker_notes_afterseps_templated.pptx

Binary file not shown.

test/pptx/speaker_notes_templated.pptx

Binary file not shown.

test/pptx/start_numbering_at.pptx

Binary file not shown.

test/pptx/start_numbering_at_templated.pptx

Binary file not shown.

test/pptx/tables.pptx

Binary file not shown.

test/pptx/tables_templated.pptx

Binary file not shown.

test/pptx/two_column.pptx

Binary file not shown.

test/pptx/two_column_templated.pptx

Binary file not shown.