以表格形式打印属性列表序列

以表格形式打印属性列表序列

我想定义两个宏,它们一起生成一张发票表。

  1. 将条目添加到序列。不生成任何输出。
% \addentry{description}{quantity}{price}
\addentry{Item 1}{5}{4.50}
\addentry{Item 2}{3}{12.00}
  1. 将所有条目打印为表格,即\printentries应扩展为
\begin{tabularx}{\textwidth}{Xrrr}
\toprule
Description & Quantity & Price & Amount \\
\midrule
Item 1 & 5 & 4.50 & 22.50 \\
Item 2 & 3 & 12.00 & 36.00 \\
\bottomrule
\end{tabularx}

目标

我迄今为止尝试过

\documentclass{article}

\usepackage{tabularx, booktabs}

\ExplSyntaxOn

\cs_generate_variant:Nn \seq_put_right:Nn {Ne}

\seq_new:N \l__entries_seq
\seq_new:N \l__formatted_entries_seq
\fp_new:N \l__entry_amount_fp
\prop_new:N \l__entry_prop

% \addentry{description}{quantity}{price}
\NewDocumentCommand\addentry{m m m}{
  % Calculate the total amount of this entry by multiplying quantity with price
  \fp_set:Nn \l__entry_amount_fp {#2 * #3}
  % Build the entry
  \prop_set_from_keyval:Nn \l__entry_prop {
    description={#1},
    quantity={#2},
    price={#3},
    amount={\fp_eval:n \l__entry_amount_fp}
  }
  % Add the entry to the sequence
  \seq_put_right:Ne \l__entries_seq{
    \prop_to_keyval:N \l__entry_prop % Serialize the property list representing the entry
  }
}

\NewDocumentCommand\printentries{}{
  % Map entries to their row representation (i.e., seperated by `&`) and temporarily store in `\l__formatted_entries_seq`
  \seq_set_map:NNn \l__formatted_entries_seq \l__entries_seq {
    \prop_set_from_keyval:Nn \l__entry_prop {##1} % Deserialize the property list representing the entry

    \prop_item:Nn \l__entry_prop {description} &
    \prop_item:Nn \l__entry_prop {quantity} &
    \prop_item:Nn \l__entry_prop {price} &
    \prop_item:Nn \l__entry_prop {amount}
  }
  
  % Generate the table
  \begin{tabularx}{\textwidth}{Xrrr}
  \toprule
  Description & Quantity & Price & Amount \\
  \midrule
  \seq_use:Nn \l__formatted_entries_seq { \\ } \\
  \bottomrule
  \end{tabularx}
}

\ExplSyntaxOff

\addentry{Item 1}{5}{4.50}
\addentry{Item 2}{3}{12.00}

\begin{document}
\printentries
\end{document}

奇怪的是,这给了我以下输出。“Description”似乎正确,但“Item 1”的其他列不正确。为什么这是错误的?

表输出

使用 2021 或更早版本的 Latex 用户须知

您可能需要将此添加到您的前言中,以便我的代码能够编译。将其添加到 行之后\ExplSyntaxOn

%%%% POLYFILL OF THE `\prop_to_keyval:N` MACRO FOR OLD TEX VERSION %%%%
\makeatletter
\cs_new:Npn \prop_to_keyval:N #1
      {
        \__kernel_exp_not:w
          \prop_if_empty:NTF #1
            { {} }
            {
              \exp_after:wN \exp_after:wN \exp_after:wN
              {
                \tex_expanded:D
                  {
                    \__kernel_exp_not:w { \use_none:n }
                    \prop_map_function:NN #1 \@@_to_keyval:nn
                  }
              }
            }
      }
    \cs_new:Npn \@@_to_keyval:nn #1#2
      { , ~ {#1} =~ { \__kernel_exp_not:w {#2} } }
\makeatother
%%%% END POLYFILL %%%%

答案1

我认为您不需要填充属性列表。只需逐步构建表主体即可。

\documentclass{article}
\usepackage{tabularx,booktabs}

\ExplSyntaxOn

\tl_new:N \g__safron_invoice_body_tl
\fp_new:N \g__safron_invoice_total_fp

\NewDocumentCommand{\addentry}{mmm}
 {
  \tl_gput_right:Nx \g__safron_invoice_body_tl
   {
    \exp_not:n { #1 } & #2 & #3 & \__safron_invoice_amount:e { \fp_eval:n { #2 * #3 } }
    \exp_not:N \\
   }
  \fp_gadd:Nn \g__safron_invoice_total_fp { #2 * #3 }
 }

\NewDocumentCommand{\printentries}{}
 {
  \noindent
  \begin{tabularx}{\textwidth}{Xrrr}
  \toprule
  Description & Quantity & Price & Amount \\
  \midrule
  \tl_use:N \g__safron_invoice_body_tl
  \midrule
  Total &&& \__safron_invoice_amount:e { \fp_use:N \g__safron_invoice_total_fp } \\
  \bottomrule
  \end{tabularx}
 }

\cs_new:Nn \__safron_invoice_amount:n
 {
  \__safron_invoice_amount:w #1 .. \q_stop
 }

\cs_new:Npn \__safron_invoice_amount:w #1 . #2 . #3 \q_stop
 {
  \tl_if_empty:nTF { #2 }
   { #1.00 }
   { #1.#2 \prg_replicate:nn { 2 - \tl_count:n { #2 } } { 0 } }
 }
\cs_generate_variant:Nn \__safron_invoice_amount:n { e }

\ExplSyntaxOff

\begin{document}

\addentry{Item 1}{5}{4.50}
\addentry{Item 2}{3}{12.00}

\printentries

\end{document}

在此处输入图片描述

答案2

egreg 已经提供了一个很棒的、可能更简单的解决方案。然而,当我试图更好地理解 expl3 时,我想知道如何调整你原来的方法,以便它输出正确的内容。

我认为,问题在于,在将事物作为键值实体存储在序列中之前,您需要对其进行扩展。例如,您需要扩展\fp_eval:n \l__entry_amount_fp,否则您将把这个宏序列存储在序列中,并且它只会在打印时扩展,并且始终输出最后一个值。(您可以使用\seq_show:N它将序列中的条目打印到日志中来检查这些内容。)

同样,您需要先扩展格式化的条目,然后再将它们添加到\l__formatted_entries_seq序列中。一种非常可靠的方法是使用\seq_put_right:Nx。您已经在宏的原始定义中使用了它的变体\addentry

\documentclass{article}

\usepackage{tabularx, booktabs}

\ExplSyntaxOn

\seq_new:N \l__entries_seq
\seq_new:N \l__formatted_entries_seq
\fp_new:N \l__entry_amount_fp
\prop_new:N \l__entry_prop

% \addentry{description}{quantity}{price}
\NewDocumentCommand\addentry{m m m}{
  % Calculate the total amount of this entry by multiplying quantity with price
  \fp_set:Nn \l__entry_amount_fp {#2 * #3}
  % Build the entry
  \prop_put:Nnx \l__entry_prop { description } {#1}
  \prop_put:Nnx \l__entry_prop { quantity } {#2}
  \prop_put:Nnx \l__entry_prop { price } {#3}
  \prop_put:Nnx \l__entry_prop { amount } { \fp_eval:n \l__entry_amount_fp }   % <-- !
  % Add the entry to the sequence
  \seq_put_right:Nx \l__entries_seq {
    \prop_to_keyval:N \l__entry_prop % Serialize the property list representing the entry
  }
}

\NewDocumentCommand\printentries{}{
  % Map entries to their row representation (i.e., seperated by `&`) and temporarily store in `\l__formatted_entries_seq`
  \seq_map_inline:Nn \l__entries_seq {
    \prop_set_from_keyval:Nn \l__entry_prop {##1} % Deserialize the property list representing the entry
    \seq_put_right:Nx \l__formatted_entries_seq {   % <-- !
      \prop_item:Nn \l__entry_prop {description} &
      \prop_item:Nn \l__entry_prop {quantity} &
      \prop_item:Nn \l__entry_prop {price} &
      \prop_item:Nn \l__entry_prop {amount}
    }
  }
  
  % Generate the table
  \begin{tabularx}{\textwidth}{Xrrr}
  \toprule
  Description & Quantity & Price & Amount \\
  \midrule
  \seq_use:Nn \l__formatted_entries_seq { \\ } \\
  \bottomrule
  \end{tabularx}
}

\ExplSyntaxOff

\addentry{Item 1}{5}{4.50}
\addentry{Item 2}{3}{12.00}

\begin{document}
\printentries
\end{document}

在此处输入图片描述

当然,输出的格式不如 egreg 的答案那么好......

相关内容