git.iko.soy/typeable/pandoc
on master help sign in
Add new unexported module T.P.XMLParser.

This exports functions that uses xml-conduit's parser to produce an xml-light Element or [Content]. This allows existing pandoc code to use a better parser without much modification. The new parser is used in all places where xml-light's parser was previously used. Benchmarks show a significant performance improvement in parsing XML-based formats (especially ODT and FB2). Note that the xml-light types use String, so the conversion from xml-conduit types involves a lot of extra allocation. It would be desirable to avoid that in the future by gradually switching to using xml-conduit directly. This can be done module by module. The new parser also reports errors, which we report when possible. A new constructor PandocXMLError has been added to PandocError in T.P.Error [API change]. Closes #7091, which was the main stimulus. These changes revealed the need for some changes in the tests. The docbook-reader.docbook test lacked definitions for the entities it used; these have been added. And the docx golden tests have been updated, because the new parser does not preserve the order of attributes. Add entity defs to docbook-reader.docbook. Update golden tests for docx.

commit8ca191604dcd13af27c11d2da225da646ebce6fc authorJohn MacFarlane <jgm@berkeley.edu> dateMon 8 Feb 2021, 23:35 (6 years ago) parent9994ad9
98 files changed+238−91
MANUAL.txt+1 pandoc.cabal+2 src/Text/Pandoc/Error.hs+3 src/Text/Pandoc/ImageSize.hs+4−1 src/Text/Pandoc/Readers/DocBook.hs+33−19 src/Text/Pandoc/Readers/Docx/Parse.hs+14−7 src/Text/Pandoc/Readers/Docx/Parse/Styles.hs+16−12 src/Text/Pandoc/Readers/EPUB.hs+11−6 src/Text/Pandoc/Readers/FB2.hs+6−4 src/Text/Pandoc/Readers/JATS.hs+7−2 src/Text/Pandoc/Readers/OPML.hs+8−2 src/Text/Pandoc/Readers/Odt.hs+14−10 src/Text/Pandoc/Writers/EPUB.hs+10−3 src/Text/Pandoc/Writers/FB2.hs+8−3 src/Text/Pandoc/Writers/ODT.hs+16−13 src/Text/Pandoc/Writers/OOXML.hs+5−4 src/Text/Pandoc/Writers/Powerpoint/Output.hs+3−1 src/Text/Pandoc/XMLParser.hs+66 test/Tests/Readers/JATS.hs+1 test/command/5321.md+2−2 test/docbook-reader.docbook+6−1 test/docx/golden/block_quotes.docx test/docx/golden/codeblock.docx test/docx/golden/comments.docx test/docx/golden/custom_style_no_reference.docx test/docx/golden/custom_style_preserve.docx test/docx/golden/custom_style_reference.docx test/docx/golden/definition_list.docx test/docx/golden/document-properties-short-desc.docx test/docx/golden/document-properties.docx test/docx/golden/headers.docx test/docx/golden/image.docx test/docx/golden/inline_code.docx test/docx/golden/inline_formatting.docx test/docx/golden/inline_images.docx test/docx/golden/link_in_notes.docx test/docx/golden/links.docx test/docx/golden/lists.docx test/docx/golden/lists_continuing.docx test/docx/golden/lists_multiple_initial.docx test/docx/golden/lists_restarting.docx test/docx/golden/nested_anchors_in_header.docx test/docx/golden/notes.docx test/docx/golden/raw-blocks.docx test/docx/golden/raw-bookmarks.docx test/docx/golden/table_one_row.docx test/docx/golden/table_with_list_cell.docx test/docx/golden/tables.docx test/docx/golden/track_changes_deletion.docx test/docx/golden/track_changes_insertion.docx test/docx/golden/track_changes_move.docx test/docx/golden/track_changes_scrubbed_metadata.docx test/docx/golden/unicode.docx test/docx/golden/verbatim_subsuper.docx test/jats-reader.native+1−1 test/jats-reader.xml+1 test/pptx/code-custom.pptx test/pptx/code-custom_templated.pptx test/pptx/code.pptx test/pptx/code_templated.pptx test/pptx/document-properties-short-desc.pptx test/pptx/document-properties-short-desc_templated.pptx test/pptx/document-properties.pptx test/pptx/document-properties_templated.pptx test/pptx/endnotes.pptx test/pptx/endnotes_templated.pptx test/pptx/endnotes_toc.pptx test/pptx/endnotes_toc_templated.pptx test/pptx/images.pptx test/pptx/images_templated.pptx test/pptx/inline_formatting.pptx test/pptx/inline_formatting_templated.pptx test/pptx/lists.pptx test/pptx/lists_templated.pptx test/pptx/raw_ooxml.pptx test/pptx/raw_ooxml_templated.pptx test/pptx/remove_empty_slides.pptx test/pptx/remove_empty_slides_templated.pptx test/pptx/slide_breaks.pptx test/pptx/slide_breaks_slide_level_1.pptx test/pptx/slide_breaks_slide_level_1_templated.pptx test/pptx/slide_breaks_templated.pptx test/pptx/slide_breaks_toc.pptx test/pptx/slide_breaks_toc_templated.pptx test/pptx/speaker_notes.pptx test/pptx/speaker_notes_after_metadata.pptx test/pptx/speaker_notes_after_metadata_templated.pptx test/pptx/speaker_notes_afterheader.pptx test/pptx/speaker_notes_afterheader_templated.pptx test/pptx/speaker_notes_afterseps.pptx test/pptx/speaker_notes_afterseps_templated.pptx test/pptx/speaker_notes_templated.pptx test/pptx/start_numbering_at.pptx test/pptx/start_numbering_at_templated.pptx test/pptx/tables.pptx test/pptx/tables_templated.pptx test/pptx/two_column.pptx test/pptx/two_column_templated.pptx
MANUAL.txt+1
@@ -1464,6 +1464,7 @@ Nonzero exit codes have the following meanings:
14641464 24 PandocCiteprocError
14651465 31 PandocEpubSubdirectoryError
14661466 43 PandocPDFError
1467+ 44 PandocXMLError
14671468 47 PandocPDFProgramNotFoundError
14681469 61 PandocHttpError
14691470 62 PandocShouldNeverHappenError
pandoc.cabal+2
@@ -493,6 +493,7 @@ library
493493 unicode-transforms >= 0.3 && < 0.4,
494494 unordered-containers >= 0.2 && < 0.3,
495495 xml >= 1.3.12 && < 1.4,
496+ xml-conduit >= 1.7 && < 1.10,
496497 zip-archive >= 0.2.3.4 && < 0.5,
497498 zlib >= 0.5 && < 0.7
498499 if os(windows) && arch(i386)
@@ -686,6 +687,7 @@ library
686687 Text.Pandoc.Lua.PandocLua,
687688 Text.Pandoc.Lua.Util,
688689 Text.Pandoc.Lua.Walk,
690+ Text.Pandoc.XMLParser,
689691 Text.Pandoc.CSS,
690692 Text.Pandoc.CSV,
691693 Text.Pandoc.RoffChar,
src/Text/Pandoc/Error.hs+3
@@ -48,6 +48,7 @@ data PandocError = PandocIOError Text IOError
4848 | PandocFailOnWarningError
4949 | PandocPDFProgramNotFoundError Text
5050 | PandocPDFError Text
51+ | PandocXMLError Text Text
5152 | PandocFilterError Text Text
5253 | PandocLuaError Text
5354 | PandocCouldNotFindDataFileError Text
@@ -103,6 +104,8 @@ handleError (Left e) =
103104 PandocPDFProgramNotFoundError pdfprog -> err 47 $
104105 pdfprog <> " not found. Please select a different --pdf-engine or install " <> pdfprog
105106 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
106109 PandocFilterError filtername msg -> err 83 $ "Error running filter " <>
107110 filtername <> ":\n" <> msg
108111 PandocLuaError msg -> err 84 $ "Error running Lua:\n" <> msg
src/Text/Pandoc/ImageSize.hs+4−1
@@ -45,7 +45,9 @@ import Text.Pandoc.Definition
4545import Text.Pandoc.Options
4646import qualified Text.Pandoc.UTF8 as UTF8
4747import qualified Text.XML.Light as Xml
48+import Text.Pandoc.XMLParser (parseXMLElement)
4849import qualified Data.Text as T
50+import qualified Data.Text.Lazy as TL
4951import qualified Data.Text.Encoding as TE
5052import Control.Applicative
5153import qualified Data.Attoparsec.ByteString.Char8 as A
@@ -327,7 +329,8 @@ getSize img =
327329
328330svgSize :: WriterOptions -> ByteString -> Maybe ImageSize
329331svgSize opts img = do
330− doc <- Xml.parseXMLDoc $ UTF8.toString img
332+ doc <- either (const mzero) return $ parseXMLElement
333+ $ TL.fromStrict $ UTF8.toText img
331334 let viewboxSize = do
332335 vb <- Xml.findAttrBy (== Xml.QName "viewBox" Nothing Nothing) doc
333336 [_,_,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.
1212-}
1313module Text.Pandoc.Readers.DocBook ( readDocBook ) where
1414import Control.Monad.State.Strict
15−import Data.Char (isSpace, toUpper)
15+import Data.Char (isSpace, toUpper, isLetter)
1616import Data.Default
1717import Data.Either (rights)
1818import Data.Foldable (asum)
@@ -21,7 +21,10 @@ import Data.List (intersperse,elemIndex)
2121import Data.Maybe (fromMaybe,mapMaybe)
2222import Data.Text (Text)
2323import qualified Data.Text as T
24+import qualified Data.Text.Lazy as TL
25+import Control.Monad.Except (throwError)
2426import Text.HTML.TagSoup.Entity (lookupEntity)
27+import Text.Pandoc.Error (PandocError(..))
2528import Text.Pandoc.Builder
2629import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
2730import Text.Pandoc.Options
@@ -29,6 +32,7 @@ import Text.Pandoc.Logging (LogMessage(..))
2932import Text.Pandoc.Shared (crFilter, safeRead, extractSpaces)
3033import Text.TeXMath (readMathML, writeTeX)
3134import Text.XML.Light
35+import Text.Pandoc.XMLParser (parseXMLContents)
3236
3337{-
3438
@@ -537,22 +541,25 @@ instance Default DBState where
537541
538542readDocBook :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
539543readDocBook _ inp = do
540− let tree = normalizeTree . parseXML . handleInstructions $ crFilter inp
544+ tree <- either (throwError . PandocXMLError "") (return . normalizeTree) $
545+ parseXMLContents (TL.fromStrict . handleInstructions $ crFilter inp)
541546 (bs, st') <- flip runStateT (def{ dbContent = tree }) $ mapM parseBlock tree
542547 return $ Pandoc (dbMeta st') (toList . mconcat $ bs)
543548
544−-- We treat <?asciidoc-br?> specially (issue #1236), converting it
545−-- to <br/>, since xml-light doesn't parse the instruction correctly.
546−-- Other xml instructions are simply removed from the input stream.
549+-- We treat certain processing instructions by converting them to tags
550+-- beginning "pi-".
547551handleInstructions :: Text -> Text
548−handleInstructions = T.pack . handleInstructions' . T.unpack
549−
550−handleInstructions' :: String -> String
551−handleInstructions' ('<':'?':'a':'s':'c':'i':'i':'d':'o':'c':'-':'b':'r':'?':'>':xs) = '<':'b':'r':'/':'>': handleInstructions' xs
552−handleInstructions' xs = case break (=='<') xs of
553− (ys, []) -> ys
554− ([], '<':zs) -> '<' : handleInstructions' zs
555− (ys, zs) -> ys ++ handleInstructions' zs
552+handleInstructions t =
553+ let (x,y) = T.breakOn "<?" t
554+ in if T.null y
555+ then x
556+ else
557+ let (w,z) = T.breakOn "?>" y
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) <>
562+ handleInstructions (T.drop 2 z)
556563
557564getFigure :: PandocMonad m => Element -> DB m Blocks
558565getFigure e = do
@@ -892,7 +899,11 @@ parseBlock (Elem e) =
892899 "subtitle" -> return mempty -- handled in parent element
893900 _ -> skip >> getBlocks e
894901 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
896907 return mempty
897908
898909 codeBlockWithLang = do
@@ -964,7 +975,7 @@ parseBlock (Elem e) =
964975 cs -> map toAlignment cs
965976 let parseWidth s = safeRead (T.filter (\x -> (x >= '0' && x <= '9')
966977 || x == '.') s)
967− let textWidth = case filterChild (named "?dbfo") e of
978+ let textWidth = case filterChild (named "pi-dbfo") e of
968979 Just d -> case attrValue "table-width" d of
969980 "" -> 1.0
970981 w -> fromMaybe 100.0 (parseWidth w) / 100.0
@@ -1165,12 +1176,15 @@ parseInline (Elem e) =
11651176 "title" -> return mempty
11661177 "affiliation" -> skip
11671178 -- Note: this isn't a real docbook tag; it's what we convert
1168− -- <?asciidor-br?> to in handleInstructions, above. A kludge to
1169− -- work around xml-light's inability to parse an instruction.
1170− "br" -> return linebreak
1179+ -- <?asciidor-br?> to in handleInstructions, above.
1180+ "pi-asciidoc-br" -> return linebreak
11711181 _ -> skip >> innerInlines id
11721182 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
11741188 return mempty
11751189
11761190 innerInlines f = extractSpaces f . mconcat <$>
src/Text/Pandoc/Readers/Docx/Parse.hs+14−7
@@ -74,6 +74,7 @@ import Text.TeXMath.Readers.OMML (readOMML)
7474import Text.TeXMath.Unicode.Fonts (Font (..), getUnicode, textToFont)
7575import Text.XML.Light
7676import qualified Text.XML.Light.Cursor as XMLC
77+import Text.Pandoc.XMLParser (parseXMLElement)
7778
7879data ReaderEnv = ReaderEnv { envNotes :: Notes
7980 , envComments :: Comments
@@ -343,10 +344,16 @@ archiveToDocxWithWarnings archive = do
343344 Right doc -> Right (Docx doc, stateWarnings st)
344345 Left e -> Left e
345346
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+
346353getDocumentXmlPath :: Archive -> Maybe FilePath
347354getDocumentXmlPath zf = do
348355 entry <- findEntryByPath "_rels/.rels" zf
349− relsElem <- (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
356+ relsElem <- parseXMLFromEntry entry
350357 let rels = filterChildrenName (\n -> qName n == "Relationship") relsElem
351358 rel <- find (\e -> findAttr (QName "Type" Nothing Nothing) e ==
352359 Just "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument")
@@ -362,7 +369,7 @@ archiveToDocument :: Archive -> D Document
362369archiveToDocument zf = do
363370 docPath <- asks envDocXmlPath
364371 entry <- maybeToD $ findEntryByPath docPath zf
365− docElem <- maybeToD $ (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
372+ docElem <- maybeToD $ parseXMLFromEntry entry
366373 let namespaces = elemToNameSpaces docElem
367374 bodyElem <- maybeToD $ findChildByName namespaces "w" "body" docElem
368375 let bodyElem' = fromMaybe bodyElem (walkDocument namespaces bodyElem)
@@ -401,9 +408,9 @@ constructBogusParStyleData stName = ParStyle
401408archiveToNotes :: Archive -> Notes
402409archiveToNotes zf =
403410 let fnElem = findEntryByPath "word/footnotes.xml" zf
404− >>= (parseXMLDoc . UTF8.toStringLazy . fromEntry)
411+ >>= parseXMLFromEntry
405412 enElem = findEntryByPath "word/endnotes.xml" zf
406− >>= (parseXMLDoc . UTF8.toStringLazy . fromEntry)
413+ >>= parseXMLFromEntry
407414 fn_namespaces = maybe [] elemToNameSpaces fnElem
408415 en_namespaces = maybe [] elemToNameSpaces enElem
409416 ns = unionBy (\x y -> fst x == fst y) fn_namespaces en_namespaces
@@ -415,7 +422,7 @@ archiveToNotes zf =
415422archiveToComments :: Archive -> Comments
416423archiveToComments zf =
417424 let cmtsElem = findEntryByPath "word/comments.xml" zf
418− >>= (parseXMLDoc . UTF8.toStringLazy . fromEntry)
425+ >>= parseXMLFromEntry
419426 cmts_namespaces = maybe [] elemToNameSpaces cmtsElem
420427 cmts = elemToComments cmts_namespaces <$> (cmtsElem >>= walkDocument cmts_namespaces)
421428 in
@@ -445,7 +452,7 @@ filePathToRelationships :: Archive -> FilePath -> FilePath -> [Relationship]
445452filePathToRelationships ar docXmlPath fp
446453 | Just relType <- filePathToRelType fp docXmlPath
447454 , Just entry <- findEntryByPath fp ar
448− , Just relElems <- (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry =
455+ , Just relElems <- parseXMLFromEntry entry =
449456 mapMaybe (relElemToRelationship relType) $ elChildren relElems
450457filePathToRelationships _ _ _ = []
451458
@@ -527,7 +534,7 @@ archiveToNumbering' zf =
527534 case findEntryByPath "word/numbering.xml" zf of
528535 Nothing -> Just $ Numbering [] [] []
529536 Just entry -> do
530− numberingElem <- (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
537+ numberingElem <- parseXMLFromEntry entry
531538 let namespaces = elemToNameSpaces numberingElem
532539 numElems = findChildrenByName namespaces "w" "num" numberingElem
533540 absNumElems = findChildrenByName namespaces "w" "abstractNum" numberingElem
src/Text/Pandoc/Readers/Docx/Parse/Styles.hs+16−12
@@ -53,6 +53,7 @@ import Data.Coerce
5353import Text.Pandoc.Readers.Docx.Util
5454import qualified Text.Pandoc.UTF8 as UTF8
5555import Text.XML.Light
56+import Text.Pandoc.XMLParser (parseXMLElement)
5657
5758newtype CharStyleId = CharStyleId T.Text
5859 deriving (Show, Eq, Ord, IsString, FromStyleId)
@@ -135,19 +136,22 @@ defaultRunStyle = RunStyle { isBold = Nothing
135136 , rParentStyle = Nothing
136137 }
137138
138−archiveToStyles' :: (Ord k1, Ord k2, ElemToStyle a1, ElemToStyle a2) =>
139− (a1 -> k1) -> (a2 -> k2) -> Archive -> (M.Map k1 a1, M.Map k2 a2)
139+archiveToStyles'
140+ :: (Ord k1, Ord k2, ElemToStyle a1, ElemToStyle a2)
141+ => (a1 -> k1) -> (a2 -> k2) -> Archive -> (M.Map k1 a1, M.Map k2 a2)
140142archiveToStyles' conv1 conv2 zf =
141− let stylesElem = findEntryByPath "word/styles.xml" zf >>=
142− (parseXMLDoc . UTF8.toStringLazy . fromEntry)
143− in
144− case stylesElem of
145− Nothing -> (M.empty, M.empty)
146− Just styElem ->
147− let namespaces = elemToNameSpaces styElem
148− in
149− ( M.fromList $ map (\r -> (conv1 r, r)) $ buildBasedOnList namespaces styElem Nothing,
150− M.fromList $ map (\p -> (conv2 p, p)) $ buildBasedOnList namespaces styElem Nothing)
143+ case findEntryByPath "word/styles.xml" zf of
144+ Nothing -> (M.empty, M.empty)
145+ Just entry ->
146+ case parseXMLElement . UTF8.toTextLazy . fromEntry $ entry of
147+ Left _ -> (M.empty, M.empty)
148+ Right styElem ->
149+ let namespaces = elemToNameSpaces styElem
150+ in
151+ ( M.fromList $ map (\r -> (conv1 r, r)) $
152+ buildBasedOnList namespaces styElem Nothing,
153+ M.fromList $ map (\p -> (conv2 p, p)) $
154+ buildBasedOnList namespaces styElem Nothing)
151155
152156isBasedOnStyle :: (ElemToStyle a, FromStyleId (StyleId a)) => NameSpaces -> Element -> Maybe a -> Bool
153157isBasedOnStyle ns element parentStyle
src/Text/Pandoc/Readers/EPUB.hs+11−6
@@ -17,7 +17,7 @@ module Text.Pandoc.Readers.EPUB
1717 (readEPUB)
1818 where
1919
20−import Codec.Archive.Zip (Archive (..), Entry, findEntryByPath, fromEntry,
20+import Codec.Archive.Zip (Archive (..), Entry(..), findEntryByPath, fromEntry,
2121 toArchiveOrFail)
2222import Control.DeepSeq (NFData, deepseq)
2323import Control.Monad (guard, liftM, liftM2, mplus)
@@ -41,9 +41,10 @@ import Text.Pandoc.MIME (MimeType)
4141import Text.Pandoc.Options (ReaderOptions (..))
4242import Text.Pandoc.Readers.HTML (readHtml)
4343import Text.Pandoc.Shared (addMetaField, collapseFilePath, escapeURI)
44−import qualified Text.Pandoc.UTF8 as UTF8 (toStringLazy)
44+import qualified Text.Pandoc.UTF8 as UTF8 (toTextLazy)
4545import Text.Pandoc.Walk (query, walk)
4646import Text.XML.Light
47+import Text.Pandoc.XMLParser (parseXMLElement)
4748
4849type Items = M.Map String (FilePath, MimeType)
4950
@@ -181,7 +182,7 @@ renameMeta s = T.pack s
181182getManifest :: PandocMonad m => Archive -> m (String, Element)
182183getManifest archive = do
183184 metaEntry <- findEntryByPathE ("META-INF" </> "container.xml") archive
184− docElem <- (parseXMLDocE . UTF8.toStringLazy . fromEntry) metaEntry
185+ docElem <- parseXMLDocE metaEntry
185186 let namespaces = mapMaybe attrToNSPair (elAttribs docElem)
186187 ns <- mkE "xmlns not in namespaces" (lookup "xmlns" namespaces)
187188 as <- fmap (map attrToPair . elAttribs)
@@ -190,7 +191,7 @@ getManifest archive = do
190191 let rootdir = dropFileName manifestFile
191192 --mime <- lookup "media-type" as
192193 manifest <- findEntryByPathE manifestFile archive
193− (rootdir,) <$> (parseXMLDocE . UTF8.toStringLazy . fromEntry $ manifest)
194+ (rootdir,) <$> parseXMLDocE manifest
194195
195196-- Fixup
196197
@@ -284,8 +285,12 @@ findEntryByPathE :: PandocMonad m => FilePath -> Archive -> m Entry
284285findEntryByPathE (normalise . unEscapeString -> path) a =
285286 mkE ("No entry on path: " ++ path) $ findEntryByPath path a
286287
287−parseXMLDocE :: PandocMonad m => String -> m Element
288−parseXMLDocE doc = mkE "Unable to parse XML doc" $ parseXMLDoc doc
288+parseXMLDocE :: PandocMonad m => Entry -> m Element
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
289294
290295findElementE :: PandocMonad m => QName -> Element -> m Element
291296findElementE 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)
3232import qualified Data.Map as M
3333import Data.Text (Text)
3434import qualified Data.Text as T
35+import qualified Data.Text.Lazy as TL
3536import Data.Default
3637import Data.Maybe
3738import Text.HTML.TagSoup.Entity (lookupEntity)
@@ -42,6 +43,7 @@ import Text.Pandoc.Logging
4243import Text.Pandoc.Options
4344import Text.Pandoc.Shared (crFilter)
4445import Text.XML.Light
46+import Text.Pandoc.XMLParser (parseXMLElement)
4547
4648type FB2 m = StateT FB2State m
4749
@@ -64,10 +66,10 @@ instance HasMeta FB2State where
6466
6567readFB2 :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
6668readFB2 _ inp =
67− case parseXMLDoc $ crFilter inp of
68− Nothing -> throwError $ PandocParseError "Not an XML document"
69− Just e -> do
70− (bs, st) <- runStateT (parseRootElement e) def
69+ case parseXMLElement $ TL.fromStrict $ crFilter inp of
70+ Left msg -> throwError $ PandocXMLError "" msg
71+ Right el -> do
72+ (bs, st) <- runStateT (parseRootElement el) def
7173 let authors = if null $ fb2Authors st
7274 then id
7375 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.
1414
1515module Text.Pandoc.Readers.JATS ( readJATS ) where
1616import Control.Monad.State.Strict
17+import Control.Monad.Except (throwError)
18+import Text.Pandoc.Error (PandocError(..))
1719import Data.Char (isDigit, isSpace, toUpper)
1820import Data.Default
1921import Data.Generics
@@ -22,6 +24,7 @@ import qualified Data.Map as Map
2224import Data.Maybe (maybeToList, fromMaybe)
2325import Data.Text (Text)
2426import qualified Data.Text as T
27+import qualified Data.Text.Lazy as TL
2528import Text.HTML.TagSoup.Entity (lookupEntity)
2629import Text.Pandoc.Builder
2730import Text.Pandoc.Class.PandocMonad (PandocMonad)
@@ -29,6 +32,7 @@ import Text.Pandoc.Options
2932import Text.Pandoc.Shared (crFilter, safeRead, extractSpaces)
3033import Text.TeXMath (readMathML, writeTeX)
3134import Text.XML.Light
35+import Text.Pandoc.XMLParser (parseXMLContents)
3236import qualified Data.Set as S (fromList, member)
3337import Data.Set ((\\))
3438
@@ -51,8 +55,9 @@ instance Default JATSState where
5155
5256readJATS :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
5357readJATS _ inp = do
54− let tree = normalizeTree . parseXML
55− $ T.unpack $ crFilter inp
58+ tree <- either (throwError . PandocXMLError "")
59+ (return . normalizeTree) $
60+ parseXMLContents (TL.fromStrict $ crFilter inp)
5661 (bs, st') <- flip runStateT (def{ jatsContent = tree }) $ mapM parseBlock tree
5762 return $ Pandoc (jatsMeta st') (toList . mconcat $ bs)
5863
src/Text/Pandoc/Readers/OPML.hs+8−2
@@ -19,14 +19,18 @@ import Data.Generics
1919import Data.Maybe (fromMaybe)
2020import Data.Text (Text)
2121import qualified Data.Text as T
22+import qualified Data.Text.Lazy as TL
2223import Text.HTML.TagSoup.Entity (lookupEntity)
2324import Text.Pandoc.Builder
2425import Text.Pandoc.Class.PandocMonad (PandocMonad)
2526import Text.Pandoc.Options
27+import Text.Pandoc.Error (PandocError(..))
2628import Text.Pandoc.Readers.HTML (readHtml)
2729import Text.Pandoc.Readers.Markdown (readMarkdown)
2830import Text.Pandoc.Shared (crFilter, blocksToInlines')
2931import Text.XML.Light
32+import Text.Pandoc.XMLParser (parseXMLContents)
33+import Control.Monad.Except (throwError)
3034
3135type OPML m = StateT OPMLState m
3236
@@ -49,8 +53,10 @@ instance Default OPMLState where
4953readOPML :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
5054readOPML opts inp = do
5155 (bs, st') <- runStateT
52− (mapM parseBlock $ normalizeTree $
53− parseXML (T.unpack (crFilter inp))) def{ opmlOptions = opts }
56+ (case parseXMLContents (TL.fromStrict (crFilter inp)) of
57+ Left msg -> throwError $ PandocXMLError "" msg
58+ Right ns -> mapM parseBlock $ normalizeTree ns)
59+ def{ opmlOptions = opts }
5460 return $
5561 setTitle (opmlDocTitle st') $
5662 setAuthors (opmlDocAuthors st') $
src/Text/Pandoc/Readers/Odt.hs+14−10
@@ -15,6 +15,7 @@ module Text.Pandoc.Readers.Odt ( readOdt ) where
1515
1616import Codec.Archive.Zip
1717import qualified Text.XML.Light as XML
18+import Text.Pandoc.XMLParser (parseXMLElement)
1819
1920import qualified Data.ByteString.Lazy as B
2021
@@ -66,18 +67,18 @@ bytesToOdt bytes = case toArchiveOrFail bytes of
6667
6768--
6869archiveToOdt :: Archive -> Either PandocError (Pandoc, MediaBag)
69−archiveToOdt archive = either (Left. PandocParseError) Right $ do
70− let onFailure msg Nothing = Left msg
70+archiveToOdt archive = do
71+ let onFailure msg Nothing = Left $ PandocParseError msg
7172 onFailure _ (Just x) = Right x
7273 contentEntry <- onFailure "Could not find content.xml"
7374 (findEntryByPath "content.xml" archive)
7475 stylesEntry <- onFailure "Could not find styles.xml"
7576 (findEntryByPath "styles.xml" archive)
76− contentElem <- onFailure "Could not find content element"
77− (entryToXmlElem contentEntry)
78− stylesElem <- onFailure "Could not find styles element"
79− (entryToXmlElem stylesEntry)
80− styles <- either (\_ -> Left "Could not read styles") Right
77+ contentElem <- entryToXmlElem contentEntry
78+ stylesElem <- entryToXmlElem stylesEntry
79+ styles <- either
80+ (\_ -> Left $ PandocParseError "Could not read styles")
81+ Right
8182 (chooseMax (readStylesAt stylesElem ) (readStylesAt contentElem))
8283 let filePathIsOdtMedia :: FilePath -> Bool
8384 filePathIsOdtMedia fp =
@@ -85,10 +86,13 @@ archiveToOdt archive = either (Left. PandocParseError) Right $ do
8586 in (dir == "Pictures/") || (dir /= "./" && name == "content.xml")
8687 let media = filteredFilesFromArchive archive filePathIsOdtMedia
8788 let startState = readerState styles media
88− either (\_ -> Left "Could not convert opendocument") Right
89+ either (\_ -> Left $ PandocParseError "Could not convert opendocument") Right
8990 (runConverter' read_body startState contentElem)
9091
9192
9293--
93−entryToXmlElem :: Entry -> Maybe XML.Element
94−entryToXmlElem = XML.parseXMLDoc . UTF8.toStringLazy . fromEntry
94+entryToXmlElem :: Entry -> Either PandocError XML.Element
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)
5555import Text.Pandoc.Writers.HTML (writeHtmlStringForEPUB)
5656import Text.Printf (printf)
5757import Text.XML.Light (Attr (..), Element (..), Node (..), QName (..),
58− add_attrs, lookupAttr, node, onlyElems, parseXML,
58+ add_attrs, lookupAttr, node, onlyElems,
5959 ppElement, showElement, strContent, unode, unqual)
60+import Text.Pandoc.XMLParser (parseXMLContents)
6061import Text.Pandoc.XML (escapeStringForXML)
6162import Text.DocTemplates (FromContext(lookupContext), Context(..),
6263 ToContext(toVal), Val(..))
@@ -160,7 +161,12 @@ mkEntry path content = do
160161getEPUBMetadata :: PandocMonad m => WriterOptions -> Meta -> E m EPUBMetadata
161162getEPUBMetadata opts meta = do
162163 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)
164170 let md' = foldr addMetadataFromXML md elts
165171 let addIdentifier m =
166172 if null (epubIdentifier m)
@@ -836,7 +842,8 @@ pandocToEPUB version opts doc = do
836842 : case subs of
837843 [] -> []
838844 (_:_) -> [unode "ol" ! [("class","toc")] $ subs]
839− where titElements = parseXML titRendered
845+ where titElements = either (const []) id $
846+ parseXMLContents (TL.fromStrict titRendered)
840847 titRendered = case P.runPure
841848 (writeHtmlStringForEPUB version
842849 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:
1919module Text.Pandoc.Writers.FB2 (writeFB2) where
2020
2121import Control.Monad (zipWithM)
22−import Control.Monad.Except (catchError)
22+import Control.Monad.Except (catchError, throwError)
2323import Control.Monad.State.Strict (StateT, evalStateT, get, gets, lift, liftM, modify)
2424import Data.ByteString.Base64 (encode)
2525import Data.Char (isAscii, isControl, isSpace)
@@ -27,16 +27,18 @@ import Data.Either (lefts, rights)
2727import Data.List (intercalate)
2828import Data.Text (Text, pack)
2929import qualified Data.Text as T
30+import qualified Data.Text.Lazy as TL
3031import qualified Data.Text.Encoding as TE
3132import Network.HTTP (urlEncode)
3233import Text.XML.Light
3334import qualified Text.XML.Light as X
3435import qualified Text.XML.Light.Cursor as XC
35−import qualified Text.XML.Light.Input as XI
36+import Text.Pandoc.XMLParser (parseXMLContents)
3637
3738import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
3839import qualified Text.Pandoc.Class.PandocMonad as P
3940import Text.Pandoc.Definition
41+import Text.Pandoc.Error (PandocError(..))
4042import Text.Pandoc.Logging
4143import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..), def)
4244import Text.Pandoc.Shared (capitalize, isURI, orderedListMarkers,
@@ -307,7 +309,10 @@ blockToXml (CodeBlock _ s) = return . spaceBeforeAfter .
307309 map (el "p" . el "code" . T.unpack) . T.lines $ s
308310blockToXml (RawBlock f str) =
309311 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
311316 else return []
312317blockToXml (Div _ bs) = cMapM blockToXml bs
313318blockToXml (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.
1313-}
1414module Text.Pandoc.Writers.ODT ( writeODT ) where
1515import Codec.Archive.Zip
16−import Control.Monad.Except (catchError)
16+import Control.Monad.Except (catchError, throwError)
1717import Control.Monad.State.Strict
1818import qualified Data.ByteString.Lazy as B
1919import Data.Generics (everywhere', mkT)
@@ -27,6 +27,7 @@ import Text.Pandoc.BCP47 (Lang (..), getLang, renderLang)
2727import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang)
2828import qualified Text.Pandoc.Class.PandocMonad as P
2929import Text.Pandoc.Definition
30+import Text.Pandoc.Error (PandocError(..))
3031import Text.Pandoc.ImageSize
3132import Text.Pandoc.Logging
3233import Text.Pandoc.MIME (extensionFromMimeType, getMimeType)
@@ -35,10 +36,11 @@ import Text.DocLayout
3536import Text.Pandoc.Shared (stringify, pandocVersion, tshow)
3637import Text.Pandoc.Writers.Shared (lookupMetaString, lookupMetaBlocks,
3738 fixDisplayMath)
38−import Text.Pandoc.UTF8 (fromStringLazy, fromTextLazy, toStringLazy)
39+import Text.Pandoc.UTF8 (fromStringLazy, fromTextLazy, toTextLazy)
3940import Text.Pandoc.Walk
4041import Text.Pandoc.Writers.OpenDocument (writeOpenDocument)
4142import Text.Pandoc.XML
43+import Text.Pandoc.XMLParser (parseXMLElement)
4244import Text.TeXMath
4345import Text.XML.Light
4446
@@ -172,17 +174,18 @@ updateStyleWithLang :: PandocMonad m => Maybe Lang -> Archive -> O m Archive
172174updateStyleWithLang Nothing arch = return arch
173175updateStyleWithLang (Just lang) arch = do
174176 epochtime <- floor `fmap` lift P.getPOSIXTime
175− return arch{ zEntries = [if eRelativePath e == "styles.xml"
176− then case parseXMLDoc
177− (toStringLazy (fromEntry e)) of
178− Nothing -> e
179− Just d ->
180− toEntry "styles.xml" epochtime
181− ( fromStringLazy
182− . ppTopElement
183− . addLang lang $ d )
184− else e
185− | e <- zEntries arch] }
177+ entries <- mapM (\e -> if eRelativePath e == "styles.xml"
178+ then case parseXMLElement
179+ (toTextLazy (fromEntry e)) of
180+ Left msg -> throwError $
181+ PandocXMLError "styles.xml" msg
182+ Right d -> return $
183+ toEntry "styles.xml" epochtime
184+ ( fromStringLazy
185+ . ppTopElement
186+ . addLang lang $ d )
187+ else return e) (zEntries arch)
188+ return arch{ zEntries = entries }
186189
187190addLang :: Lang -> Element -> Element
188191addLang lang = everywhere' (mkT updateLangAttr)
src/Text/Pandoc/Writers/OOXML.hs+5−4
@@ -35,6 +35,7 @@ import qualified Data.Text as T
3535import Text.Pandoc.Class.PandocMonad (PandocMonad)
3636import qualified Text.Pandoc.UTF8 as UTF8
3737import Text.XML.Light as XML
38+import Text.Pandoc.XMLParser (parseXMLElement)
3839
3940mknode :: Node t => String -> [(String,String)] -> t -> Element
4041mknode s attrs =
@@ -62,10 +63,10 @@ parseXml refArchive distArchive relpath =
6263 findEntryByPath relpath distArchive of
6364 Nothing -> throwError $ PandocSomeError $
6465 T.pack relpath <> " missing in reference file"
65− Just e -> case parseXMLDoc . UTF8.toStringLazy . fromEntry $ e of
66− Nothing -> throwError $ PandocSomeError $
67− T.pack relpath <> " corrupt in reference file"
68− Just d -> return d
66+ Just e -> case parseXMLElement . UTF8.toTextLazy . fromEntry $ e of
67+ Left msg ->
68+ throwError $ PandocXMLError (T.pack relpath) msg
69+ Right d -> return d
6970
7071-- Copied from Util
7172
src/Text/Pandoc/Writers/Powerpoint/Output.hs+3−1
@@ -29,6 +29,7 @@ import Data.Time.Clock (UTCTime)
2929import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds, posixSecondsToUTCTime)
3030import System.FilePath.Posix (splitDirectories, splitExtension, takeExtension)
3131import Text.XML.Light
32+import Text.Pandoc.XMLParser (parseXMLElement)
3233import Text.Pandoc.Definition
3334import qualified Text.Pandoc.UTF8 as UTF8
3435import Text.Pandoc.Class.PandocMonad (PandocMonad)
@@ -77,7 +78,8 @@ getPresentationSize :: Archive -> Archive -> Maybe (Integer, Integer)
7778getPresentationSize refArchive distArchive = do
7879 entry <- findEntryByPath "ppt/presentation.xml" refArchive `mplus`
7980 findEntryByPath "ppt/presentation.xml" distArchive
80− presElement <- parseXMLDoc $ UTF8.toStringLazy $ fromEntry entry
81+ presElement <- either (const Nothing) return $
82+ parseXMLElement $ UTF8.toTextLazy $ fromEntry entry
8183 let ns = elemToNameSpaces presElement
8284 sldSize <- findChild (elemName ns "p" "sldSz") presElement
8385 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"
8888 "<p>\n\
8989 \ <inline-formula><alternatives>\n\
9090 \ <tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\
91+ \ </alternatives></inline-formula>\n\
9192 \</p>"
9293 =?> para (math "\\sigma|_{\\{x\\}}")
9394 , test jats "math ml only" $
test/command/5321.md+2−2
@@ -4,7 +4,7 @@
44 <caption>
55 <p>bar</p>
66 </caption>
7− <graphic xlink:href="foo.png" xlink:alt-text="baz">
7+ <graphic xlink:href="foo.png" xlink:alt-text="baz" />
88</fig>
99^D
1010[Para [Image ("fig-1",[],[]) [Str "bar"] ("foo.png","fig:")]]
@@ -17,7 +17,7 @@
1717 <title>foo</title>
1818 <p>bar</p>
1919 </caption>
20− <graphic xlink:href="foo.png" xlink:alt-text="baz">
20+ <graphic xlink:href="foo.png" xlink:alt-text="baz" />
2121</fig>
2222^D
2323[Para [Image ("fig-1",[],[]) [Str "foo",LineBreak,Str "bar"] ("foo.png","fig:")]]
test/docbook-reader.docbook+6−1
@@ -1,6 +1,11 @@
11<?xml version="1.0" encoding="utf-8" ?>
22<!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+]>
49<article>
510 <articleinfo>
611 <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"])]})
22[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."]
33,Header 1 ("headers",[],[]) [Str "Headers"]
44,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 @@
2020 <surname>MacFarlane</surname>
2121 <given-names>John</given-names>
2222 </name>
23+ </contrib>
2324 <contrib contrib-type="author">
2425 <name>
2526 <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.