PDA

View Full Version : Problem mit ampersand in automatisierter Tabelle



rafael
09-08-2011, 21:23
Ich habe ein Problem mit der Verbindung von keys, makros und dem ampersandzeichen in einer Tabelle.
Motivation: Es sollen Spalteninhalte in einer Liste über keys aus dem xkeyval Paket übergeben werden, die in Makros umgewandelt werden und anschließend wieder automatisch ausgegeben werden.

Folgendes MB läuft fehlerfrei (die Komplexität ist notwendig um den Effekt zu erzielen). Problematisch ist aber, dass die jeweiligen Spalteninhalte nicht ausgegeben werden, wenn das "&"-Zeichen im Befehl \printrow eingefügt. Wird es auskommentiert, werden zwar alle INhalte ausgegeben (nur eben allein in der ersten Spalte).



\documentclass{scrartcl}

\usepackage{xkeyval,forloop}
\newcounter{colloop}\newcounter{maxflcol}
\makeatletter
\define@key{fltable}{columns}{%key mit einer Liste, die den Spalten zugeordnet wird
\def\vara{#1}%liste abspeichern
\setcounter{colloop}{0}
\@for\mycolumn:=\vara\do{%gehe die Liste durch und setze in \mycolumn1,\mycolumn2 usw. die Inhalte
\stepcounter{colloop}%
\expandafter\edef\csname mycolumn\the\value{colloop}\endcsname{\mycolumn}
}
\setcounter{maxflcol}{\value{colloop}}%merke die maximale Spaltenzahl
}
\makeatother

\newcommand{\printrow}[1]{%zeile ausgeben
\setkeys{fltable}{#1}%
\forloop{colloop}{1}{\value{colloop} < \value{maxflcol}}%
{%%gehe durch jede Spalte und gebe den Inhalt aus
\csname mycolumn\the\value{colloop}\endcsname%
%%%%%%%%%dieses Ampersand macht Probleme, wird es weggelassen, werden alle Inhalte ausgegeben
&%
%%%%%%%%%%%%%%, mit ihm fehlen die Inhalte
}%
%%das letzte Stück mit Inhalt
\csname mycolumn\the\value{colloop}\endcsname%
\\%
}%

%%%%%%%%%%%%%%%%%%
\begin{document}
\begin{tabular}{|l|l|l|l|}
\printrow{columns={erste,zweite,dritte,vierte}}
\end{tabular}
\end{document}

mechanicus
10-08-2011, 01:43
Hi,


viel Spaß :p


Mit deinem Ansatz:

\documentclass{scrartcl}

\usepackage{xkeyval,forloop}
\newcounter{colloop}\newcounter{maxflcol}
\makeatletter
\define@key{fltable}{columns}{%key mit einer Liste, die den Spalten zugeordnet wird
\def\vara{#1}%liste abspeichern
\setcounter{colloop}{0}%
\@for\mycolumn:=\vara\do{%gehe die Liste durch und setze in \mycolumn1,\mycolumn2 usw. die Inhalte
\stepcounter{colloop}%
\expandafter\edef\csname mycolumn\the\value{colloop}\endcsname{\mycolumn}%
}
\setcounter{maxflcol}{\value{colloop}}%merke die maximale Spaltenzahl
}
\makeatother

\newcommand{\printrow}[1]{%zeile ausgeben
\setkeys{fltable}{#1}%
\def\@tempb{}%
\forloop{colloop}{1}{\value{colloop} < \value{maxflcol}}%
{%%gehe durch jede Spalte und gebe den Inhalt aus
\edef\@tempb{\@tempb\csname mycolumn\the\value{colloop}\endcsname&}%
%%%%%%%%%dieses Ampersand macht Probleme, wird es weggelassen, werden alle Inhalte ausgegeben
% &%
%%%%%%%%%%%%%%, mit ihm fehlen die Inhalte
}%
%%das letzte Stück mit Inhalt
\edef\@tempb{\@tempb\csname mycolumn\the\value{colloop}\endcsname}%
\@tempb%
\\%
}%

%%%%%%%%%%%%%%%%%%
\begin{document}
\begin{tabular}{|l|l|l|l|}
\printrow{columns={erste,zweite,dritte,vierte}}
\end{tabular}
\end{document}

Marco

EDIT: Hier die Möglichkeit mit etoolbox (eines meiner liebsten Pakete ;-) )

\documentclass{scrartcl}

\usepackage{xkeyval,etoolbox}
\newcounter{colloop}
\newcounter{maxflcol}
\makeatletter
\define@key{fltable}{columns}{%key mit einer Liste, die den Spalten zugeordnet wird
\setcounter{maxflcol}{0}%
\def\@tempa{}%
\forcsvlist{\listadd\@tempa}{#1}%
\forlistloop{\stepcounter{maxflcol}\@gobble}{\@tem pa}%
\setcounter{colloop}{0}%
\def\do##1{\expandafter\gdef\csname mycolumn\the\value{colloop}\endcsname{##1}\refstep counter{colloop}}%
\docsvlist{#1}%
}

\newcommand{\printrow}[1]{%zeile ausgeben
\setkeys{fltable}{#1}%
\setcounter{colloop}{0}%
\addtocounter{maxflcol}{-1}%
\let\@tempb\@empty%
\loop\ifnum\value{colloop}<\numexpr\value{maxflcol}\relax\relax%
\edef\@tempb{\@tempb\csname mycolumn\the\value{colloop}\endcsname&}%
\refstepcounter{colloop}%
\repeat%
\edef\@tempb{\@tempb\csname mycolumn\the\value{maxflcol}\endcsname}%
\@tempb%
\\%
}%
\makeatother
%%%%%%%%%%%%%%%%%%
\begin{document}
\begin{tabular}{|l|l|l|l|}
\printrow{columns={erste Teil,zweite,dritte,vierte}}
\printrow{columns={erste Teil,zweite,dritte,{vierte,acht}}}
\end{tabular}
\end{document}

rafael
10-08-2011, 14:26
Hi,
viel Spaß :p
Mit deinem Ansatz:

Danke, für das Beispiel klappt das gut.

Wenn ich es aber versuche, in ein größeres Projekt einzupflegen, funktioniert das Ganze nicht mehr. Ich habe leider keine Ahnung warum. Tut mir leid, wenn im nächsten Beispiel die Sachlage nun komplexer ist, aber ich habe schon viel Code rausgeworfen.

Die Idee besteht darin, Tabellen nicht mehr so kompliziert mit "&" und unter Berücksichtigung der Spaltenreihenfolge in die .tex Datei zu schreiben, sondern mittels einer key-value-liste.
Zeilen sollen beispielsweise mittels

\myrow{name={Mickey},
geburt={32.03.2001},
steuer={90}}
eingegeben werden. Dabei spielen Reihenfolge und Umfang der Einzelnen keys keine Rolle, da mit

\begin{myfltable}{tabpreambel={r|r|r},columns={nam e,geburt,steuer}}die eigentliche Tabellenformatierung nicht in \myrow{}, sondern in einer Umgebung gegeben ist. Ich hoffe es wird verständlich, wozu das dient (komfortable Dateneingabe, die bei Bedarf schnelle Formatierungsänderung erlaubt, indem nur die keys der Umgebung geändert werden, nicht mehr die eigentlichen row-Einträge). Falls es schon Pakete gibt, die das zur Verfügung stellen, bin ich für Hinweise dankbar.

MB:

\documentclass[ngerman]{scrartcl}

\usepackage{filecontents}
\begin{filecontents}{fltable.sty}
%%Pakete
\usepackage{xkeyval,forloop,calc,array}

%%%%%%keys für env:fltable}
%%Präambel
\define@key{fltable}{tabpreamble}{\newcolumntype{\ tabpreamble}{#1}}
%%Tabellenspalten
\newcounter{colloop}\newcounter{maxflcol}
\define@key{fltable}{columns}{%
\def\vara{#1}%liste definieren
\setcounter{colloop}{0}
\@for\mycolumn:=\vara\do{%
\stepcounter{colloop}%
\expandafter\edef\csname mycolumn\the\value{colloop}\endcsname{\mycolumn}}% erzeuge die Spalten\mycolumn1 usw.
\setcounter{maxflcol}{\value{colloop}}%
}
%%%keys für coltypen festlegen
\newcommand{\makenewcoltype}[2]{%#1intern#2ausgabename
%%%%%1. keydef und Makro \mytype#1 erzeugen
\define@key{mycoltype}{#1}{%
\@namedef{mycoltype#1content}{##1}%
}%
\define@key{mycoltype}{#1name}{%
\@namedef{mycoltype#1name}{##1}%
}%
\@namedef{mycoltype#1name}{#2}%
\presetkeys{mycoltype}{#1={Voreinstellung}}{}%
}
%%drei coltypen
\makenewcoltype{name}{Name}
\makenewcoltype{geburt}{Geburtsdatum}
\makenewcoltype{steuer}{SteuerID}

%%%Verknüpfung von \mycol1 und \mycoltypename#1
\newcommand{\printfltab}[1]{%#1 entweder "`name"' oder "`content"'
\def\@tempb{}%
\forloop{colloop}{1}{\value{colloop} < \value{maxflcol}}%
{%%gehe durch jede Spalte und
% \edef\@tempb{\@tempb
\csname mycoltype\csname mycolumn\the\value{colloop}\endcsname#1\endcsname&}
% }%
%%das letzte Stück
% \edef\@tempb{\@tempb
\csname mycoltype\csname mycolumn\the\value{colloop}\endcsname#1\endcsname%
% }
% \@tempb
\\%
}
\presetkeys{fltable}{%Voreinstellungen
tabpreamble={||r||r||r||}
,columns={name,steuer,geburt}
}{}

\newenvironment{myfltable}[1]{%begine tabelle
\setkeys{fltable}{#1}
\begin{tabular}{\tabpreamble}
\hline\printfltab{name}\hline%Tabellenkopf
}{%Ende Tabelle
\hline\end{tabular}}

\newcommand{\myrow}[1]{%
\setkeys{mycoltype}{#1}
\printfltab{content}%Inhalte ausgeben
}
\end{filecontents}

\usepackage{fltable}

\begin{document}
Tabelle mit Voreinstellung:\par
\begin{myfltable}{}
\myrow{
name={Mickey Maus}
,steuer={123}
,geburt={32.03.2011}
}
\end{myfltable}

\vspace*{1cm}
Tabelle mit angepassten Spalten:\par
\begin{myfltable}{
tabpreamble={|l|l|r|}
,columns={name,geburt,steuer}
}
\myrow{name={Mickey Maus}
,steuer={123}
,geburt={32.03.2011}
}
\end{myfltable}

\end{document}

mechanicus
10-08-2011, 14:50
Hi,

soll das ein Paket werden :rolleyes:

Marco

rafael
10-08-2011, 20:17
soll das ein Paket werden :rolleyes:
Marco
ja, aber nur für den Hausgebrauch

mechanicus
10-08-2011, 20:18
ja, aber nur für den Hausgebrauch

Vielleicht kommt noch jemand vor dem WE dazu, sich deinem Problem anzunehmen. Ich schaffe es nicht. Ich würde dir aber mal empfehlen, einen Blick auf das Paket datotool zu werfen.

Marco

rafael
10-08-2011, 22:37
Ich würde dir aber mal empfehlen, einen Blick auf das Paket datotool zu werfen.

Hatte ich mir schon gedacht, dass dieses Paket vorgeschlagen wird.
Ich finde das Paket eignet sich super um strukturierte Informationen mit kleinen Einträge in Latex einzubinden. Problematisch finde ich nur, dass oftmals durch irgendwelche verschiedenen codings (z.B. in Excel erstellte Tabellen) der ganze Import oder die Überbrückung zu Latex scheitert (ich habe dann meist doch wieder die csv-Datei in einem Latexeditor erstelllen müssen, damit datatool pefekt läuft.) Deshalb möchte ich die auch aus Textpassagen bestehenden Daten lieber gleich in der .tex datei haben und dort editierfreundlich eingeben und gleichzeitig flexibel ausgeben.

mechanicus
12-08-2011, 17:25
Hi,

hier eine noch nichtangepasste Variante an xkeyval mit datatool:

\documentclass{article}
\usepackage{array}
\usepackage{datatool}
\begin{document}
\DTLnewdb{fltdatadb}
\DTLnewrow{fltdatadb}
\DTLnewdbentry{fltdatadb}{name}{Mickey Maus}
\DTLnewdbentry{fltdatadb}{steuer}{123}
\DTLnewdbentry{fltdatadb}{geburt}{32.03.2011}
\DTLnewrow{fltdatadb}
\DTLnewdbentry{fltdatadb}{name}{Hans Peter}
\DTLnewdbentry{fltdatadb}{steuer}{456}
\DTLnewdbentry{fltdatadb}{geburt}{05564654}
\DTLdisplaydb{fltdatadb}
\end{document}
Deinen Code schaue ich mir auch noch an ;)

Marco

rafael
13-08-2011, 21:59
Hallo Marco,

womöglich kann man meinen Ansatz mit datatool sehr fruchtbar verbinden. Datatool dient dabei als interne Repräsentation der Daten unter Nutzung der casesensitiven Umgangs mit Daten.

Ich werde das mal versuchen, wenn ich etwas mer Zeit habe

rafael
23-08-2011, 20:47
Ich habe noch einmal gebastelt. Den Ansatz mit Datatool zu verbinden, klingt zwar erst mal attraktiv, sorgt aber für wenig Anpassungsmöglichkeit.
Wöllte man beispielsweise innerhalb der fltable Umgebung doch etwas variieren, bsp:


\begin{myfltable}{
tabpreamble={|l|l|r|}
,columns={name,geburt,steuer}
}
\myrow{name={Mickey Maus}
,steuer={123}
,geburt={32.03.2011}
}
\multicolumn{3}{l}{EIne Unterbrechung, warum auch immer}\\
\myrow{name={Mickey Maus}
,steuer={123}
,geburt={32.03.2011}
}
\end{myfltable}


dann geht das nicht mit datatool. Etwas mehr flexibilität brauche ich schon.
Damit bleibt das ursprüngliche Problem der Tabellenausgabe mit Ampersand noch immer bestehen.

rafael
22-09-2011, 11:55
Da ich nach wie vor an einer Lösung interessiert bin, gebe ich noch einmal das Problem in die Runde.
Schwierigkeiten macht der Befehl

\printfltable{}
Dort sollen die Daten für eine ganze Zeile gesammelt und dann gesamt ausgegeben werden. Leider gehen durch die "&" die Daten verloren. Die Idee von mechanicus hatte auch nicht den gewünschten Erfolg gebracht (die Einpflegung seines Ansatzes ist in dem entsprechenden Bereich auskommentiert)


\documentclass[ngerman]{scrartcl}

\usepackage{filecontents}
\begin{filecontents}{fltable.sty}
%%Pakete
\usepackage{xkeyval,forloop,calc,array}

%%%%%%keys für env:fltable}
%%Präambel
\define@key{fltable}{tabpreamble}{\newcolumntype{\ tabpreamble}{#1}}
%%Tabellenspalten
\newcounter{colloop}\newcounter{maxflcol}
\define@key{fltable}{columns}{%
\def\vara{#1}%liste definieren
\setcounter{colloop}{0}
\@for\mycolumn:=\vara\do{%
\stepcounter{colloop}%
\expandafter\edef\csname mycolumn\the\value{colloop}\endcsname{\mycolumn}}% erzeuge die Spalten\mycolumn1 usw.
\setcounter{maxflcol}{\value{colloop}}%
}
%%%keys für coltypen festlegen
\newcommand{\makenewcoltype}[2]{%#1intern#2ausgabename
%%%%%1. keydef und Makro \mytype#1 erzeugen
\define@key{mycoltype}{#1}{%
\@namedef{mycoltype#1content}{##1}%
}%
\define@key{mycoltype}{#1name}{%
\@namedef{mycoltype#1name}{##1}%
}%
\@namedef{mycoltype#1name}{#2}%
\presetkeys{mycoltype}{#1={Voreinstellung}}{}%
}
%%drei coltypen
\makenewcoltype{name}{Name}
\makenewcoltype{geburt}{Geburtsdatum}
\makenewcoltype{steuer}{SteuerID}

%%%Verknüpfung von \mycol1 und \mycoltypename#1
\newcommand{\printfltab}[1]{%#1 entweder "`name"' oder "`content"'
\def\@tempb{}%
\forloop{colloop}{1}{\value{colloop} < \value{maxflcol}}%
{%%gehe durch jede Spalte und
% \edef\@tempb{\@tempb
\csname mycoltype\csname mycolumn\the\value{colloop}\endcsname#1\endcsname&}
% }%
%%das letzte Stück
% \edef\@tempb{\@tempb
\csname mycoltype\csname mycolumn\the\value{colloop}\endcsname#1\endcsname%
% }
% \@tempb
\\%
}
\presetkeys{fltable}{%Voreinstellungen
tabpreamble={||r||r||r||}
,columns={name,steuer,geburt}
}{}

\newenvironment{myfltable}[1]{%begine tabelle
\setkeys{fltable}{#1}
\begin{tabular}{\tabpreamble}
\hline\printfltab{name}\hline%Tabellenkopf
}{%Ende Tabelle
\hline\end{tabular}}

\newcommand{\myrow}[1]{%
\setkeys{mycoltype}{#1}
\printfltab{content}%Inhalte ausgeben
}
\end{filecontents}

\usepackage{fltable}

\begin{document}
Tabelle mit Voreinstellung:\par
\begin{myfltable}{}
\myrow{
name={Mickey Maus}
,steuer={123}
,geburt={32.03.2011}
}
\end{myfltable}

\vspace*{1cm}
Tabelle mit angepassten Spalten:\par
\begin{myfltable}{
tabpreamble={|l|l|r|}
,columns={name,geburt,steuer}
}
\myrow{name={Mickey Maus}
,steuer={123}
,geburt={32.03.2011}
}
\end{myfltable}

\end{document}

u_fischer
22-09-2011, 13:07
Du solltest den Tabelleninhalt besser in einem toks-Register sammeln. Ich würde auch empfehlen die Tabelle erst beim \end{Befehl} zu beginnen.

Hier etwas Code (aus einem alten Posting von Heiko Oberdiek) zum Thema Toks-Register:


Solutions:
* Construct the table contents outside the longtable in a toks
register:

\newtoks\litemtoks
\newcommand{\litem}[3][0]{%
\ifthenelse{\value{implevel}<#1}{}{%
\litemtoks=\expandafter{\the\litemtoks #2&#3\tabularnewline}%
}%

}

...
\litemtoks={}
\litem[1]{cell 1}{cell 2}
\litem{cell 3}{cell 4}
\litem[1]{cell 5}{cell 6}
...
\begin{longtable}{l|l}\the\litemtoks\end{longtable }

cookie170
22-09-2011, 13:59
Da ich nach wie vor an einer Lösung interessiert bin, gebe ich noch einmal das Problem in die Runde.
Schwierigkeiten macht der Befehl

\printfltable{}


Das scheint ja ein harter Brocken zu sein. Sag' mal, hast Du je erwogen, Dein Problem mit Lua und Luatex zu lösen? Lua beruht so ziemlich auf der Manipulation von Tabellen und ist _viel_ leichter verständlich als das hier!

Du könntest ja mal den Einstieg suchen, in dem Du schilderst, was Du eigentlich machen willst, so dass man's auch versteht ohne TeX-Kenntnisse.

Bitte, nur ein Vorschlag, bevor Du noch Tage an diesem Problem verbringst,

Gruß,

Alexander

rafael
23-09-2011, 10:03
Hier etwas Code (aus einem alten Posting von Heiko Oberdiek) zum Thema Toks-Register:

Ich werde noch nicht ganz schlau aus dem Ansatz.


\documentclass{scrartcl}

\usepackage{longtable,xifthen}
\newtoks\litemtoks
\newcommand{\litem}[3][0]{%
\ifthenelse{\value{implevel}<#1}{}{%
\litemtoks=\expandafter{\the\litemtoks #2&#3\tabularnewline}%
}%
}%

\begin{document}
\litemtoks={}
\litem[1]{cell 1}{cell 2}
\litem{cell 3}{cell 4}
\litem[1]{cell 5}{cell 6}

\begin{longtable}{l|l}
\the\litemtoks
\end{longtable}

\end{document}
Damit bekomme ich drei Fehlermeldungen ("You can't use \relax after \the <recently read> \@cimplevel")
Was ist eigentlich "implevel" und gibt es den counter in jeder Tabellenumgebung?

rafael
23-09-2011, 10:04
Das scheint ja ein harter Brocken zu sein. Sag' mal, hast Du je erwogen, Dein Problem mit Lua und Luatex zu lösen? Lua beruht so ziemlich auf der Manipulation von Tabellen und ist _viel_ leichter verständlich als das hier!
Ich habe leider noch keine Berührung mit Lua und Luatex gemacht. Wo sollte ich denn da anfangen?

u_fischer
23-09-2011, 10:11
Was ist eigentlich "implevel" und gibt es den counter in jeder Tabellenumgebung?

Nein, den gibt es nicht in jeder Umgebung, der gehörte irgendwie zu der alten Fragestellung. Du musst den Code schon anpassen. Wenn du ein bisschen nach \newtoks + tabular suchst, findest du bestimmt noch weitere Beispiele, wie man eine Tabelle füllt.