git.iko.soy/typeable/pandoc
on master help sign in
JATS writer: properly handle footnotes.

"Best Practice: When footnotes are grouped at the end of an article, wrap them in a `<fn-group>` and use an `<xref>` element in the text, as usual, to tie each footnote in the list to a particular location in the text." Closes #5511.

commite87b54dcad5e37133bc0f4cfc8039e9fd0dd1b4e authorJohn MacFarlane <jgm@berkeley.edu> dateThu 16 May 2019, 21:39 (7 years ago) parent2e13c0a
3 files changed+56−31
src/Text/Pandoc/Writers/JATS.hs+24−7 test/Tests/Writers/JATS.hs+1−3 test/writer.jats+31−21
src/Text/Pandoc/Writers/JATS.hs+24−7
@@ -16,6 +16,7 @@ https://jats.nlm.nih.gov/publishing/tag-library
1616module Text.Pandoc.Writers.JATS ( writeJATS ) where
1717import Prelude
1818import Control.Monad.Reader
19+import Control.Monad.State
1920import Data.Char (toLower)
2021import Data.Generics (everywhere, mkT)
2122import Data.List (isSuffixOf, partition, isPrefixOf)
@@ -39,11 +40,16 @@ import qualified Text.XML.Light as Xml
3940data JATSVersion = JATS1_1
4041 deriving (Eq, Show)
4142
42−type JATS = ReaderT JATSVersion
43+data JATSState = JATSState
44+ { jatsNotes :: [(Int, Doc)] }
45+
46+type JATS a = StateT JATSState (ReaderT JATSVersion a)
4347
4448writeJATS :: PandocMonad m => WriterOptions -> Pandoc -> m Text
4549writeJATS opts d =
46− runReaderT (docToJATS opts d) JATS1_1
50+ runReaderT (evalStateT (docToJATS opts d)
51+ (JATSState{ jatsNotes = [] }))
52+ JATS1_1
4753
4854-- | Convert Pandoc document to string in JATS format.
4955docToJATS :: PandocMonad m => WriterOptions -> Pandoc -> JATS m Text
@@ -52,7 +58,7 @@ docToJATS opts (Pandoc meta blocks) = do
5258 isBackBlock _ = False
5359 let (backblocks, bodyblocks) = partition isBackBlock blocks
5460 let elements = hierarchicalize bodyblocks
55− let backElements = hierarchicalize backblocks
61+ let backElements = hierarchicalize $ backblocks
5662 let colwidth = if writerWrapText opts == WrapAuto
5763 then Just $ writerColumns opts
5864 else Nothing
@@ -77,8 +83,10 @@ docToJATS opts (Pandoc meta blocks) = do
7783 meta
7884 main <- (render' . vcat) <$>
7985 mapM (elementToJATS opts' startLvl) elements
80− back <- (render' . vcat) <$>
81− mapM (elementToJATS opts' startLvl) backElements
86+ notes <- reverse . map snd <$> gets jatsNotes
87+ backs <- mapM (elementToJATS opts' startLvl) backElements
88+ let fns = inTagsIndented "fn-group" $ vcat notes
89+ let back = render' $ vcat backs $$ fns
8290 let context = defField "body" main
8391 $ defField "back" back
8492 $ defField "mathml" (case writerHTMLMathMethod opts of
@@ -368,9 +376,18 @@ inlineToJATS _ Space = return space
368376inlineToJATS opts SoftBreak
369377 | writerWrapText opts == WrapPreserve = return cr
370378 | otherwise = return space
371−inlineToJATS opts (Note contents) =
379+inlineToJATS opts (Note contents) = do
372380 -- TODO technically only <p> tags are allowed inside
373− inTagsIndented "fn" <$> blocksToJATS opts contents
381+ notes <- gets jatsNotes
382+ let notenum = case notes of
383+ (n, _):_ -> n + 1
384+ [] -> 1
385+ thenote <- inTags True "fn" [("id","fn" ++ show notenum)]
386+ <$> blocksToJATS opts contents
387+ modify $ \st -> st{ jatsNotes = (notenum, thenote) : notes }
388+ return $ inTags False "xref" [("ref-type", "fn"),
389+ ("rid", "fn" ++ show notenum)]
390+ $ text (show notenum)
374391inlineToJATS opts (Cite _ lst) =
375392 -- TODO revisit this after examining the jats.csl pipeline
376393 inlinesToJATS opts lst
test/Tests/Writers/JATS.hs+1−3
@@ -86,9 +86,7 @@ tests = [ testGroup "inline code"
8686 headerWith ("foo",["unnumbered"],[]) 1
8787 (text "Header 1" <> note (plain $ text "note")) =?>
8888 "<sec id=\"foo\">\n\
89− \ <title>Header 1<fn>\n\
90− \ <p>note</p>\n\
91− \ </fn></title>\n\
89+ \ <title>Header 1<xref ref-type=\"fn\" rid=\"fn1\">1</xref></title>\n\
9290 \</sec>"
9391 , "unnumbered sub header" =:
9492 headerWith ("foo",["unnumbered"],[]) 1
test/writer.jats+31−21
@@ -844,38 +844,48 @@ These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
844844</sec>
845845<sec id="footnotes">
846846 <title>Footnotes</title>
847− <p>Here is a footnote reference,<fn>
847+ <p>Here is a footnote reference,<xref ref-type="fn" rid="fn1">1</xref> and
848+ another.<xref ref-type="fn" rid="fn2">2</xref> This should
849+ <italic>not</italic> be a footnote reference, because it contains a
850+ space.[^my note] Here is an inline
851+ note.<xref ref-type="fn" rid="fn3">3</xref></p>
852+ <disp-quote>
853+ <p>Notes can go in quotes.<xref ref-type="fn" rid="fn4">4</xref></p>
854+ </disp-quote>
855+ <list list-type="order">
856+ <list-item>
857+ <p>And in list items.<xref ref-type="fn" rid="fn5">5</xref></p>
858+ </list-item>
859+ </list>
860+ <p>This paragraph should not be part of the note, as it is not indented.</p>
861+</sec>
862+</body>
863+<back>
864+<fn-group>
865+ <fn id="fn1">
848866 <p>Here is the footnote. It can go anywhere after the footnote reference.
849867 It need not be placed at the end of the document.</p>
850− </fn> and another.<fn>
868+ </fn>
869+ <fn id="fn2">
851870 <p>Here’s the long note. This one contains multiple blocks.</p>
852871 <p>Subsequent blocks are indented to show that they belong to the footnote
853872 (as with list items).</p>
854873 <preformat> { &lt;code&gt; }</preformat>
855874 <p>If you want, you can indent every line, but you can also be lazy and
856875 just indent the first line of each block.</p>
857− </fn> This should <italic>not</italic> be a footnote reference, because it
858− contains a space.[^my note] Here is an inline note.<fn>
876+ </fn>
877+ <fn id="fn3">
859878 <p>This is <italic>easier</italic> to type. Inline notes may contain
860879 <ext-link ext-link-type="uri" xlink:href="http://google.com">links</ext-link>
861880 and <monospace>]</monospace> verbatim characters, as well as [bracketed
862881 text].</p>
863− </fn></p>
864− <disp-quote>
865− <p>Notes can go in quotes.<fn>
866− <p>In quote.</p>
867− </fn></p>
868− </disp-quote>
869− <list list-type="order">
870− <list-item>
871− <p>And in list items.<fn>
872− <p>In list.</p>
873− </fn></p>
874− </list-item>
875− </list>
876− <p>This paragraph should not be part of the note, as it is not indented.</p>
877−</sec>
878−</body>
879−<back>
882+ </fn>
883+ <fn id="fn4">
884+ <p>In quote.</p>
885+ </fn>
886+ <fn id="fn5">
887+ <p>In list.</p>
888+ </fn>
889+</fn-group>
880890</back>
881891</article>