使用 LaTeX 制作零件清单?

使用 LaTeX 制作零件清单?

我有一份文档,其中描述了如何装修我的房子。现在有人想要一份附加文档(在附录中和/或作为额外的 CSV 文件),其中包含所有窗户和门等的零件清单。

如何生成在文档内部调用的宏的表格​​和/或 CSV 文件?

例如我想写这样的文档:

\documentclass[final,a4paper,11pt,oneside,openany]{memoir}

\usepackage[naustrian]{babel}

\usepackage[thmmarks]{ntheorem}
\usepackage{thm-restate}

\newcounter{reqcounter}
\newtheorem{RQ}[reqcounter]{Neu}

\begin{document}
\chapter{Dachgeschoss}
\section{Wohnzimmer}
% I am searching for a macro to be used like:
%\fenster{130/150}{1 flg Drehkipp rechts}{Fixrahmen von innen abnehmbar}{}

\appendix
% After using \fenster several times, I can create a list somewhere else in the document:
%\listoffenster
\end{document}

在本地具有类似以下 LaTeX 代码的效果,RQ 被定义为定理以为每个要求获取一个数字:

\begin{RQ}
Fenster mit 3-Scheiben Isolierverglasung, mit Rolladen und Fensterbank. %fixed text
Ausmaße: 130/150. % from 1st argument
Ausführung: 1 flg Drehkipp rechts % from 2nd argument
Insektenschutz: Fixrahmen von innen abnehmbar % from 3rd argument
% from 4th argument
\textit{Farbe: Innen Weiß, Außen weiß; Beschlag: Silber.} %fixed text
\end{RQ}

并在附录中创建一个表格(在上面的示例中使用 \listoffenster)和/或外部 CSV 文件(第一行是静态标题):

Floor;Room;Size;Ausführung;Insektenschutz;Kommentar
Dachgeschoss;Wohnzimmer;130/150;1 flg Drehkipp rechts;Fixrahmen von innen abnehmbar;

其中“Dachgeschoss”是章节,“Wohnzimmer”是调用宏的部分。

答案1


由于 30000 个字符的限制,我需要将我的答案分成两部分。

这是我的回答的第二部分。

第1部分包含考虑、解释和想法。

第2部分包含第 1 部分中引用的可编译示例。

如果你想点赞,请点赞只有一个两部分。这可以防止不公平的声誉获取。如果你想要反对,就投票给你想反对的任何部分。


承诺的例子:

%\listfiles
%\errorcontextlines=10000
\documentclass[final,a4paper,11pt,oneside,openany]{memoir}
%\documentclass[final,a4paper,11pt,oneside,openany]{book}
\usepackage{datatool}
\usepackage{xparse}
\usepackage{hyperref}
\usepackage{atveryend}
\usepackage{rerunfilecheck}

\usepackage{verbatim}

