Complex parsing of arguments in new environments
Here's an implementation with LaTeX3 macros.
\documentclass{article}
\usepackage{longtable}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentEnvironment{invoicetable}{mm} % #1 = columns, #2 = column names
{
\travers_invoicetable:n { #2 }
}
{
\begin{longtable}{#1}
\l_travers_tablehead_tl
\hline
\endhead
\l_travers_table_tl
\end{longtable}
}
\NewDocumentCommand{\theading}{m}
{
\travers_makeline:Nn \l_travers_tablehead_tl { #1 }
}
\NewDocumentCommand{\tline}{m}
{
\travers_makeline:Nn \l_travers_table_tl { #1 }
}
\tl_new:N \l_travers_tablehead_tl
\tl_new:N \l_travers_table_tl
\tl_new:N \l__travers_linetemp_tl
\tl_new:N \l_travers_lastcol_tl
\seq_new:N \l_travers_colnames_seq
%%% what to do with unknown keys
\keys_define:nn { travers/invoice }
{
unknown .code:n =
}
% absorb the list of column names and define the keys
\cs_new_protected:Npn \travers_invoicetable:n #1
{
\seq_set_split:Nnn \l_travers_colnames_seq { , } { #1 }
\seq_map_inline:Nn \l_travers_colnames_seq
{
\keys_define:nn { travers/invoice }
{
##1 .tl_set:c = { l__travers_name_##1_tl }
}
}
% detach the last column
\seq_pop_right:NN \l_travers_colnames_seq \l_travers_lastcol_tl
}
% each line processes the key-value pairs and adds to the table
\cs_new_protected:Npn \travers_makeline:Nn #1 #2
{
\tl_clear:N \l__travers_linetemp_tl
\keys_set:nn { travers/invoice } { #2 }
\seq_map_inline:Nn \l_travers_colnames_seq
{
\tl_put_right:Nv \l__travers_linetemp_tl { l__travers_name_##1_tl }
\tl_put_right:Nn \l__travers_linetemp_tl { & }
}
\tl_put_right:Nv \l__travers_linetemp_tl { l__travers_name_\l_travers_lastcol_tl _tl }
\tl_put_right:Nn \l__travers_linetemp_tl { \\ }
\tl_put_right:NV #1 \l__travers_linetemp_tl
}
\cs_generate_variant:Nn \tl_put_right:Nn { Nv }
\ExplSyntaxOff
\begin{document}
\begin{invoicetable}{r|llr|r}{
runningnumber,
description,
qty,
sellprice,
linetotal
}
\theading{
runningnumber=\#,
partnumber=Part number,
description=Description,
qty=Qty,
sellprice=Price,
linetotal=Total
}
\tline{
runningnumber=1,
partnumber=A-12232,
description={Test part, some data},
qty=4,
sellprice=14.99,
linetotal=59.96
}
\end{invoicetable}
\begin{invoicetable}{r|llrr|r}{
runningnumber,
partnumber,
description,
qty,
sellprice,
linetotal
}
\theading{
runningnumber=\#,
partnumber=Part number,
description=Description,
qty=Qty,
sellprice=Price,
linetotal=Total
}
\tline{
runningnumber=1,
partnumber=A-12232,
description={Test part, some data},
qty=4,
sellprice=14.99,
linetotal=59.96
}
\end{invoicetable}
\begin{invoicetable}{r}{
linetotal
}
\theading{
runningnumber=\#,
partnumber=Part number,
description=Description,
qty=Qty,
sellprice=Price,
linetotal=Total
}
\tline{
runningnumber=1,
partnumber=A-12232,
description={Test part, some data},
qty=4,
sellprice=14.99,
linetotal=59.96
}
\end{invoicetable}
\end{document}
Here is a solution involving xtring
:
\documentclass{article}
\usepackage{xstring,longtable}
\makeatletter
\def\line#1{%
\global\let\tab@keys@i\tab@keys
\gdef\line@content{#1,}%
\line@i
}
\def\line@i{%
\StrCut\tab@keys@i,\current@key\tab@keys@i
\global\let\tab@keys@i\tab@keys@i
\IfSubStr\line@content\current@key
{\StrBehind\line@content\current@key[\current@key]%
\StrBetween\current@key=,%
}
\relax
\ifx\@empty\tab@keys@i\\%
\else&\expandafter\line@i
\fi
}
\def\heading#1{\line{#1}\endhead}
\newenvironment{invoicetable}[2]%
{\edef\tab@keys{#2,}%
\expandarg\noexploregroups
\longtable{#1}%
}
\endlongtable
\makeatother
\begin{document}
\begin{invoicetable}{r|llrr|r}{runningnumber,description,qty,sellprice,linetotal}
\heading{runningnumber=\#,partnumber=Partnumber,description=Description,qty=Qty,sellprice=Price,linetotal=Total}
\line{runningnumber=1,partnumber=A-12232,description={Test part, some data},qty=4,sellprice=14.99,linetotal=59.96}
\end{invoicetable}
\end{document}