ich möchte eine Schleife mit dem Prozess erstellen:
Aktuell: (mit folgendem Code)
- jede Zeile erstellt eine Seite
- Box A, B, C: Dieselben Daten aus einer Zeile des Datentools
Muss aktualisiert werden:
Erstellen Sie nur eine Seite \Break=break oder alle 3 Zeilen
Feld A = Daten der Zeile: 1,4,7...,
Feld B = Daten der Zeile: 2,5,8…
Feld C = Daten der Zeile: 3,6,9
Alle 3 Zeilen in Datatools erstellen eine Seite
Beispiel:
Seite 1:
A: Daten der Zeile: 1
B: Daten der Zeile: 2
C: Daten der Zeile: 3
Seite 2:
A: Daten der Zeile: 4
B: Daten der Zeile: 5
C; Daten der Zeile: 6
Minimale Codierung:
\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}
Beispielbild des aktuellen Codes
Danke im Voraus
Antwort1
Der folgende Code implementiert die Pufferung aufdatatool
, um Ihnen die Verarbeitung der Zeilen zu ermöglichenNvonNDies funktioniert über eine Umgebung namens lfbuffering
, die folgendermaßen aufgerufen wird:
\begin{lfbuffering}{n}{macro names for needed columns}{code}
\DTLforeach*{database}% Database
{\macro1=colname1, \macro2=colname2, ..., \macrop=colnamep}
{\lfbufProcessOneRow}
\end{lfbuffering}
Dadurch wird der Code im dritten Argument deslfbuffering
Umgebung jedes Mal aufgerufenNZeilen wurden gelesen (gepuffert) von\DTLforeach*
. Wenn weniger alsNZeilen sind verfügbar für die letzte Ausführung vonCode, es wird trotzdem ausgeführt; \lfbufNbBufferedRows
gibt an, wie viele Zeilen im Puffer verfügbar sind (technisch gesehen \lfbufNbBufferedRows
ist dies ein \countdef
Token; insbesondere ist es eine TeX-<Zahl>, also eine Ganzzahl).
Wenn also zum BeispielNist 4 und\DTLforeach*
stellt insgesamt 11 Datenbankzeilen bereit. Die aufeinanderfolgenden Aufrufe vonCodewerden sehen\lfbufNbBufferedRows
4, 4 und dann 3 (4 + 4 + 3 = 11).Codekann ein Makroname oder mehrere Token sein. Es hat Zugriff auf die gepufferten Felder mit \lfbufField{k}{macroName}
where
kist 1 für die erste gepufferte Zeile, 2 für die zweite gepufferte Zeile usw. (kmuss kleiner oder gleich sein
\lfbufNbBufferedRows
);Makronameist ein beliebiges von
macro1
,macro2
, … (Elemente aus dem zweiten Argument vonlfbuffering
, entsprechend einem Teil oder allen Makronamen, die im\DTLforeach*
zweiten obligatorischen Argument des Aufrufs definiert sind, ohne die führenden Backslashes).
Nehmen wir ein einfaches Beispiel:
\begin{lfbuffering}{3}{Type, Name, Description}{\myPrintBufferedData}
\DTLforeach*{products}% Database
{\NoCoding=No,\Type=Type,\Name=Name,\Description=Description,\Break=Break}
{\lfbufProcessOneRow}
\end{lfbuffering}
Hier verarbeiten wir die Zeilen (Datensätze Ihrer products
Datenbank) 3 mal 3. \lfbufProcessOneRow
ist das einzige Token im dritten obligatorischen Argument von \DTLforeach*
: seine Rolle besteht darin, die von gelesenen Zeilen im Speicher zu sammeln, \DTLforeach*
bis 3 erreicht sind. An diesem Punkt ruft es auf \myPrintBufferedData
(Inhalt derCodeArgument der lfbuffering
Umgebung). Sie müssen definieren, \myPrintBufferedData
was Sie mit den gepufferten Zeilen tun möchten. Die Definition kann wie folgt aussehen (angesichts des Wertes, der lfbuffering
in diesem Beispiel für das zweite Argument von verwendet wird, \myPrintBufferedData
kann auf die Felder Type
, Name
und zugegriffen werden 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
}
Seit derCodeArgument der lfbuffering
Umgebung wird nie mit einem leeren Puffer aufgerufen, der erste Test ( \ifnum\lfbufNbBufferedRows>0
[mit einem Leerzeichen beendet]) könnte weggelassen werden. Auf diese Weise folgen alle Fälle jedoch demselben Muster. Hier ist ein vollständiges Beispiel, das dem ähnelt, was wir gerade erklärt haben:
\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}
Und hier ist das Beispiel mit Ihrem 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}
Seite 1:
Seite 2:
Seite 3:
...
Seite 7: