git.iko.soy/typeable/pandoc
on master help sign in
JATS reader: better citation handling.

We now convert a ref-list element into a list of citations in metadata, suitable for use with pandoc-citeproc. We also convert references to pandoc citation elements. Thus a JATS article with embedded bibliographic information can be processed with pandoc and pandoc-citeproc to produce a formatted bibliography.

commitdd399594531ad3496c5d471af886573a4c099d9f authorJohn MacFarlane <jgm@berkeley.edu> dateFri 22 Dec 2017, 19:01 (9 years ago) parente3c1449
1 file changed+79−3
src/Text/Pandoc/Readers/JATS.hs+79−3
src/Text/Pandoc/Readers/JATS.hs+79−3
@@ -5,6 +5,7 @@ import Data.Char (isDigit, isSpace, toUpper)
55import Data.Default
66import Data.Generics
77import Data.List (intersperse)
8+import qualified Data.Map as Map
89import Data.Maybe (maybeToList, fromMaybe)
910import Data.Text (Text)
1011import qualified Data.Text as T
@@ -189,8 +190,7 @@ parseBlock (Elem e) =
189190 "fig" -> divWith (attrValue "id" e, ["fig"], []) <$> getBlocks e
190191 "table-wrap" -> divWith (attrValue "id" e, ["table-wrap"], []) <$> getBlocks e
191192 "caption" -> divWith (attrValue "id" e, ["caption"], []) <$> sect 6
192− "ref-list" -> divWith ("refs", [], []) <$> getBlocks e
193− "ref" -> divWith ("ref-" <> attrValue "id" e, [], []) <$> getBlocks e
193+ "ref-list" -> parseRefList e
194194 "?xml" -> return mempty
195195 _ -> getBlocks e
196196 where parseMixed container conts = do
@@ -312,6 +312,74 @@ getInlines :: PandocMonad m => Element -> JATS m Inlines
312312getInlines e' = (trimInlines . mconcat) <$>
313313 mapM parseInline (elContent e')
314314
315+parseRefList :: PandocMonad m => Element -> JATS m Blocks
316+parseRefList e = do
317+ refs <- mapM parseRef $ filterChildren (named "ref") e
318+ addMeta "references" refs
319+ return mempty
320+
321+parseRef :: PandocMonad m
322+ => Element -> JATS m (Map.Map String MetaValue)
323+parseRef e = do
324+ let refId = text $ attrValue "id" e
325+ let getInlineText n = maybe (return mempty) getInlines . filterChild (named n)
326+ case filterChild (named "element-citation") e of
327+ Just c -> do
328+ let refType = text $
329+ case attrValue "publication-type" c of
330+ "journal" -> "article-journal"
331+ x -> x
332+ (refTitle, refContainerTitle) <- do
333+ t <- getInlineText "article-title" c
334+ ct <- getInlineText "source" c
335+ if t == mempty
336+ then return (ct, mempty)
337+ else return (t, ct)
338+ refLabel <- getInlineText "label" c
339+ refYear <- getInlineText "year" c
340+ refVolume <- getInlineText "volume" c
341+ refFirstPage <- getInlineText "fpage" c
342+ refLastPage <- getInlineText "lpage" c
343+ refPublisher <- getInlineText "publisher-name" c
344+ refPublisherPlace <- getInlineText "publisher-loc" c
345+ let refPages = refFirstPage <> (if refLastPage == mempty
346+ then mempty
347+ else text "\x2013" <> refLastPage)
348+ let personGroups' = filterElements (named "person-group") c
349+ let getName nm = do
350+ given <- maybe (return mempty) getInlines
351+ $ filterElement (named "given-names") nm
352+ family <- maybe (return mempty) getInlines
353+ $ filterElement (named "surname") nm
354+ return $ toMetaValue $ Map.fromList [
355+ ("given", given)
356+ , ("family", family)
357+ ]
358+ personGroups <- mapM (\pg ->
359+ do names <- mapM getName
360+ (filterElements (named "name") pg)
361+ return (attrValue "person-group-type" pg,
362+ toMetaValue names))
363+ personGroups'
364+ return $ Map.fromList $
365+ [ ("id", toMetaValue refId)
366+ , ("type", toMetaValue refType)
367+ , ("title", toMetaValue refTitle)
368+ , ("container-title", toMetaValue refContainerTitle)
369+ , ("publisher", toMetaValue refPublisher)
370+ , ("publisher-place", toMetaValue refPublisherPlace)
371+ , ("title", toMetaValue refTitle)
372+ , ("issued", toMetaValue
373+ $ Map.fromList [
374+ ("year", refYear)
375+ ])
376+ , ("volume", toMetaValue refVolume)
377+ , ("page", toMetaValue refPages)
378+ , ("citation-label", toMetaValue refLabel)
379+ ] ++ personGroups
380+ Nothing -> return $ Map.insert "id" (toMetaValue refId) mempty
381+ -- TODO handle mixed-citation
382+
315383strContentRecursive :: Element -> String
316384strContentRecursive = strContent .
317385 (\e' -> e'{ elContent = map elementToStr $ elContent e' })
@@ -354,7 +422,15 @@ parseInline (Elem e) =
354422 let rid = attrValue "rid" e
355423 let refType = ("ref-type",) <$> maybeAttrValue "ref-type" e
356424 let attr = (attrValue "id" e, [], maybeToList refType)
357− return $ linkWith attr ('#' : rid) "" ils
425+ return $ if refType == Just ("ref-type","bibr")
426+ then cite [Citation{
427+ citationId = rid
428+ , citationPrefix = []
429+ , citationSuffix = []
430+ , citationMode = NormalCitation
431+ , citationNoteNum = 0
432+ , citationHash = 0}] ils
433+ else linkWith attr ('#' : rid) "" ils
358434 "ext-link" -> do
359435 ils <- innerInlines
360436 let title = fromMaybe "" $ findAttr (QName "title" (Just "http://www.w3.org/1999/xlink") Nothing) e