eu quero fazer um loop com o processo:
Atual: (com código abaixo)
- cada linha cria uma página
- Caixa A, B, C: mesmos dados de uma linha do datatool
Precisa de atualização:
Crie apenas uma página \Break=break ou a cada 3 linhas
Caixa A = dados da linha: 1,4,7...,
Caixa B = dados da linha: 2,5,8…
Caixa C = dados da linha: 3,6,9
Cada 3 linhas no datatools criam uma página
Exemplo:
Página 1:
A: dados da linha: 1
B: dados da linha: 2
C: dados da linha: 3
Página 2:
A: dados da linha: 4
B: dados da linha: 5
C; dados da linha: 6
Codificação mínima:
\documentclass[a5paper,twoside,8pt]{article}
\usepackage[a5paper,landscape,left=1.0cm,right=0.3cm,top=0.5cm,bottom=0.5cm]{geometry}
\usepackage{tcolorbox}
\tcbuselibrary{poster}
\usepackage{tikz,everypage}
\usepackage[absolute,overlay]{textpos}
\usepackage{filecontents}
\begin{filecontents*}{product.tex}
%Type =1,2...10
No,Type,Name,Description,Break
1,1,A1,D1,xx
2,1,A1,D2,yy
3,1,A1,D3,break
4,1,A1,D30,ll
5,1,A2,D31,mm
6,1,A2,D131,break
7,1,A3,D132,bb
8,1,A3,D133,tt
9,1,A3,D134,break
10,1,A4,D249,ii
11,1,A10,D1000,bb
12,1,A2,D11,break
13,1,A3,D13,qq
14,1,A3,D135,gg
15,1,A3,D137,break
16,1,A4,D249,ff
17,1,A10,D100,gg
18,1,A43,D318,break
19,1,A44,D319,ss
20,1,A40,D320,ww
21,1,A43,D318,break
22,2,A44,D319,as
23,2,A40,D320,aw
\end{filecontents*}
\usepackage{datatool}
\usepackage{ifthen}
\DTLloaddb[autokeys=false]{products}{product.tex}
\newcommand{\printtype}[1]{%
\DTLforeach*
[\DTLiseq{\Type}{#1}]% Condition
{products}% Database
{\NoCoding=No,\Type=Type,\Name=Name,\Description=Description,\Break=Break}{%
\begin{tcbposter}[
poster = {
columns=1,
rows=2,
spacing=3mm,
height=14cm,
width=12cm,
},
]
%Box A
\posterbox[
colframe = red,
width=5cm, height= 5cm
]{xshift=1 cm,yshift=-3cm}{\includegraphics[height=2cm]{example-image-a}
\\
\noindent \NoCoding \quad \Name \quad \Break\par
}
%Box B
\posterbox[
colframe = blue,
width=5cm, height= 5cm
]{xshift=7cm,yshift =-3cm }{\includegraphics[height=3cm]{example-image-b}
\\
\noindent \NoCoding \quad \Name \quad \Break\par
}
%Box C
\posterbox[
colframe = green,
width=5cm, height= 5cm
]{xshift=13cm,yshift =-3cm }{\includegraphics[height=3cm]{example-image-c}
\\
\noindent \NoCoding \quad \Name \quad \Break \par
}
\end{tcbposter}
\newpage
}%
}
\begin{document}
\printtype{1}
\end{document}
Exemplo de imagem do código atual
Agradeço antecipadamente
Responder1
O código a seguir implementa buffer em cima de datatool
, para permitir que você processe as linhasnporn. Isso funciona por meio de um ambiente chamado lfbuffering
assim:
\begin{lfbuffering}{n}{macro names for needed columns}{code}
\DTLforeach*{database}% Database
{\macro1=colname1, \macro2=colname2, ..., \macrop=colnamep}
{\lfbufProcessOneRow}
\end{lfbuffering}
Isso chamará o código no terceiro argumento do lfbuffering
ambiente toda veznlinhas foram lidas (armazenadas em buffer) por \DTLforeach*
. Se menos quenlinhas estão disponíveis para a última execução decódigo, ainda será executado; \lfbufNbBufferedRows
informa quantas linhas estão disponíveis no buffer (tecnicamente, \lfbufNbBufferedRows
é um \countdef
token; em particular, é um 〈número〉 TeX, ou seja, um número inteiro).
Então, por exemplo, sené 4 e \DTLforeach*
fornece 11 linhas de banco de dados no total, as invocações sucessivas decódigoverá \lfbufNbBufferedRows
igual a 4, 4 e depois 3 (4 + 4 + 3 = 11).códigopode ser um nome de macro ou mais tokens. Ele tem acesso aos campos em buffer usando \lfbufField{k}{macroName}
where
ké 1 para a primeira linha em buffer, 2 para a segunda linha em buffer, etc.kdeve ser menor ou igual a
\lfbufNbBufferedRows
);macroNomeé qualquer um de
macro1
,macro2
, ... (elementos do segundo argumento delfbuffering
, correspondendo a parte ou todos os nomes de macro definidos no\DTLforeach*
segundo argumento obrigatório da chamada, sem as barras invertidas iniciais).
Vejamos um exemplo simples:
\begin{lfbuffering}{3}{Type, Name, Description}{\myPrintBufferedData}
\DTLforeach*{products}% Database
{\NoCoding=No,\Type=Type,\Name=Name,\Description=Description,\Break=Break}
{\lfbufProcessOneRow}
\end{lfbuffering}
Aqui processamos as linhas (registros do seu products
banco de dados) 3 por 3. \lfbufProcessOneRow
é o único token no terceiro argumento obrigatório de \DTLforeach*
: sua função é reunir na memória as linhas lidas \DTLforeach*
até ter 3, momento em que irá chamar \myPrintBufferedData
( conteúdo docódigoargumento do lfbuffering
meio ambiente). Você precisa definir \myPrintBufferedData
o que deseja fazer com as linhas em buffer. Sua definição pode ser assim (dado o valor usado para o segundo argumento lfbuffering
neste exemplo, \myPrintBufferedData
pode acessar os campos Type
, Name
e Description
):
\newcommand*{\myPrintBufferedData}{%
\setlength{\parindent}{0pt}% for instance
\ifnum\lfbufNbBufferedRows>0 % <-- space or end-of-line here, important!
\lfbufField{1}{Type}, \lfbufField{1}{Name},
\lfbufField{1}{Description}\par
\fi
%
\ifnum\lfbufNbBufferedRows>1 % here too
\lfbufField{2}{Type}, \lfbufField{2}{Name},
\lfbufField{2}{Description}\par
\fi
%
\ifnum\lfbufNbBufferedRows>2 % and here
\lfbufField{3}{Type}, \lfbufField{3}{Name},
\lfbufField{3}{Description}\par\medskip
\fi
}
Desde ocódigoargumento do lfbuffering
ambiente nunca é chamado com um buffer vazio, o primeiro teste ( \ifnum\lfbufNbBufferedRows>0
[terminado por um espaço]) pode ser omitido. Mas desta forma, todos os casos seguem o mesmo padrão. Aqui está um exemplo completo semelhante ao que acabamos de explicar:
\RequirePackage{filecontents}
\begin{filecontents*}{product.tex}
%Type =1,2...10
No,Type,Name,Description,Break
1,1,A1,D1,xx
2,1,A1,D2,yy
3,1,A1,D3,break
4,1,A1,D30,ll
5,1,A2,D31,mm
6,1,A2,D131,break
7,1,A3,D132,bb
8,1,A3,D133,tt
9,1,A3,D134,break
10,1,A4,D249,ii
11,1,A10,D1000,bb
12,1,A2,D11,break
13,1,A3,D13,qq
14,1,A3,D135,gg
15,1,A3,D137,break
16,1,A4,D249,ff
17,1,A10,D100,gg
18,1,A43,D318,break
19,1,A44,D319,ss
20,1,A40,D320,ww
21,1,A43,D318,break
22,2,A44,D319,as
23,2,A40,D320,aw
\end{filecontents*}
\documentclass{article}
\usepackage{xparse}
\usepackage{datatool}
\DTLloaddb[autokeys=false]{products}{product.tex}
\ExplSyntaxOn
\int_new:N \l_lfbuf_buffer_depth_int
\seq_new:N \l_lfbuf_colnames_seq
\tl_new:N \l_lfbuf_output_callback_tl
% #1: zero-based index of buffered row
% #2: field name
% #3: value
\cs_new_protected:Npn \lfbuf_store_field_aux:nnn #1#2#3
{
\tl_set:cn { l_lfbuf_data_#1_#2_tl } {#3}
}
\cs_generate_variant:Nn \lfbuf_store_field_aux:nnn { nnV }
% #1: zero-based index of buffered row
% #2: field name
\cs_new_protected:Npn \lfbuf_store_field:nn #1#2
{
% Get the field contents; this requires 3 expansion steps
\tl_set:No \l_tmpa_tl { \use:c {#2} }
\exp_args:NNNo \exp_args:NNo \tl_set:No \l_tmpa_tl { \l_tmpa_tl}
\lfbuf_store_field_aux:nnV {#1} {#2} \l_tmpa_tl
}
\cs_generate_variant:Nn \lfbuf_store_field:nn { Vn }
\cs_new_protected:Npn \lfbuf_clear_buffer_vars:
{
\int_step_inline:nnn { 0 } { \l_lfbuf_buffer_depth_int - 1 }
{
\seq_map_inline:Nn \l_lfbuf_colnames_seq
{ \tl_clear_new:c { l_lfbuf_data_##1_####1_tl } }
}
}
% These two are often identical, but not always
\int_new:N \l_lfbuf_buffered_row_index_int
\int_new:N \lfbufNbBufferedRows % user-accessible from callback code
\cs_new_protected:Npn \lfbuf_process_one_row:
{
\seq_map_inline:Nn \l_lfbuf_colnames_seq
{ \lfbuf_store_field:Vn \l_lfbuf_buffered_row_index_int {##1} }
% Advance the index, but stay modulo \l_lfbuf_buffer_depth_int
\int_set:Nn \l_lfbuf_buffered_row_index_int
{ \int_mod:nn
{ \l_lfbuf_buffered_row_index_int + 1 }
{ \l_lfbuf_buffer_depth_int }
}
% Is the buffer full?
\int_compare:nNnT { \l_lfbuf_buffered_row_index_int } = { 0 }
{
% Print output and start over with an empty buffer.
\int_set_eq:NN \lfbufNbBufferedRows \l_lfbuf_buffer_depth_int
\tl_use:N \l_lfbuf_output_callback_tl
}
}
\cs_new:Npn \lfbuf_get_field:nn #1#2
{
\use:c { l_lfbuf_data_#1_#2_tl }
}
\cs_generate_variant:Nn \lfbuf_get_field:nn { f }
% *********************************************************************
% As opposed to all code-level functions, document commands use 1-based
% indexing (datatool also uses 1-based indexing for rows and columns).
% *********************************************************************
% Expand to field #2 (column title) of buffered row #1 (index starting from 1).
\NewExpandableDocumentCommand \lfbufField { m m }
{
\lfbuf_get_field:fn { \int_eval:n {#1-1} } {#2}
}
\NewDocumentCommand \lfbufProcessOneRow { }
{
\lfbuf_process_one_row:
}
\NewDocumentEnvironment { lfbuffering } { m m +m }
{
\int_set:Nn \l_lfbuf_buffer_depth_int {#1}
\seq_set_from_clist:Nn \l_lfbuf_colnames_seq {#2}
\tl_set:Nn \l_lfbuf_output_callback_tl {#3}
\int_set:Nn \l_lfbuf_buffered_row_index_int { 0 }
\lfbuf_clear_buffer_vars:
\ignorespaces
}
{
\unskip
% If there is buffered data that hasn't been output, process it now (this
% means that the last row of the datatool table didn't fill the buffer).
\int_compare:nNnT { \l_lfbuf_buffered_row_index_int } > { 0 }
{
\int_set_eq:NN \lfbufNbBufferedRows \l_lfbuf_buffered_row_index_int
\tl_use:N \l_lfbuf_output_callback_tl
}
}
\ExplSyntaxOff
\newcommand*{\myPrintBufferedData}{%
\setlength{\parindent}{0pt}%
% I keep this test for symmetry with the other cases, but it is always true.
% You can remove it if you prefer.
\ifnum\lfbufNbBufferedRows>0 % if there remains at least one row
\lfbufField{1}{NoCoding}, \lfbufField{1}{Type}, \lfbufField{1}{Name},
\lfbufField{1}{Description}, \lfbufField{1}{Break}\par
\fi
%
\ifnum\lfbufNbBufferedRows>1
\lfbufField{2}{NoCoding}, \lfbufField{2}{Type}, \lfbufField{2}{Name},
\lfbufField{2}{Description}, \lfbufField{2}{Break}\par
\fi
%
\ifnum\lfbufNbBufferedRows>2
\lfbufField{3}{NoCoding}, \lfbufField{3}{Type}, \lfbufField{3}{Name},
\lfbufField{3}{Description}, \lfbufField{3}{Break}\par\medskip
\fi
}
\begin{document}
% Read and process 3 lines at a time. Call \myPrintBufferedData every time
% the buffer is full as well as at the end (i.e., the last call can have 1,
% 2 or 3 lines, as indicated by \lfbufNbBufferedRows).
\begin{lfbuffering}{3}{NoCoding, Type, Name, Description, Break}
{\myPrintBufferedData}
\DTLforeach*{products}% Database
{\NoCoding=No,\Type=Type,\Name=Name,\Description=Description,\Break=Break}
{\lfbufProcessOneRow}
\end{lfbuffering}
\end{document}
E aqui está o exemplo com o seu tcbposter
:
\RequirePackage{filecontents}
\begin{filecontents*}{product.tex}
%Type =1,2...10
No,Type,Name,Description,Break
1,1,A1,D1,xx
2,1,A1,D2,yy
3,1,A1,D3,break
4,1,A1,D30,ll
5,1,A2,D31,mm
6,1,A2,D131,break
7,1,A3,D132,bb
8,1,A3,D133,tt
9,1,A3,D134,break
10,1,A4,D249,ii
11,1,A10,D1000,bb
12,1,A2,D11,break
13,1,A3,D13,qq
14,1,A3,D135,gg
15,1,A3,D137,break
16,1,A4,D249,ff
17,1,A10,D100,gg
18,1,A43,D318,break
19,1,A44,D319,ss
20,1,A40,D320,ww
21,1,A43,D318,break
22,2,A44,D319,as
23,2,A40,D320,aw
\end{filecontents*}
\documentclass{article}
\usepackage[landscape,hscale=0.8]{geometry}
\usepackage{tcolorbox}
\tcbuselibrary{poster}
\usepackage{xparse}
\usepackage{datatool}
\DTLloaddb[autokeys=false]{products}{product.tex}
\ExplSyntaxOn
\int_new:N \l_lfbuf_buffer_depth_int
\seq_new:N \l_lfbuf_colnames_seq
\tl_new:N \l_lfbuf_output_callback_tl
% #1: zero-based index of buffered row
% #2: field name
% #3: value
\cs_new_protected:Npn \lfbuf_store_field_aux:nnn #1#2#3
{
\tl_set:cn { l_lfbuf_data_#1_#2_tl } {#3}
}
\cs_generate_variant:Nn \lfbuf_store_field_aux:nnn { nnV }
% #1: zero-based index of buffered row
% #2: field name
\cs_new_protected:Npn \lfbuf_store_field:nn #1#2
{
% Get the field contents; this requires 3 expansion steps
\tl_set:No \l_tmpa_tl { \use:c {#2} }
\exp_args:NNNo \exp_args:NNo \tl_set:No \l_tmpa_tl { \l_tmpa_tl}
\lfbuf_store_field_aux:nnV {#1} {#2} \l_tmpa_tl
}
\cs_generate_variant:Nn \lfbuf_store_field:nn { Vn }
\cs_new_protected:Npn \lfbuf_clear_buffer_vars:
{
\int_step_inline:nnn { 0 } { \l_lfbuf_buffer_depth_int - 1 }
{
\seq_map_inline:Nn \l_lfbuf_colnames_seq
{ \tl_clear_new:c { l_lfbuf_data_##1_####1_tl } }
}
}
% These two are often identical, but not always
\int_new:N \l_lfbuf_buffered_row_index_int
\int_new:N \lfbufNbBufferedRows % user-accessible from callback code
\cs_new_protected:Npn \lfbuf_process_one_row:
{
\seq_map_inline:Nn \l_lfbuf_colnames_seq
{ \lfbuf_store_field:Vn \l_lfbuf_buffered_row_index_int {##1} }
% Advance the index, but stay modulo \l_lfbuf_buffer_depth_int
\int_set:Nn \l_lfbuf_buffered_row_index_int
{ \int_mod:nn
{ \l_lfbuf_buffered_row_index_int + 1 }
{ \l_lfbuf_buffer_depth_int }
}
% Is the buffer full?
\int_compare:nNnT { \l_lfbuf_buffered_row_index_int } = { 0 }
{
% Print output and start over with an empty buffer.
\int_set_eq:NN \lfbufNbBufferedRows \l_lfbuf_buffer_depth_int
\tl_use:N \l_lfbuf_output_callback_tl
}
}
\cs_new:Npn \lfbuf_get_field:nn #1#2
{
\use:c { l_lfbuf_data_#1_#2_tl }
}
\cs_generate_variant:Nn \lfbuf_get_field:nn { f }
% *********************************************************************
% As opposed to all code-level functions, document commands use 1-based
% indexing (datatool also uses 1-based indexing for rows and columns).
% *********************************************************************
% Expand to field #2 (column title) of buffered row #1 (index starting from 1).
\NewExpandableDocumentCommand \lfbufField { m m }
{
\lfbuf_get_field:fn { \int_eval:n {#1-1} } {#2}
}
\NewDocumentCommand \lfbufProcessOneRow { }
{
\lfbuf_process_one_row:
}
\NewDocumentEnvironment { lfbuffering } { m m +m }
{
\int_set:Nn \l_lfbuf_buffer_depth_int {#1}
\seq_set_from_clist:Nn \l_lfbuf_colnames_seq {#2}
\tl_set:Nn \l_lfbuf_output_callback_tl {#3}
\int_set:Nn \l_lfbuf_buffered_row_index_int { 0 }
\lfbuf_clear_buffer_vars:
\ignorespaces
}
{
\unskip
% If there is buffered data that hasn't been output, process it now (this
% means that the last row of the datatool table didn't fill the buffer).
\int_compare:nNnT { \l_lfbuf_buffered_row_index_int } > { 0 }
{
\int_set_eq:NN \lfbufNbBufferedRows \l_lfbuf_buffered_row_index_int
\tl_use:N \l_lfbuf_output_callback_tl
}
}
\ExplSyntaxOff
\newcommand*{\myPrintBufferedData}{%
\begin{tcbposter}[poster={columns=1, rows=2, spacing=3mm,
height=14cm, width=12cm}]
% Box A
\posterbox[colframe=red, width=6cm, height=5cm]{xshift=0cm, yshift=-3cm}
{% I keep this test for symmetry with the other cases, but it is always
% true. You can remove it if you prefer.
\ifnum\lfbufNbBufferedRows>0
\includegraphics[width=4cm]{example-image-a}\\
\noindent
\lfbufField{1}{NoCoding}\quad
\lfbufField{1}{Name}\quad
\lfbufField{1}{Break}%
\fi
}%
% Box B
\posterbox[colframe=blue, width=6cm, height=5cm]{xshift=8cm, yshift=-3cm}
{%
\ifnum\lfbufNbBufferedRows>1
\includegraphics[width=4cm]{example-image-b}\\
\noindent
\lfbufField{2}{NoCoding}\quad
\lfbufField{2}{Name}\quad
\lfbufField{2}{Break}%
\fi
}%
% Box C
\posterbox[colframe=green, width=6cm, height=5cm]{xshift=16cm, yshift=-3cm}
{%
\ifnum\lfbufNbBufferedRows>2
\includegraphics[width=4cm]{example-image-c}\\
\noindent
\lfbufField{3}{NoCoding}\quad
\lfbufField{3}{Name}\quad
\lfbufField{3}{Break}%
\fi
}%
\end{tcbposter}%
\newpage
}
\newcommand{\printtype}[1]{%
% Read and process 3 lines at a time. Call \myPrintBufferedData every time
% the buffer is full as well as at the end (i.e., the last call can have 1,
% 2 or 3 lines, as indicated by \lfbufNbBufferedRows).
\begin{lfbuffering}{3}{NoCoding, Type, Name, Description, Break}
{\myPrintBufferedData}
\DTLforeach*
[\DTLiseq{\Type}{#1}]% Condition
{products}% Database
{\NoCoding=No,\Type=Type,\Name=Name,\Description=Description,\Break=Break}
{\lfbufProcessOneRow}
\end{lfbuffering}%
}
\begin{document}
\printtype{1}
\end{document}
Página 1:
Página 2:
Página 3:
...
Página 7: