Authors and affiliations schema exposed to Quarto Lua API #2715
-
Hi, Does Quarto expose the normalized and de-normalized authors and affiliations to Lua such that it is usable by Lua filters? Based on https://quarto.org/docs/journals/authors.html it seems like those authors and affiliation schema are only usable for LaTeX. I am trying to write a Lua filter to create author lists and affiliation lists for Word document format, and having access to Thoughts? |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 25 replies
-
Yes it does - they are available in LUA filters and in any template (e.g. they are used in our HTML title blocks as well). Please give it a try and let us know if you run into issue - the goal is very much to support scenario like you're describing (allowing you to write author and affiliation processing for output without having to worry about the input structure)! |
Beta Was this translation helpful? Give feedback.
-
You are completely correct and great detective work - we are currently filtering on output type (which I'm not sure is a good idea any longer, especially as we continue to make our format output more flexible and extensible). I'm taking a look at changing this now so we process author metadata without regard to the specified format (with the exception of markdown output, which I think we should continue to leave untransformed). |
Beta Was this translation helpful? Give feedback.
-
In case anyone stumbles upon this Discussion because they too are trying to have authors and affiliations work consistently across Word and PDF academic manuscripts destined for peer-review, this is my start on a Lua filter for exactly that. I'm sure it could be improved in many ways as I am new to programming in Lua. But for now, this works. I took inspiration from: https://github.com/pandoc/lua-filters/tree/master/author-info-blocks and from the suggestions of @dragonstyle. local List = require 'pandoc.List'
local utils = require 'pandoc.utils'
local stringify = utils.stringify
local byAuthor
local byAffiliation
local Authors = {}
local Affiliations = {}
local Corresponding
local equalCont
local authorHoriz
local function make_correspondance(name, email)
correspondance = List:new{
pandoc.Str('* Corresponding Author: '),
pandoc.Str(name),
pandoc.Str(' ('),
pandoc.Link(email, 'mailto:' .. email),
pandoc.Str(')')
}
Corresponding = List:new{pandoc.Span(correspondance)}
end
local function make_equal_contributor()
eq_statement = pandoc.Str('† These authors contributed equally to this work.')
equalCont = List:new{pandoc.Span(eq_statement)}
end
local function create_author_list(byAuthor)
local authors = {}
for i,author in ipairs(byAuthor) do
local sups = {}
for j,aff in ipairs(author.affiliations) do
table.insert(sups, aff.number)
end
sups_str = table.concat(sups, ',')
local name = stringify(author.name.literal)
if author.attributes ~= nil then
if author.attributes.equal ~= nil and author.attributes.equal then
sups_str = sups_str .. '†'
make_equal_contributor()
end
if author.attributes.corresponding ~= nil and author.attributes.corresponding then
local email = stringify(author.email)
sups_str = sups_str .. '*'
make_correspondance(name, email)
end
end
local authorEntry = List:new{
pandoc.Str(name),
pandoc.Superscript(pandoc.Str(sups_str))
}
if authorHoriz then
authorEntry:extend({pandoc.Str(', ')})
end
table.insert(authors, pandoc.Span(authorEntry))
end
if authorHoriz then
Authors = {pandoc.Para(authors)}
else
Authors = authors
end
end
local function create_affiliation_list(byAffiliation)
for i,aff in ipairs(byAffiliation) do
local number = stringify(aff.number)
local name = stringify(aff.name)
local address = stringify(aff.address)
local city = stringify(aff.city)
local region = stringify(aff.region)
local country = stringify(aff.country)
local full_aff = {name, address, city, region, country}
local entry = table.concat(full_aff, ', ')
entry = number .. '. ' .. entry
table.insert(Affiliations, pandoc.Span(pandoc.Str(entry)))
end
end
local function remove_author_meta(meta)
meta.author = nil
meta.authors = nil
meta.affiliations = nil
meta['by-author'] = nil
meta['by-affiliation'] = nil
return meta
end
return {
{
Meta = function(meta)
byAuthor = meta['by-author']
byAffiliation = meta['by-affiliation']
if meta['author-horizontal'] ~= nil then
authorHoriz = meta['author-horizontal']
else
authorHoriz = false
end
create_author_list(byAuthor)
create_affiliation_list(byAffiliation)
return meta
end
},
{
Pandoc = function(doc)
local meta = doc.meta
local body = List:new{}
body:extend(Authors)
body:extend(Affiliations)
body:extend(equalCont)
body:extend(Corresponding)
body:extend(doc.blocks)
meta = remove_author_meta(meta)
return pandoc.Pandoc(body, meta)
end
}
} |
Beta Was this translation helpful? Give feedback.
-
It is exactly what I need. Is it possible to adapt this
---
title: Test Document
author:
- name: Norah Jones
email: [email protected]
affiliations:
- ref: aff1
- ref: aff2
affiliations:
- id: aff1
name: Blue Note Records
- id: aff2
name: Green Note Records
filters:
- test.lua
format:
docx: default
html: default
---
## This is a test
Currently, with the code above, I got error as shown below.
Here is the local List = require 'pandoc.List'
local utils = require 'pandoc.utils'
local stringify = utils.stringify
local byAuthor
local byAffiliation
local Authors = {}
local Affiliations = {}
local Corresponding
local equalCont
local authorHoriz
local function make_correspondance(name, email)
correspondance = List:new{
pandoc.Str('* Corresponding Author: '),
pandoc.Str(name),
pandoc.Str(' ('),
pandoc.Link(email, 'mailto:' .. email),
pandoc.Str(')')
}
Corresponding = List:new{pandoc.Span(correspondance)}
end
local function make_equal_contributor()
eq_statement = pandoc.Str('† These authors contributed equally to this work.')
equalCont = List:new{pandoc.Span(eq_statement)}
end
local function create_author_list(byAuthor)
local authors = {}
for i,author in ipairs(byAuthor) do
local sups = {}
for j,aff in ipairs(author.affiliations) do
table.insert(sups, aff.number)
end
sups_str = table.concat(sups, ',')
local name = stringify(author.name.literal)
if author.attributes ~= nil then
if author.attributes.equal ~= nil and author.attributes.equal then
sups_str = sups_str .. '†'
make_equal_contributor()
end
if author.attributes.corresponding ~= nil and author.attributes.corresponding then
local email = stringify(author.email)
sups_str = sups_str .. '*'
make_correspondance(name, email)
end
end
local authorEntry = List:new{
pandoc.Str(name),
pandoc.Superscript(pandoc.Str(sups_str))
}
if authorHoriz then
authorEntry:extend({pandoc.Str(', ')})
end
table.insert(authors, pandoc.Span(authorEntry))
end
if authorHoriz then
Authors = {pandoc.Para(authors)}
else
Authors = authors
end
end
local function create_affiliation_list(byAffiliation)
for i,aff in ipairs(byAffiliation) do
local number = stringify(aff.number)
local name = stringify(aff.name)
local address = stringify(aff.address)
local city = stringify(aff.city)
local region = stringify(aff.region)
local country = stringify(aff.country)
local full_aff = {name, address, city, region, country}
local entry = table.concat(full_aff, ', ')
entry = number .. '. ' .. entry
table.insert(Affiliations, pandoc.Span(pandoc.Str(entry)))
end
end
local function remove_author_meta(meta)
meta.author = nil
meta.authors = nil
meta.affiliations = nil
meta['by-author'] = nil
meta['by-affiliation'] = nil
return meta
end
return {
{
Meta = function(meta)
byAuthor = meta['by-author']
byAffiliation = meta['by-affiliation']
if meta['author-horizontal'] ~= nil then
authorHoriz = meta['author-horizontal']
else
authorHoriz = false
end
create_author_list(byAuthor)
create_affiliation_list(byAffiliation)
return meta
end
},
{
Pandoc = function(doc)
local meta = doc.meta
local body = List:new{}
body:extend(Authors)
body:extend(Affiliations)
body:extend(equalCont)
body:extend(Corresponding)
body:extend(doc.blocks)
meta = remove_author_meta(meta)
return pandoc.Pandoc(body, meta)
end
}
}
|
Beta Was this translation helpful? Give feedback.
-
Hi @mattwarkentin, To provide a simple reprex and demo of the issue, I'll use your first, create an empty Quarto project and then install the extension with:
Then, copy your
When I render to docx, I get the following (docx on left, pdf on right): Expectations would be for the author/affiliation information to appear immediately after the Title and before the Table of Contents. Additionally, the MS Word style associated with line 10 ("Matthew T. Warkentin") is 'First Paragraph' and the remaining author/affiliation information is 'Body Text'. This means any MS Word style specified for 'Author' in the reference/template docx isn't applied to the author/affiliation text. And, any style information specified for 'First Paragraph' might cause issues. I think you might be on to something with your statement that Lua filter above places the authors and affiliations as the first thing in the body and before the rest of the existing content (doc.blocks). This is exactly what's happening. So the Title and Table of Contents must be contained outside the 'body' and in some other section that represents the title block. Seems there must be a way to access the title block so the author/affiliation data is inserted in that section instead of in the body. Similarly, seems we'd want to make sure style tag/labels are properly associated with the content. |
Beta Was this translation helpful? Give feedback.
Yes it does - they are available in LUA filters and in any template (e.g. they are used in our HTML title blocks as well). Please give it a try and let us know if you run into issue - the goal is very much to support scenario like you're describing (allowing you to write author and affiliation processing for output without having to worry about the input structure)!