\makeatletter
%========================================================================
%  \immediategroup{<balanced text>}%
%------------------------------------------------------------------------
%  A local scope wherein <balanced text> is carried out while \write, 
%  \closeout and \openout are patched to work in terms of \immediate.
%------------------------------------------------------------------------
\newcommand\immediategroup[1]{%
  \begingroup
  \@ifdefinable\MyStuffsavedwrite{\let\MyStuffsavedwrite\write}%
  \@ifdefinable\MyStuffsavedopenout{\let\MyStuffsavedopenout\openout}%
  \@ifdefinable\MyStuffsavedcloseout{\let\MyStuffsavedcloseout\closeout}%
  \def\write{\immediate\MyStuffsavedwrite}%
  \def\openout{\immediate\MyStuffsavedopenout}%
  \def\closeout{\immediate\MyStuffsavedcloseout}%
  #1%
  \endgroup
}%
%========================================================================
%  \DATABASEFILECreateIfNotExistent{<base-name of databases and of .csv-file>}%
%                                  {<separator>}%
%                                  {<delimiter>}%
% - Creates database of name: <base-name of databases and of .csv-file>DataFromPreviousLaTeXRun
% - Creates database of name: <base-name of databases and of .csv-file>DataToBeWrittenAtEndOfThisLaTeXRun
%   These databases exist in TeX's memory during the LaTeX-run.
% - Triggers the writing of file  <base-name of databases and of .csv-file>.csv 
%   at the end of the LaTeX-run from the content of the database 
%   <base-name of databases and of .csv-file>DataToBeWrittenAtEndOfThisLaTeXRun
% - Initializes Counter-macro \<base-name of databases and of .csv-file>DataToBeWrittenAtEndOfThisLaTeXRunCnt
%   to 0.   That counter-macro is to hold the value of the field "PrimaryKey" of the data-base 
%   <base-name of databases and of .csv-file>DataToBeWrittenAtEndOfThisLaTeXRun 
%   and is incremented always right before writing another line/row to the that database.
%
% The memory-database <base-name of databases and of .csv-file>DataFromPreviousLaTeXRun is
% used for retrieving data. In case the file  <base-name of databases and of .csv-file>.csv 
% exists that database is initialized by reading that file. Otherwise it is
% initialized empty.It is not modified during the LaTeX-run.
% The data stems from the previous LaTeX-run.
%
% The memory-database <base-name of databases and of .csv-file>DataToBeWrittenAtEndOfThisLaTeXRun is
% used for writing/storing entries during the LaTeX-run. It is initialized empty.
% It is modified during the LaTeX-run. At the end of the LaTeX-run it is saved as
% file <base-name of databases and of .csv-file>.csv .
%
% At the end of the LaTeX-run both databases are compared. If they differ, then
% something has changed and you are informed that you need to do another LaTeX-run.
%
% <separator> is the separator of values in the .csv-file. Usually this is comma (,)
% , but in your question you specified that you wish to use semicolon (;).
%
% <delimiter>: In case a value contains <separator> it needs to be nested
% between two instances of <delimiter>. <delimiter> usually is the quotes-character (").
%------------------------------------------------------------------------
\newcommand\DATABASEFILECreateIfNotExistent[3]{%
  \DTLifdbexists{#1DataFromPreviousLaTeXRun}{}{%
    \begingroup
    \DTLsetseparator{#2}%
    \DTLsetdelimiter{#3}%
    \IfFileExists{#1.csv}{%
      \DTLloaddb{#1DataFromPreviousLaTeXRun}{#1.csv}%
    }{%
      \DTLgnewdb{#1DataFromPreviousLaTeXRun}%
    }%
    \endgroup
  }%
  \DTLifdbexists{#1DataToBeWrittenAtEndOfThisLaTeXRun}{}{%
    \DTLgnewdb{#1DataToBeWrittenAtEndOfThisLaTeXRun}%
    % --- Counter-macro for primary-key of database ---
    \expandafter\@ifdefinable\csname#1DataToBeWrittenAtEndOfThisLaTeXRunCnt\endcsname{%
      \expandafter\long\expandafter\gdef\csname#1DataToBeWrittenAtEndOfThisLaTeXRunCnt\endcsname{0}%
    }%
    % -------------------------------------------------
    \AfterLastShipout{%
      % This will save the ..DataToBeWrittenAtEndOfThisLaTeXRun-
      % database to file after the last \shipout. The last \shipout 
      % is triggered by \end{document}/\enddocument.
      \immediategroup{%
        \DTLsetseparator{#2}%
        \DTLsetdelimiter{#3}%
        \RerunFileCheck{#1.csv}{}{Database `#1' may have changed. Rerun LaTeX to get listings of database-entries etc right}%
        \DTLsavedb{#1DataToBeWrittenAtEndOfThisLaTeXRun}{#1.csv}%
      }%
      %% Check if content of database-token-register stemming from
      %% database-file of previous LaTeX-run differs from content of
      %% database-token-register stemming from database-file of 
      %% the current LaTeX-run.
      %% If so, something changed and you need to re-run LaTeX.
      %% Probably this should be omitted with large databases.
      %% Therefore this is turned into comments and a tesr via
      %% \RerunFileCheck is used instead.
      %\begingroup
      %\DTLsetseparator{#2}%
      %\DTLsetdelimiter{#3}%
      %\DTLgcleardb{#1DataToBeWrittenAtEndOfThisLaTeXRun}%
      %\DTLnewdbonloadfalse
      %\DTLloaddb{#1DataToBeWrittenAtEndOfThisLaTeXRun}{#1.csv}%
      %\edef\tempa{%
      %  \the\csname dtldb@#1DataFromPreviousLaTeXRun\endcsname
      %  \the\csname dtlkeys@#1DataFromPreviousLaTeXRun\endcsname
      %  \the\csname dtlrows@#1DataFromPreviousLaTeXRun\endcsname
      %  \the\csname dtlcols@#1DataFromPreviousLaTeXRun\endcsname
      %}%
      %\edef\tempb{%
      %  \the\csname dtldb@#1DataToBeWrittenAtEndOfThisLaTeXRun\endcsname
      %  \the\csname dtlkeys@#1DataToBeWrittenAtEndOfThisLaTeXRun\endcsname
      %  \the\csname dtlrows@#1DataToBeWrittenAtEndOfThisLaTeXRun\endcsname
      %  \the\csname dtlcols@#1DataToBeWrittenAtEndOfThisLaTeXRun\endcsname
      %}%
      %\ifx\tempa\tempb
      %  \endgroup
      %\else
      %  \endgroup
      %  \@latex@warning@no@line{%
      %     Database `#1' may have changed.
      %     Rerun to get listings of entries etc right%
      %   }%
      %\fi
    }%
  }%
}%
%=========================================================================
% Infrastructure for triggering a warning in case the value of a document-
% wide property was requested at a moment in time when the property didn't
% exist (yet).
%-------------------------------------------------------------------------
\AfterLastShipout{\PropertyValuesNotFound}%
\newcommand*\PropertyValuesNotFound{}%
\newcommand*\PropertyValuesNotFoundTrue{%
  \gdef\PropertyValuesNotFound{\@latex@warning@no@line {There were undefined properties}}%
}%
\ExplSyntaxOn
%=========================================================================
% Property-List for properties that are to be maintained document-wide
% during the LaTeX-run. Values can change during the LaTeX-run.
% If you want to store the values which some properties have at a specific
% moment in time during the LaTeX-run, you can use the macro
% \DatabaseRowFromSomeOfThisDocumentsProperties
% for storing these properties' current values as another row of a
% database of name <base-name of databases and of .csv-file>DataToBeWrittenAtEndOfThisLaTeXRun
%-------------------------------------------------------------------------
\prop_new:N {\g__MyStuff_ThisDocumentsProperties_prop}
\prop_gput:Nnn \g__MyStuff_ThisDocumentsProperties_prop{Primary-Key}{0}
%=========================================================================
% expl3-scratch-variables:
%-------------------------------------------------------------------------
\tl_new:N {\l__MyStuff_ExtractedProperty_tl}
\clist_new:N{\l__MyStuff_PropertyNames_clist}
\bool_new:N \g__MyStuff_NewDatabaseRow_bool
\cs_new:Nn \__MyStuff_ExpandedDatabaseName: {}
%=========================================================================
% Set document-wide properties' values _globally_ by providing a
% <property1>=<value1>, <property2>=<value2>, ..., <propertyN>=<valueN>-list:
% \SetSomeOfThisDocumentsPropertiesFromKeyValList{%
%    <property1>=<value1>, <property2>=<value2>, ..., <propertyN>=<valueN>
% }%
%
% If a property doesn't exist it is created anew automatically.
% If a property does exist, its value is overridden.
%-------------------------------------------------------------------------
\NewDocumentCommand{\SetSomeOfThisDocumentsPropertiesFromKeyValList}{m}{
  \keyval_parse:NNn \__MyStuff_GSetSomeOfThisDocumentsPropertiesFromKeyValList:n
                    \__MyStuff_GSetSomeOfThisDocumentsPropertiesFromKeyValList:nn
                    {#1}
}
\cs_new:Nn \__MyStuff_GSetSomeOfThisDocumentsPropertiesFromKeyValList:n { 
  \__MyStuff_GSetSomeOfThisDocumentsPropertiesFromKeyValList:nn {#1}{\DTLstringnull}
}
\cs_new:Nn \__MyStuff_GSetSomeOfThisDocumentsPropertiesFromKeyValList:nn {
  \group_begin:
  \cs_set:Npn \protect { \noexpand\protect\noexpand }
  \exp_args:Nnx \use:n 
                { 
                  \exp_args:Nnx \use:n 
                                { \prop_gput:Nnn \g__MyStuff_ThisDocumentsProperties_prop }
                                {#1} 
                }
                {#2}
  % \prop_gput:Nxx \g__MyStuff_ThisDocumentsProperties_prop{#1}{#2}
  \group_end:
} 
%=========================================================================
% Create a row of a database 
% <base-name of databases and of .csv-file>DataToBeWrittenAtEndOfThisLaTeXRun
% from current values of document-wide properties by specifying a comma-
% separated list of property-names.
% Names of properties will be used as names of fields/columns of the database.
% If a field/column doesn't yet exist in the database, it will be created automatically.
% If the database itself doesn't exist, it will be created automatically
% by \DATABASEFILECreateIfNotExistent. (That's why you need to specify
% <separator> and <delimiter>.)
% If a property doesn't exist, an error-message is raised and datatool's
% null-value for strings is provided as value to the database.
%
%  \DatabaseRowFromSomeOfThisDocumentsProperties{<base-name of databases and of .csv-file>}%
%                                               {<separator>}%
%                                               {<delimiter>}%
%                                               {<Property1>, <Property2>,..., <PropertyN>}%
%
%-------------------------------------------------------------------------
\NewDocumentCommand{\DatabaseRowFromSomeOfThisDocumentsProperties}{mmmm}{
  \bool_gset_true:N \g__MyStuff_NewDatabaseRow_bool
  \cs_set:Nx \__MyStuff_ExpandedDatabaseName: {#1DataToBeWrittenAtEndOfThisLaTeXRun}
  \exp_args:Nx  \DATABASEFILECreateIfNotExistent{#1}{#2}{#3}
  \clist_set:Nn \l__MyStuff_PropertyNames_clist {#4}
  \cs_gset:cpx {\__MyStuff_ExpandedDatabaseName: Cnt} 
               {\number\numexpr\use:c{\__MyStuff_ExpandedDatabaseName: Cnt}+1\relax} 
  \exp_args:Nnx \use:n 
                { 
                  \prop_gput:Nnn \g__MyStuff_ThisDocumentsProperties_prop {PrimaryKey} 
                }
                {\use:c{\__MyStuff_ExpandedDatabaseName: Cnt}}
  % \prop_gput:Nxx \g__MyStuff_ThisDocumentsProperties_prop {PrimaryKey} {\use:c{\__MyStuff_ExpandedDatabaseName: Cnt}}
  \__MyStuff_DatabaseEntryFromThisDocumentsProperty:n {PrimaryKey}
  \clist_map_function:NN \l__MyStuff_PropertyNames_clist \__MyStuff_DatabaseEntryFromThisDocumentsProperty:x
}
\cs_new:Nn \__MyStuff_DatabaseEntryFromThisDocumentsProperty:n {
  \prop_get:NnN \g__MyStuff_ThisDocumentsProperties_prop {#1} \l__MyStuff_ExtractedProperty_tl
  \exp_args:NV \quark_if_no_value:nTF \l__MyStuff_ExtractedProperty_tl {
    \protect\PropertyValuesNotFoundTrue
    % I am too lazy to delve into expl3's l3msg
    \@latex@warning{Macro~ \token_to_str:N\DatabaseRowFromSomeOfThisDocumentsProperties:\space
    Property~`#1'~undefined~-~using~value~\DTLstringnull\space instead~-}
    \tl_set:Nn \l__MyStuff_ExtractedProperty_tl {\DTLstringnull}
  }{}
  \__MyStuff_DatabaseRowFromPropertyAndValue:onV \__MyStuff_ExpandedDatabaseName: {#1} \l__MyStuff_ExtractedProperty_tl
}
\cs_generate_variant:Nn \__MyStuff_DatabaseEntryFromThisDocumentsProperty:n {x}
\cs_new:Nn \__MyStuff_DatabaseRowFromPropertyAndValue:nnn {
  \DTLifhaskey{#1}{#2}{}{
    \DTLaddcolumn{#1}{#2}
  }
  \bool_if:NTF \g__MyStuff_NewDatabaseRow_bool{
     \DTLnewrow{#1}
  }{}
  \bool_gset_false:N \g__MyStuff_NewDatabaseRow_bool
  \group_begin:
  % \cs_set:Npn \protect { \noexpand\protect\noexpand }
  \cs_set:Npn \protect { \token_to_str:N  }
  \exp_args:Nnx \use:n {\DTLnewdbentry{#1}{#2}} {#3}
  \group_end:
}
\cs_generate_variant:Nn \__MyStuff_DatabaseRowFromPropertyAndValue:nnn{onV}
%=========================================================================
% Retrieve the current value of a document-wide property.
%
%  \GetDocumentsPropertyValue{<Property>}
%
% If a property doesn't exist, an error-message is raised and the
% tokens  \textsf{??}  are provided.
%
% Not used in the following code. But I wasn't aware of that at the time
% of composing all this. Probably it may be useful in other scenarios.
%-------------------------------------------------------------------------
\NewDocumentCommand{\GetDocumentsPropertyValue}{m}{
  \__GetDocumentsPropertyValue:x{#1}
}
\cs_new:Nn \__GetDocumentsPropertyValue:n {
  \prop_get:NnN \g__MyStuff_ThisDocumentsProperties_prop {#1} \l__MyStuff_ExtractedProperty_tl
  \exp_args:NV \quark_if_no_value:nTF \l__MyStuff_ExtractedProperty_tl {
    \protect\PropertyValuesNotFoundTrue
    % I am too lazy to delve into expl3's l3msg
    \@latex@warning{Macro~\token_to_str:N\GetDocumentsPropertyValue:\space
    Property~`#1'~undefined~-~using~value~\token_to_str:N\textsf{??}~instead~-}
    \tl_set:Nn \l__MyStuff_ExtractedProperty_tl {\textsf{??}}
  }{}
  \tl_use:N \l__MyStuff_ExtractedProperty_tl
}
\cs_generate_variant:Nn \__GetDocumentsPropertyValue:n {x}
%=========================================================================
%  Via datatool-package's \DTLforeach iterate on the rows
%  of the database  <base-name of databases and of .csv-file>DataFromPreviousLaTeXRun.
%
%  If the database itself doesn't exist, it will be created automatically
%  by \DATABASEFILECreateIfNotExistent. (That's why you need to specify
%  <separator> and <delimiter>.)
%
% \DoWithDatabaseProperties{<base-name of databases and of .csv-file>}%
%                          {<separator>}%
%                          {<delimiter>}%
%                          [<condition>]%
%                          {<assign list>}%
%                          {<text>}%
%
% <base-name of databases and of .csv-file>, <separator> and <delimiter> are
% the same as above. 
% <condition>, <assign list> and <text> are the same as with \DTLforeach
% of the datatool-package.
%-------------------------------------------------------------------------
\NewDocumentCommand\DoWithDatabaseProperties{mmmo}{
  \exp_args:Nx \DATABASEFILECreateIfNotExistent {#1}{#2}{#3}
  \IfNoValueTF{#4}{\exp_args:Nnx \use:n {\DTLforeach*}}
                  {\exp_args:Nnx \use:n {\DTLforeach*[{#4}]}}
                  {#1DataFromPreviousLaTeXRun}
}
\ExplSyntaxOff
\makeatother
%=========================================================================
%  Now the individual building blocks of the infrastructure for managing 
%  document-wide properties via databases and .csv files are in place. 
%  They can now be used for implementing the macros at user level, which
%  is straightforward:
%=========================================================================
% \ListOf...-commands can easily be implemented in terms of
% \DoWithDatabaseProperties.
%
% A scratch-switch which can be initialized by the \ListOf...-command
% and toggled by \DoWithDatabaseProperties's <text>-argument. This 
% switch is intended to indicate whether at least one row of the 
% database already ended up as an entry of the list.
% 
% E.g., only in this case a heading for the list in question is needed.
% Only in this case starting/ending some environment is needed, e.g., 
% description or tabular.
%
\newif\ifNoDatabaseEntryEndedUpInTheListYet
\global\NoDatabaseEntryEndedUpInTheListYettrue
%=========================================================================
% An example of how to implement \ListOfFenster by means of
% nested description-environments and \DoWithDatabaseProperties (whose
% underlying macro is \DTLforeach):
%-------------------------------------------------------------------------
\newcommand\ListOfFenster{%
  \global\NoDatabaseEntryEndedUpInTheListYettrue
  \DoWithDatabaseProperties{Parts}{;}{"}%
                           [{\equal{Fenster}{\ArtDesTeils}}]%
                           {%
                              \PrimaryKey=PrimaryKey,%
                              \NummerDesTeils=NummerDesTeils,%
                              \ArtDesTeils=ArtDesTeils,%
                              \Stockwerkname=Stockwerkname,%
                              \Zimmer=Zimmer,%
                              \Ausmasze=Ausmasze,%
                              \Ausfuehrung=Ausfuehrung,%
                              \Insektenschutz=Insektenschutz,%
                              \Kommentar=Kommentar,%
                              \Destination=Destination%
                           }%
                           {%
                             \ifNoDatabaseEntryEndedUpInTheListYet
                                \global\NoDatabaseEntryEndedUpInTheListYetfalse
                                \section*{Liste der Fenster}%
                                \begin{description}%
                             \fi
                             \item[\hyperlink
                                   {\Destination}%
                                   {%
                                     \PrintAssignListElement\NummerDesTeils 
                                     ~(\PrintAssignListElement\Stockwerkname, 
                                     \PrintAssignListElement\Zimmer)%
                                   }]\hfill\null
                             \begin{description}%
                             \AssignListElementDescriptionItem{\Ausmasze}{Maße}%
                             \AssignListElementDescriptionItem{\Ausfuehrung}{Ausführung}%
                             \AssignListElementDescriptionItem{\Insektenschutz}{Insektenschutz}%
                             \AssignListElementDescriptionItem{\Kommentar}{Kommentar}%
                             \end{description}%
                           }%
  \ifNoDatabaseEntryEndedUpInTheListYet\else\end{description}\fi
}%
\newcommand\PrintAssignListElement[1]{\DTLifnull{#1}{\textsf{??}}{#1}}%
\newcommand\AssignListElementDescriptionItem[2]{%
  \DTLifnullorempty{#1}{%
    \DTLifnull{#1}{\item[{#2:}]\PrnProp\textsf{??}}{}%
  }{%
    \item[{#2:}]#1%
  }%
}%
%=========================================================================
% Some elements of your database of parts shall come from the arguments
% of commands like \chapter or \section.
% One could patch these commands to also fulfill the purpose of
% setting the corresponding document-wide properties' values.
% Instead I define variants of these commands with slightly different
% names which set the corresponding document-wide properties' values
% and call the corresponding sectioning-commands:
%=========================================================================
\newcommand\FloorChapter[1]{%
  \SetSomeOfThisDocumentsPropertiesFromKeyValList{Stockwerkname=#1}%
  \chapter{#1}%
}
\newcommand\RoomSection[1]{%
  \SetSomeOfThisDocumentsPropertiesFromKeyValList{Zimmer=#1}%
  \section{#1}%
}%
%=========================================================================
% The \Fenster-Command sets some document-wide properties from its
% arguments, delivers an RQ-environment, sets some other document-wide 
% property from the current value of the counter underlying the RQ-environment
% and then creates a(nother) database-row from the current values of
% the document-wide properties:
%=========================================================================
\newcommand\Fenster[4]{%
  \SetSomeOfThisDocumentsPropertiesFromKeyValList{%
     ArtDesTeils=Fenster, 
     Ausmasze=#1, Ausfuehrung=#2, Insektenschutz=#3, Kommentar=#4%
  }%
  \begin{RQ}
  Fenster mit 3-Scheiben Isolierverglasung, mit Rolladen und Fensterbank.\\
  Ausmaße: #1.\\
  Ausführung: #2.\\
  Insektenschutz: #3.\\
  \textit{Farbe: Innen Weiß, Außen weiß; Beschlag: Silber.}%
  \ifcat$\detokenize{#4}$\else\\Kommentar: #4\fi
  \end{RQ}
  \SetSomeOfThisDocumentsPropertiesFromKeyValList{%
      NummerDesTeils=Neu\protect~\thereqcounter,
      Destination=\csname @currentHref\endcsname
  }%
  \DatabaseRowFromSomeOfThisDocumentsProperties{Parts}{;}{"}{%
     NummerDesTeils, ArtDesTeils, Stockwerkname, Zimmer, Ausmasze, 
     Ausfuehrung, Insektenschutz, Kommentar, Destination,
  }%
}%


\usepackage[naustrian]{babel}

\usepackage[thmmarks]{ntheorem}
\usepackage{thm-restate}

\newcounter{reqcounter}
\newtheorem{RQ}[reqcounter]{Neu}

\begin{document}

\ListOfFenster

\FloorChapter{Erdgeschoss}
\RoomSection{Toilette}
\Fenster{50/80}{1 flg Keinkipp mitte}{Fixrahmen von aussen einsehbar}{Kommentar zu diesem Fenster}

\FloorChapter{Dachgeschoss}
\RoomSection{Wohnzimmer}
\Fenster{130/150}{1 flg Drehkipp rechts}{Fixrahmen von innen abnehmbar}{}

This is the content of the automatically created .csv-file \verb|Parts.csv|\,:

\begingroup

\tiny

\verbatiminput{Parts.csv}

\endgroup

And once more:

\ListOfFenster

\end{document}

.pdf 输出的图像:

在此处输入图片描述 在此处输入图片描述 在此处输入图片描述

Parts.csv在 LaTeX 运行期间自动写入的文件:

PrimaryKey;NummerDesTeils;ArtDesTeils;Stockwerkname;Zimmer;Ausmasze;Ausfuehrung;Insektenschutz;Kommentar;Destination
1;Neu~1;Fenster;Erdgeschoss;Toilette;50/80;1 flg Keinkipp mitte;Fixrahmen von aussen einsehbar;Kommentar zu diesem Fenster;RQ.1
2;Neu~2;Fenster;Dachgeschoss;Wohnzimmer;130/150;1 flg Drehkipp rechts;Fixrahmen von innen abnehmbar;;RQ.2

TeX-distribution/format/documentclass/packages/files 正在使用 - 摘自 .log 文件,在取消注释 -command 时创建\listfiles

pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=pdflatex)
LaTeX2e <2020-10-01> patch level 4
L3 programming layer <2021-02-18>

memoir.cls -- 2020/10/04 v3.7n configurable book, report, article document class
(
 Package abstract [2008/07/23] emulated by memoir.
 Package appendix [2008/07/23] emulated by memoir.
 Package booktabs [2016/05/16] emulated by memoir.
 Package ccaption [2008/07/23] emulated by memoir.
 Package changepage [2008/07/23] emulated by memoir.
 Package chngcntr [2008/07/23] emulated by memoir.
 Package chngpage [2008/07/23] emulated by memoir.
 Package crop emulated by memoir.
 Package enumerate [2008/07/23] emulated by memoir.
 Package epigraph [2008/07/23] emulated by memoir.
 Package ifmtarg [2008/07/23] emulated by memoir.
 Package index [2008/07/23] emulated by memoir.
 Package makeidx [2008/07/23] emulated by memoir.
 Package moreverb [2008/07/23] emulated by memoir.
 Package mparhack [2008/07/23] emulated by memoir.
 Package needspace [2008/07/23] emulated by memoir.
 Package newfile [2008/07/23] emulated by memoir.
 Package nextpage [2008/07/23] emulated by memoir.
 Package pagenote [2008/07/23] emulated by memoir.
 Package parskip [2008/07/23] emulated by memoir.
 Package patchcmd [2008/07/23] emulated by memoir.
 Package setspace [2008/07/23] emulated by memoir.
 Package shortvrb [2008/07/23] emulated by memoir.
 Package showidx [2008/07/23] emulated by memoir.
 Package titleref [2008/07/23] emulated by memoir.
 Package titling [2008/07/23] emulated by memoir.
 Package tocbibind [2008/07/23] emulated by memoir.
 Package tocloft [2008/07/23] emulated by memoir.
 Package tocvsec2 [2008/07/23] emulated by memoir.
 Package verbatim [2008/07/23] emulated by memoir.
 Package verse [2008/07/23] emulated by memoir.
)
aliasctr.sty -- 2020/08/01 v0.72
amsbsy.sty -- 1999/11/29 v1.2d Bold Symbols
amsgen.sty -- 1999/11/30 v2.0 generic functions
amsmath.sty -- 2020/09/23 v2.17i AMS math features
amsopn.sty -- 2016/03/08 v2.02 operator names
amstext.sty -- 2000/06/29 v2.01 AMS text
array.sty -- 2020/10/01 v2.5c Tabular extension package (FMi)
atbegshi-ltx.sty -- 2020/08/17 v1.0a Emulation of the original atbegshi package with kernel methods
atveryend-ltx.sty -- 2020/08/19 v1.0a Emulation of the original atvery package with kernel methods
auxhook.sty -- 2019-12-17 v1.6 Hooks for auxiliary files (HO)
babel.sty -- 2021/02/22 3.54 The Babel package
bigintcalc.sty -- 2019/12/15 v1.5 Expandable calculations on big integers (HO)
bitset.sty -- 2019/12/09 v1.3 Handle bit-vector datatype (HO)
datatool-base.sty -- 2019/09/27 v2.32 (NLCT)
datatool-fp.sty -- 2019/09/27 v2.32 (NLCT)
datatool.sty -- 2019/09/27 v2.32 (NLCT)
dcolumn.sty -- 2014/10/28 v1.06 decimal alignment package (DPC)
defpattern.sty -- 1994/10/12
delarray.sty -- 2014/10/28 v1.01 array delimiter package (DPC)
etexcmds.sty -- 2019/12/15 v1.7 Avoid name clashes with e-TeX commands (HO)
etoolbox.sty -- 2020/10/05 v2.5k e-TeX tools for LaTeX (JAW)
expl3.sty -- 2021-02-18 L3 programming layer (loader) 
fp-addons.sty -- 1995/03/15
fp-basic.sty -- 1996/05/13
fp-eqn.sty -- 1995/04/03
fp-eval.sty -- 1995/04/03
fp-exp.sty -- 1995/04/03
fp-pas.sty -- 1994/08/29
fp-random.sty -- 1995/02/23
fp-snap.sty -- 1995/04/05
fp-trigo.sty -- 1995/04/14
fp-upn.sty -- 1996/10/21
gettitlestring.sty -- 2019/12/15 v1.6 Cleanup title references (HO)
hpdftex.def -- 2021-02-10 v7.00j Hyperref driver for pdfTeX
hycolor.sty -- 2020-01-27 v1.10 Color options for hyperref/bookmark (HO)
hyperref-langpatches.def -- 2021-02-10 v7.00j Hyperref: patches for babel languages
hyperref.sty -- 2021-02-10 v7.00j Hypertext links for LaTeX
iftex.sty -- 2020/03/06 v1.0d TeX engine tests
ifthen.sty -- 2014/09/29 v1.1c Standard LaTeX ifthen package (DPC)
infwarerr.sty -- 2019/12/03 v1.5 Providing info/warning/error messages (HO)
intcalc.sty -- 2019/12/15 v1.3 Expandable calculations with integers (HO)
kvdefinekeys.sty -- 2019-12-19 v1.6 Define keys (HO)
kvoptions.sty -- 2020-10-07 v3.14 Key value format for package options (HO)
kvsetkeys.sty -- 2019/12/15 v1.18 Key value parser (HO)
l3backend-pdftex.def -- 2021-02-18 L3 backend support: PDF output (pdfTeX)
letltxmacro.sty -- 2019/12/03 v1.6 Let assignment for LaTeX macros (HO)
ltxcmds.sty -- 2020-05-10 v1.25 LaTeX kernel commands for general use (HO)
mem11.clo -- 2008/01/30 v0.3 memoir class 11pt size option
memhfixc.sty -- 2019/10/24 v1.18 nameref/hyperref package fixes for memoir class
nameref.sty -- 2021-04-02 v2.47 Cross-referencing by name of section
naustrian.ldf -- 2020/07/21 v2.12 German support for babel (post-1996 orthography)
ntheorem.sty -- 2011/08/15 1.33
parseargs.sty -- 2020/08/01 v0.72
pd1enc.def -- 2021-02-10 v7.00j Hyperref: PDFDocEncoding definition (HO)
pdfescape.sty -- 2019/12/09 v1.15 Implements pdfTeX's escape features (HO)
pdftexcmds.sty -- 2020-06-27 v0.33 Utility functions of pdfTeX for LuaTeX (HO)
puenc.def -- 2021-02-10 v7.00j Hyperref: PDF Unicode definition (HO)
refcount.sty -- 2019/12/15 v3.6 Data extraction from label references (HO)
rerunfilecheck.sty -- 2019/12/05 v1.9 Rerun checks for auxiliary files (HO)
substr.sty -- 2009/10/20 v1.2 Handle substrings
tabularx.sty -- 2020/01/15 v2.11c `tabularx' package (DPC)
textcase.sty -- 2019/09/14 v1.00 Text only upper/lower case changing (DPC)
thm-autoref.sty -- 2020/08/01 v0.72
thm-kv.sty -- 2020/08/01 v0.72
thm-listof.sty -- 2020/08/01 v0.72
thm-ntheorem.sty -- 2020/08/01 v0.72
thm-patch.sty -- 2020/08/01 v0.72
thm-restate.sty -- 2020/08/01 v0.72
thmtools.sty -- 2020/08/01 v0.72
uniquecounter.sty -- 2019/12/15 v1.4 Provide unlimited unique counter (HO)
url.sty -- 2013/09/16 ver 3.4 Verb mode for urls, etc.
xfor.sty -- 2009/02/05 v1.05 (NLCT)
xkeyval.sty -- 2020/11/20 v2.8 package option processing (HA)
xkeyval.tex -- 2014/12/03 v2.7a key=value parser (HA)
xparse-2020-10-01.sty -- 2020-10-01
xparse.sty -- 2021-01-09 L3 Experimental document command parser

答案2


由于 30000 个字符的限制,我需要将我的答案分成两部分。

这是我的回答的第一部分。

第1部分包含考虑、解释和想法。

第2部分包含第 1 部分中引用的可编译示例。

如果你想点赞,请点赞只有一个两部分。这可以防止不公平的声誉获取。如果你想要反对,就投票给你想反对的任何部分。


您的请求可以拆分成几个需要合并的方面:

  1. 您希望维护外部.csv 文件。

    我建议采取以下方法:

    通过 Nicola Talbot 博士的包裹数据工具从 LaTeX 运行开始维护LaTeX 内存中的数据库:

    一个内存数据库用于存储数据它将出现在 LaTeX 运行结束时的 .csv 文件中。 该数据库的内容在 LaTeX 运行结束时写入 .csv 文件中。

    另一个内存数据库是通过读取 .csv 文件创建的这是在上一次 LaTeX 运行期间产生的。 该数据库用于检索数据用于创建.pdf 文件的输出。

    这样,同时尝试在数据库中存储和从数据库中读取不会发生冲突,并且在 LaTeX 运行结束时产生的数据也可以在 LaTeX 运行开始时使用,尽管它源于上一次 LaTeX 运行,这意味着您需要多次 LaTeX 运行直到一切都匹配。

    \refstepcounter(这基本上与由命令/ \label/ \ref/等组成的 LaTeX 交叉引用机制的概念相同。\paggeref不同之处在于数据库不是通过外部 .aux 文件维护,而是通过外部 .csv 文件维护。)

    在示例中第2部分这个答案维护一个数据库⟨base name of databases and .csv‑file⟩⁠DataToBeWrittenAtEndOfThisLaTeXRun和一个数据库⟨base name of databases and .csv‑file⟩⁠DataFromPreviousLaTeXRun和一个.csv文件 ⟨base name of databases and .csv‑file⟩⁠.csv是由宏启动的

    \DATABASEFILECreateIfNotExistent{⟨base name of databases and .csv-file⟩}%
                                    {⟨separator⟩}%
                                    {⟨delimiter⟩}%

  2. 您希望维护零件列表。您可以将“零件”视为具有某些属性的集合。因此您需要机制来

    • 通过名称引入新属性
    • 设置这些属性的当前值
    • 根据某些属性的当前值的集合创建数据库条目。

    我建议一个类似于 LaTeX 的概念\refstepcounter。内部由分段命令( 、、 ...)\refstepcounter调用,并设置通过宏、、等实现的属性值,这些属性值又被命令用于将条目写入 .aux 文件。\section\caption\@currentlabel\@currentHref\label\newlabel

    在示例中第2部分这个答案引入属性(如果尚未引入)并全局设置它们的当前值是通过宏完成的

    \SetSomeOfThisDocumentsPropertiesFromKeyValList{%
      ⟨propertyA⟩=⟨valueA⟩, ⟨propertyB⟩=⟨valueB⟩, ...%
    }%
    。如果您未指定值,数据工具字符串的空值被假定。
    表示属性名称的标记和表示属性值的标记都通过 expl3 的 x 扩展进行扩展。对于后者,我尝试考虑 LaTeX 2ε-\protect机制。

    在示例中第2部分这个答案将属性的当前值集合存储为数据库的新行⟨base name of databases and .csv‑file⟩⁠DataToBeWrittenAtEndOfThisLaTeXRun是通过宏完成的

    \DatabaseRowFromSomeOfThisDocumentsProperties{⟨base name of databases and .csv-file⟩}%
                                                 {⟨separator⟩}%
                                                 {⟨delimiter⟩}%
                                                 {⟨propertyA⟩, ⟨propertyB⟩, ...}%

    如果数据库⟨base name of databases and .csv‑file⟩⁠DataToBeWrittenAtEndOfThisLaTeXRun尚不存在,则将重新创建它们,并在 LaTeX 运行结束时触发⟨base name of databases and .csv‑file⟩⁠DataFromPreviousLaTeXRun写入文件。⟨base name of databases and .csv‑file⟩⁠.csv

    如果该文件⟨base name of databases and .csv‑file⟩⁠.csv在之前的 LaTeX 运行中已经存在,它的内容将被读取到数据库中⟨base name of databases and .csv‑file⟩⁠DataFromPreviousLaTeXRun,否则数据库⟨base name of databases and .csv‑file⟩⁠DataFromPreviousLaTeXRun将被视为空的。

    在 LaTeX 运行结束时,将比较两个数据库。如果它们不同,则表示发生了一些变化,并且会通知您需要再进行一次 LaTeX 运行。

    ⟨separator⟩是 .csv 文件中值的分隔符。通常为逗号 ( ,) ,但在您的问题中,您指定要使用分号 ( ;)。

    ⟨delimiter⟩:如果值包含,⟨separator⟩则需要将其嵌套在两个实例之间⟨delimiter⟩⟨delimiter⟩通常是引号字符(")。

  3. 您的示例包含\chapter{Dachgeschoss}\section{Wohnzimmer}。似乎您的数据库的某些元素/某些属性的值来自分段命令的参数,例如\chapter(这是为了设置属性“floor”的值)和\section(这是为了设置属性“room”的值)。这意味着除了通常的用途之外,您希望为这些分段命令分配一个额外的用途,即表示随后提到的 parts/windows/Fenster 所具有的某些属性的值。这意味着这些分段命令也需要修补才能实现此目的。在我看来,这是最困难的方面,因为为了增加实现目的,命令需要更改/修补,而相关的分段命令也有带星号的变体和可选参数,例如,您没有指定在指定可选参数的情况下该怎么做。

  4. 您需要一些基础设施来创建\listof...命令,这些命令通过迭代数据库来创建任何列表 ⟨base name of databases and .csv‑file⟩⁠DataFromPreviousLaTeXRun

    在示例中第2部分这个答案的宏

    \DoWithDatabaseProperties{⟨base name of databases and .csv‑file⟩}%
                             {⟨separator⟩}%
                             {⟨delimiter⟩}%
                             [⟨condition⟩]%
                             {⟨assign list⟩}%
                             {⟨text⟩}%
    是一个用于应用的包装器数据工具
    \DTLforeach[⟨condition⟩]%
                {⟨database name}%
                {⟨assign list⟩}%
                {⟨text⟩}%
    更方便地访问数据库,⟨base name of databases and .csv‑file⟩⁠DataFromPreviousLaTeXRun同时确保数据库(如果尚不存在)被创建,并且能够在将内容写入 .csv 文件时指定值⟨separator⟩⟨delimiter⟩

    ⟨assign list⟩‑ 参数中,将这些属性的名称分配给宏,这些属性的值存储在数据库中,以便数据库具有具有相应名称的字段。在 ‑ 参数中,⟨text⟩您可以使用这些宏来表示来自数据库行中单个字段的相应值。

    提供了一个临时开关\ifNoDatabaseEntryEndedUpInTheListYet。它可以通过 ‑命令初始化\ListOf...并在\DoWithDatabaseProperties的 ‑⟨text⟩参数内切换。此开关旨在指示数据库中至少一行是否已成为列表的条目。例如,只有在这种情况下才需要列表的标题。例如,只有在这种情况下才需要启动/结束某些环境;例如,描述/表格。

相关内容