2

Based on the question How to generate summary table automatically?, I re-wrote the MWE:

\documentclass{article}
\usepackage{nameref}
\usepackage{booktabs}
\usepackage{xparse}
\ExplSyntaxOn
\prop_new:N \g__leonardo_impact_prop
\prop_new:N \g__leonardo_counter_prop
\makeatletter
\NewDocumentCommand \DeclareImpact { m +m +m }
  {
    \@bsphack
      \prop_gput:Nnn \g__leonardo_impact_prop {#1} {#2}
      \prop_gput:Nnn \g__leonardo_counter_prop {#1} {#3}
    \@esphack
  }
\makeatother
\NewExpandableDocumentCommand \impact { O{Not~applicable} m }
  {
    \prop_if_in:NnTF \g__leonardo_impact_prop {#2}
      { \prop_item:Nn \g__leonardo_impact_prop {#2} }
      { \exp_not:n {#1} }
  }
\NewExpandableDocumentCommand \countermeasure { O{Not~applicable} m }
  {
    \prop_if_in:NnTF \g__leonardo_counter_prop {#2}
      { \prop_item:Nn \g__leonardo_counter_prop {#2} }
      { \exp_not:n {#1} }
  }
%
\NewExpandableDocumentCommand \TableBody { m }
  { \clist_map_function:nN {#1} \__leonardo_table_row:n }
\NewDocumentCommand \SetRowFormat { m }
  { \cs_gset:Npn \__leonardo_table_row:n ##1 {#1} }
\cs_new_eq:NN \StrLowerCase \str_lowercase:n
\ExplSyntaxOff

\begin{document}

\section{Impacts on the Environment}
\subsection{Air quality}
\label{sec:air}
Analyses of air quality.
\DeclareImpact{Air}{Wood burning}{Sleeve filter installation}

\textbf{Impact}: \impact{Air}

\textbf{Countermeasure}: \countermeasure{Air}

\subsection{Water resources}
\label{sec:water}
Analyses of water resources.

\DeclareImpact{Water}{low pervious surface rate}{rain water harvesting}
\DeclareImpact{Water}{alkaline waste water}{ph correction water treatment process}

\textbf{Impact}: \impact{Water}


\textbf{Countermeasure}: \countermeasure{Water}


\section{Conclusion}
A succinct conclusion. See Table \ref{tab:sumary}.

% Set table row format:
\SetRowFormat
  {%
    \nameref{sec:\StrLowerCase{#1}}
  & \impact[--]{#1}
  & \countermeasure[--]{#1} \\
  }

\begin{table}[htb!]
  \centering
  \caption{Summary of impacts and countermeasures}
  \label{tab:sumary}
  \begin{tabular}{lll}
    \toprule
      \textbf{Analyse} & \textbf{Impact} & \textbf{Countermeasure}\\
    \midrule
        \TableBody{Air, Water}
    \bottomrule
  \end{tabular}
\end{table}

\end{document}

Is it possible to store more than one impact and countermeasure under the same label to obtain something like this?

enter image description here

3

This one was tricky. . . I rewrote the code so that it's backwards-compatible with the previous version. The features are mostly the same:

You declare a new impact/countermeasure pair with \DeclareImpact{<id>}{<impact>}{<counter>}. If you use \DeclareImpact again for the same <id>, the impact/countermeasure pair is appended to that list. Arbitrarily many items are allowed. You can clear an <id> using \ClearImpact{<id>}.

The commands \impact and \countermeasure have the same syntax. Everything I say for one is valid for the other. When you use \impact[<empty-text>](<item-list>){<id>} there are two possibilities:

  1. In case <id> was never declared using \DeclareImpact or it was cleared using \ClearImpact, then <empty-text> is returned. The argument <empty-text> is optional and the default is “Not applicable”.
  1. If the <id> contains a single impact (i.e., \DeclareImpact{<id>} was used only once) then it is printed using the code in \SetPrintSingle (more on this later).

  2. If the argument <item-list> was given, then only the items whose number is present in the <item-list> will be printed (items are numbered sequentially, starting from 1, as they are placed using \DeclareImpact). If <item-list> was not given, then all items are printed in order. Either way, the items apre printed using the code in \SetPrintList.

After processing the lists, the items are passed to the code defined by the two template functions, \SetPrintSingle (that is Print Single, not Pringles :-) and \SetPrintList. To define a template you use \SetPrintSingle{<code-with-#1>} (where #1 is the impact text) and \SetPrintList{<code-with-#1-and-#2>} (where #1 is the item number and #2 is the impact text). The same way you use the template function \SetRowFormat{<code-with-#1>} to set the format of a table row, where #1 is each comma-separated item passed to \TableBody.

Enough talking. The output looks quite similar to the one you asked:

enter image description here

And here's the code:

\documentclass{article}
\usepackage{nameref}
\usepackage{booktabs}
\usepackage[margin=4cm]{geometry}
\usepackage{tabularx}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new_protected:Npn \leonardo_declare_property:Nn #1 #2
  {
    \seq_if_exist:NF #1 { \seq_new:N #1 }
    \seq_gput_right:Nn #1 {#2}
  }
\cs_generate_variant:Nn \leonardo_declare_property:Nn { c }
\cs_new:Npn \leonardo_get_property:Nnn #1 #2 #3
  {
    \bool_lazy_or:nnTF
      { ! \seq_if_exist_p:N #1 }
      { \seq_if_empty_p:N #1 }
      { \exp_not:n {#2} }
      { \__leonardo_get_property:Nn #1 {#3} }
  }
\cs_generate_variant:Nn \leonardo_get_property:Nnn { c }
\cs_new:Npn \__leonardo_get_property:Nn #1 #2
  {
    \tl_if_novalue:nTF {#2}
      {
        \int_compare:nNnTF { \seq_count:N #1 } = { 1 }
          { \__leonardo_print_property:f { \seq_item:Nn #1 { 1 } } }
          { \seq_indexed_map_function:NN #1 \__leonardo_print_property:nn }
      }
      { \__leonardo_seq_filtered_map_tokens:Nnn #1 {#2} { \__leonardo_print_property:nn } }
  }
\cs_new_eq:NN \__leonardo_print_property:n \use:n
\cs_new_eq:NN \__leonardo_print_property:nn \use_ii:nn
\cs_generate_variant:Nn \__leonardo_print_property:n { f }
\cs_new:Npn \__leonardo_seq_filtered_map_tokens:Nnn #1#2#3
  {
    \exp_last_unbraced:Nno
      \use_i:nn { \__leonardo_map_tokens:nnnw { 1 } {#2} {#3} } #1
    \prg_break: \__seq_item:n { } \prg_break_point:
    \prg_break_point:Nn \seq_map_break: { }
  }
\cs_new:Npn \__leonardo_map_tokens:nnnw #1 #2#3 #4 \__seq_item:n #5
  {
    #4
    \afp_int_ismember:nnT {#1} {#2} { \use:n {#3} {#1} {#5} }
    \exp_args:Nf \__leonardo_map_tokens:nnnw { \int_eval:n {#1+1} } {#2} {#3}
  }
% List membership code: https://tex.stackexchange.com/a/501777/134574
\cs_new:Npn \__afp_ismember_loop:Nnw #1#2#3,
  {
    \quark_if_recursion_tail_stop_do:nn {#3} { \prg_return_false: }
    #1 {#2} {#3}
      { \use_i_delimit_by_q_recursion_stop:nw { \prg_return_true: } }
      { \__afp_ismember_loop:Nnw #1 {#2} }
  }
\prg_new_conditional:Npnn \__afp_int_isequal:nn #1#2 { p, T, F, TF }
  { \int_compare:nNnTF {#1} = {#2} { \prg_return_true: } { \prg_return_false: } }
\prg_new_conditional:Npnn \afp_int_ismember:nn #1#2 { p, T, F, TF }
  { \__afp_ismember_loop:Nnw \__afp_int_isequal:nnTF {#1} #2 , \q_recursion_tail , \q_recursion_stop }
% User interfaces
\makeatletter
\NewDocumentCommand \DeclareImpact { m +m +m }
  {
    \@bsphack
      \leonardo_declare_property:cn { g__leonardo_#1_impact_seq } {#2}
      \leonardo_declare_property:cn { g__leonardo_#1_counter_seq } {#3}
    \@esphack
  }
\NewDocumentCommand \ClearImpact { m }
  {
    \seq_gclear:c { g__leonardo_#1_impact_seq }
    \seq_gclear:c { g__leonardo_#1_counter_seq }
  }
\makeatother
\NewExpandableDocumentCommand \impact { O{Not~applicable} d() m }
  { \leonardo_get_property:cnn { g__leonardo_#3_impact_seq } {#1} {#2} }
\NewExpandableDocumentCommand \countermeasure { O{Not~applicable} d() m }
  { \leonardo_get_property:cnn { g__leonardo_#3_counter_seq } {#1} {#2} }
\NewExpandableDocumentCommand \TableBody { m }
  { \clist_map_function:nN {#1} \__leonardo_table_row:n }
\NewDocumentCommand \SetRowFormat { +m }
  { \cs_gset:Npn \__leonardo_table_row:n ##1 {#1} }
\NewDocumentCommand \SetPrintSingle { +m }
  { \cs_gset:Npn \__leonardo_print_property:n ##1 {#1} }
\NewDocumentCommand \SetPrintList { +m }
  { \cs_gset:Npn \__leonardo_print_property:nn ##1 ##2 {#1} }
\cs_new_eq:NN \StrLowerCase \str_lowercase:n
\ExplSyntaxOff

And now the document. Note that I used \SetPrintList twice; once to print the list in the text (which I did using a tabularx, to match the output you want), and again to print the text in the summary table. The summary table is especially tricky because the template:

\SetRowFormat
  {%
    \nameref{sec:\StrLowerCase{#1}}
  & \impact[--]{#1}
  & \countermeasure[--]{#1} \\
  }

prints all the impacts stored in #1 and then all the countermeasures. If the <id> in #1 happens to have more than one \impact then you need a new table row for each, and when you go to next column to print the \countermeasure, the table is a few rows down and you can't come back. To circumvent this issue I changed the template to:

\SetRowFormat
  {%
    \nameref{sec:\StrLowerCase{#1}}
  & \parbox[t]{\hsize}{\impact[--]{#1}}
  & \parbox[t]{\hsize}{\countermeasure[--]{#1}} \\
  }

which typesets all \impacts in a single \parbox, making them all of them go to the same table row, and then the same to the \countermeasure. This setting relies on the fact that tabularx changes the value of \hsize, so you need to load it.

Here it is:

\begin{document}

% Setting templates:

% Single-item impact/countermeasure: Just print the item
\SetPrintSingle{#1}

% Multi-item impact/countermeasure:
% Shift to the next table cell, print “<number>. <description>”, and shift to the next row
\SetPrintList{& #1.~#2\\}

\section{Impacts on the Environment}
\subsection{Air quality}
\label{sec:air}
Analyses of air quality.
\DeclareImpact{Air}{Wood burning}{Sleeve filter installation}

\textbf{Impact}: \impact{Air}

\textbf{Countermeasure}: \countermeasure{Air}

\subsection{Water resources}
\label{sec:water}
Analyses of water resources.

\DeclareImpact{Water}{low pervious surface rate}{rain water harvesting}
\DeclareImpact{Water}{alkaline waste water}{ph correction water treatment process}

\noindent
\begin{tabularx}{\textwidth}{lX}
  \textbf{Impact}: \impact{Water}
\end{tabularx}

\noindent
\begin{tabularx}{\textwidth}{lX}
  \textbf{Countermeasure}: \countermeasure{Water}
\end{tabularx}

\section{Conclusion}
A succinct conclusion. See Table \ref{tab:sumary}.

% Set table row format:
\SetRowFormat
  {%
    \nameref{sec:\StrLowerCase{#1}}
  & \parbox[t]{\hsize}{\impact[--]{#1}}
  & \parbox[t]{\hsize}{\countermeasure[--]{#1}} \\
  }

% Reset multi-item impact/countermeasure:
% Just print <description>, and break the paragraph: we're in a \parbox here
\SetPrintList{#2\par}

\begin{table}[htb!]
  \centering
  \caption{Summary of impacts and countermeasures}
  \label{tab:sumary}
  \begin{tabularx}{\textwidth}{l>{\hsize=.4\hsize}X>{\hsize=.6\hsize}X}
    \toprule
      \textbf{Analyse} & \textbf{Impact} & \textbf{Countermeasure}\\
    \midrule
        \TableBody{Air, Water}
    \bottomrule
  \end{tabularx}
\end{table}

\end{document}
  • after 3 days i digested this impressive code. if the impact does not exist, for example if I comment the command \ DeclareImpact {Air} {Wood burning} {Sleeve filter installation}, the compiler returns a Misplaced \ omit error. how to avoid this error, in the case there is'nt a impact? ** – leonardo cesar Oct 25 '19 at 14:23
  • @leonardocesar Odd... When you ask for an impact in the table body, it is printed in one way or another. The difference when the impact doesn't exist is that the fallback value (in the example, --) is printed instead. Other than that there should be no difference (theoretically, of course :-). Can you please upload the .log file somewhere (pastebin.com or other site you prefer) so I can take a look? – Phelype Oleinik Oct 25 '19 at 16:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.