Why is this CSV form letter code incompatable with the table of contents in ConTeXt?
Using the code in the answer to How to create form letters from spreadsheet data in ConTeXt?, I am building a document from data in a CSV file. I found that some part of the code is incomparable with chapter titles, such that, if I add a table of contents using \completecontent or add headers using \getmarkings{chapter}, it will not compile.
% macros=mkvi
\unprotect
\startluacode
local datasets = { }
local buffersraw = buffers.raw
local context = context
local ioloaddata = io.loaddata
local lpegmatch = lpeg.match
local stringformat = string.format
local stringmatch = string.match
local stringsub = string.sub
local tableconcat = table.concat
local tableswapped = table.swapped
local die = function (msg) print(msg or "ERROR") os.exit(1) end
local csv_parser
do
--- This is (more than) an RFC 4180 parser.
--- http://tools.ietf.org/html/rfc4180
local C, Cg, Cs, Ct, P, S, V
= lpeg.C, lpeg.Cg, lpeg.Cs, lpeg.Ct, lpeg.P, lpeg.S, lpeg.V
local backslash = P[[\letterbackslash]]
local comma = ","
local dquote = P[["]]
local eol = S"\n\r"^1
local noquote = 1 - dquote
local unescape = function (s) return stringsub(s, 2) end
csv_parser = P{
"file",
file = Ct((V"header" * eol)^-1 * V"records"),
header = Cg(Ct(V"name" * (comma * V"name")^0), "header"),
records = V"record" * (eol * V"record")^0 * eol^0,
record = Ct(V"field" * (comma * V"field")^0),
name = V"field",
field = V"escaped" + V"non_escaped",
--- Deviate from rfc: the “textdata” terminal was defined only
--- for 7bit ASCII. Also, any character may occur in a quoted
--- field as long as it is escaped with a backslash. (\TEX\
--- macros start with two backslashes.)
escaped = dquote
* Cs(((backslash * 1 / unescape) + noquote)^0)
* dquote
,
non_escaped = C((1 - dquote - eol - comma)^0),
}
end
local process = function (id, raw)
--- buffers may have trailing EOLs
raw = stringmatch(raw, "^[\n\r]*(.-)[\n\r]*$")
local data = lpegmatch(csv_parser, raw)
--- map column name -> column nr
data.header = tableswapped(data.header)
datasets[id] = data
end
--- escaping hell ahead, please ignore.
local s_item = [[
\bgroup
\string\def\string\insert{\string\getvalue{csv_insert_field}{%s}{%s}}%%
%s%% template
\egroup
]]
local typeset = function (id, template)
local data = datasets[id] or die("ERROR unknown dataset: " .. id)
template = stringmatch(buffersraw(template), "^[\n\r]*(.-)[\n\r]*$")
local result = { }
local last = \letterhash data
for i=1, last do
result[i] = stringformat(s_item, id, i, template)
end
context(tableconcat(result))
end
local insert = function (id, n, field)
local this = datasets[id]
context(this[n][this.header[field]])
end
commands.process_csv = process
commands.process_csv_file = function (id, fname)
process(id, ioloaddata(fname, true))
end
commands.typeset_csv_job = typeset
commands
Using the code in the answer to How to create form letters from spreadsheet data in ConTeXt?, I am building a document from data in a CSV file. I found that some part of the code is incomparable with chapter titles, such that, if I add a table of contents using \completecontent or add headers using \getmarkings{chapter}, it will not compile.
% macros=mkvi
\unprotect
\startluacode
local datasets = { }
local buffersraw = buffers.raw
local context = context
local ioloaddata = io.loaddata
local lpegmatch = lpeg.match
local stringformat = string.format
local stringmatch = string.match
local stringsub = string.sub
local tableconcat = table.concat
local tableswapped = table.swapped
local die = function (msg) print(msg or "ERROR") os.exit(1) end
local csv_parser
do
--- This is (more than) an RFC 4180 parser.
--- http://tools.ietf.org/html/rfc4180
local C, Cg, Cs, Ct, P, S, V
= lpeg.C, lpeg.Cg, lpeg.Cs, lpeg.Ct, lpeg.P, lpeg.S, lpeg.V
local backslash = P[[\letterbackslash]]
local comma = ","
local dquote = P[["]]
local eol = S"\n\r"^1
local noquote = 1 - dquote
local unescape = function (s) return stringsub(s, 2) end
csv_parser = P{
"file",
file = Ct((V"header" * eol)^-1 * V"records"),
header = Cg(Ct(V"name" * (comma * V"name")^0), "header"),
records = V"record" * (eol * V"record")^0 * eol^0,
record = Ct(V"field" * (comma * V"field")^0),
name = V"field",
field = V"escaped" + V"non_escaped",
--- Deviate from rfc: the “textdata” terminal was defined only
--- for 7bit ASCII. Also, any character may occur in a quoted
--- field as long as it is escaped with a backslash. (\TEX\
--- macros start with two backslashes.)
escaped = dquote
* Cs(((backslash * 1 / unescape) + noquote)^0)
* dquote
,
non_escaped = C((1 - dquote - eol - comma)^0),
}
end
local process = function (id, raw)
--- buffers may have trailing EOLs
raw = stringmatch(raw, "^[\n\r]*(.-)[\n\r]*$")
local data = lpegmatch(csv_parser, raw)
--- map column name -> column nr
data.header = tableswapped(data.header)
datasets[id] = data
end
--- escaping hell ahead, please ignore.
local s_item = [[
\bgroup
\string\def\string\insert{\string\getvalue{csv_insert_field}{%s}{%s}}%%
%s%% template
\egroup
]]
local typeset = function (id, template)
local data = datasets[id] or die("ERROR unknown dataset: " .. id)
template = stringmatch(buffersraw(template), "^[\n\r]*(.-)[\n\r]*$")
local result = { }
local last = \letterhash data
for i=1, last do
result[i] = stringformat(s_item, id, i, template)
end
context(tableconcat(result))
end
local insert = function (id, n, field)
local this = datasets[id]
context(this[n][this.header[field]])
end
commands.process_csv = process
commands.process_csv_file = function (id, fname)
process(id, ioloaddata(fname, true))
end
commands.typeset_csv_job = typeset
commands
No comments:
Post a Comment