# How display next row before current row when use datatool?

i use datatool, and want display next data before current data, is possible? I need help in code "diplay here data of (AAACoding+1), CCCCoding+1...)"

My Minimal Coding:

\documentclass[a5paper,oneside,8pt]{article}
\usepackage[a5paper,landscape,left=1.0cm,right=0.3cm,top=0.5cm,bottom=0.5cm]{geometry}
\usepackage{datatool}
\usepackage{filecontents}
\begin{filecontents*}{fileabc.tex}
AAA|BBB|CCC|DDD|
1|100|NT|E1|
2|109|NT|EE|
3|210|AT|E|
4|340|NT|E30|
5|12|AT|E31|
6|410|AT|E44|
7|234|NT|E77|
8|012|AT|E88|
\end{filecontents*}
\usepackage{datatool}
\DTLsetseparator{|}
\DTLsetdelimiter{"}

\newcommand{\printCCCCoding}[1]{%
\par

\DTLforeach*
[\DTLiseq{\CCCCoding}{#1}]%
{fileabc}% Database
{\CCCCoding=CCC,\AAACoding=AAA, \BBBCoding=BBB,\DDDCoding=DDD}{%
Next row: diplay here data of (AAACoding+1), CCCCoding+1...)
\\
Current row: \AAACoding \\
\noindent \CCCCoding \hspace{0.1cm} 2 \AAACoding \hspace{0.1cm}  3 \BBBCoding \hspace{0.1cm} 4 \DDDCoding \par\\
-----------\\
}%
}

\begin{document}

%\DTLdisplaydb{fileabc}
%\newpage
\\
\printCCCCoding{NT}

\end{document}


Here is a solution using LaTeX3. It works by keeping the last two lines loaded by datatool in a sliding window. You can think of this sliding window as a buffer of database rows. It is implemented as a LaTeX3 sequence of token lists, where each token list contains exactly one item per column of your database.

\RequirePackage{filecontents}
\begin{filecontents*}{fileabc.tex}
AAA|BBB|CCC|DDD|
1|100|NT|E1|
2|109|NT|EE|
3|210|AT|E|
4|340|NT|E30|
5|12|AT|E31|
6|410|AT|E44|
7|234|NT|E77|
8|012|AT|E88|
\end{filecontents*}

\documentclass{article}
\usepackage{xparse}
\usepackage{datatool}

\DTLsetseparator{|}
\DTLsetdelimiter{"}

\ExplSyntaxOn

% Sliding window encoding at most two database rows. Each <item> of the seq
% corresponds to a database row and is a token list that contains as many
% subitems as there are columns in the database.
\seq_new:N \l__lforti_window_seq

{
% Append the new row as a token list containing one <item> per database
% column.
\seq_put_right:Nn \l__lforti_window_seq { {#1} {#2} {#3} {#4} }
}

\tl_new:N \l__lforti_current_row_tl
\tl_new:N \l__lforti_next_row_tl
\str_new:N \l__lforti_tested_field_str

% Process the first row loaded in the sliding window, if any. The second row
% is the next one, and is used too in case the first row is a match.
%
% #1: index (starting from 1) of the field to test
% #2: value to compare to (a string)
\cs_new_protected:Npn \lforti_process_one_db_row:nn #1#2
{
\seq_pop_left:NN \l__lforti_window_seq \l__lforti_current_row_tl

\tl_if_eq:NNF \l__lforti_current_row_tl \q_no_value
{
\str_set:Nx \l__lforti_tested_field_str
{ \tl_item:Nn \l__lforti_current_row_tl {#1} }

\str_if_eq:VnT \l__lforti_tested_field_str {#2}
{ % There is a match on the tested field, get the next row
\seq_set_eq:NN \l_tmpa_seq \l__lforti_window_seq
\seq_pop_left:NN \l_tmpa_seq \l__lforti_next_row_tl

\tl_if_eq:NNF \l__lforti_next_row_tl \q_no_value
{
\par \noindent Next~row:~
\lforti_display_row:nN { \c_false_bool } \l__lforti_next_row_tl
\\
}

\noindent Current~row:~
% Full display of the current row
\lforti_display_row:nN { \c_true_bool } \l__lforti_current_row_tl
\\[1ex]
\rule { 4cm } { 0.4pt }
\par \skip_vertical:n { 1ex }
}
}
}

% #1: boolean expression indicating whether to do full display of the row
% #2: token list variable corresponding to the row contents (one <item> per
%     field)
\cs_new_protected:Npn \lforti_display_row:nN #1#2
{
\bool_if:nT {#1}            % Full display?
{ \tl_item:Nn #2 { 1 } \\ }

\tl_item:Nn #2 { 3 }
\hspace{0.1cm} 2~
\tl_item:Nn #2 { 1 }
\hspace{0.1cm} 3~
\tl_item:Nn #2 { 2 }
\hspace{0.1cm} 4~
\tl_item:Nn #2 { 4 }
}

% #1: column number for the tested value (1 for the first column, 2 for the
%     second one, 3 for the third [CCC], etc.)
% #2: value to test against
\NewDocumentCommand \printCoding { m m }
{
\par
\seq_clear:N \l__lforti_window_seq

\DTLforeach* { fileabc } % database
{\CCCCoding=CCC, \AAACoding=AAA, \BBBCoding=BBB, \DDDCoding=DDD }
{
{ \AAACoding } { \BBBCoding } { \CCCCoding } { \DDDCoding }

% Process the sliding window contents here only if it's full (the
% “current row” for \lforti_process_one_db_row:nn is always the first
% item of \l__lforti_window_seq; the second item, if any, is processed
% after the \DTLforeach* loop).
\int_compare:nNnT { \seq_count:N \l__lforti_window_seq } = { 2 }
{ \lforti_process_one_db_row:nn {#1} {#2} }
}

% Process the last row, if any (it is now the first element of
% \l__lforti_window_seq).
\lforti_process_one_db_row:nn {#1} {#2}
}

% Convenience user macro
\NewDocumentCommand \printCCCCoding { m }
{
\printCoding {3} {#1}
}

\ExplSyntaxOff

\begin{document}

\printCCCCoding{NT}

\end{document}


Edge cases should be handled correctly (no “Next row” printed when the match was on the last row, etc.):

\begin{filecontents*}{fileabc.tex}
AAA|BBB|CCC|DDD|
1|100|NT|E1|
2|109|NT|EE|
3|210|AT|E|
4|340|NT|E30|
5|12|AT|E31|
6|410|AT|E44|
7|234|NT|E77|
8|012|AT|E88|
9|777|NT|E99|
\end{filecontents*}


An empty or one-line database is handled correctly, too. For instance:

\begin{filecontents*}{fileabc.tex}
AAA|BBB|CCC|DDD|
9|777|NT|E99|
\end{filecontents*}


Note: you can very easily adapt the definition of \printCCCCoding to perform the row selection test with values from other columns (the first argument of \printCoding is the column number used for this purpose, starting from 1). Of course, you can use \printCoding as many times as you want in the document.

• I fixed a variable type declaration and simplified the implementation (there was no real need for an end marker, after all). The behavior should be exactly the same as before. :-) – frougon Jun 7 '19 at 15:07