
Ich habe gelernt, wie man Anforderungen mit eindeutigen IDs erstelltin diesem Beitrag. Nun möchte ich für jede Anforderung eine Testmethode hinzufügen - im Code denke ich dabei an so etwas:
\Requirement{SOMEID}{This is the requirement text.}{This describes the testmethod.}
Später, in einem anderen Abschnitt, möchte ich diese Testmethoden durchlaufen, um sie aufzulisten. Am Ende suche ich nach so etwas wie:
Der erste Teil ist mir klar, aber wie kann man einen Parameter (die Testmethoden) „speichern“, um ihn später zu verwenden?
Antwort1
\csname
Sie benötigen einen „assoziativen Speicher“, der mit oder mit bereits von bereitgestellten Datenstrukturen implementiert werden kann expl3
.
Hier \Requirement
wird die ID in einer Sequenz gespeichert, um sie zu indizieren, dann werden beide Texte in einer Eigenschaftenliste gespeichert. Das Speichern des Anforderungstexts wird hier nicht wirklich verwendet, aber Sie können sich entscheiden, ihn auf eine andere Weise zu verwenden, also ist es besser, ihn ebenfalls zu speichern.
Bei Bedarf kann die Sequenz so zugeordnet werden, dass alle zum Zeitpunkt der Definition gespeicherten Testmethoden bereitgestellt werden.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\Requirement}{mmm}
{
\subsubsection*{Requirement ~ ID ~ #1}
#2
\jfb_requirement_store:nnn { #1 } { #2 } { #3 }
}
\NewDocumentCommand{\DescribeRequirements}{}
{
\seq_map_inline:Nn \g_jfb_requirement_ids_seq
{
\subsubsection*{##1} \prop_item:Nn \g_jfb_requirement_ids_prop { ##1@B } \par
}
}
\seq_new:N \g_jfb_requirement_ids_seq
\prop_new:N \g_jfb_requirement_ids_prop
\cs_new_protected:Nn \jfb_requirement_store:nnn
{
\seq_gput_right:Nn \g_jfb_requirement_ids_seq { #1 }
\prop_gput:Nnx \g_jfb_requirement_ids_prop { #1@A } { \tl_trim_spaces:n { #2 } }
\prop_gput:Nnx \g_jfb_requirement_ids_prop { #1@B } { \tl_trim_spaces:n { #3 } }
}
\ExplSyntaxOff
\begin{document}
\section{Introduction}
Blah.
\section{Requirements}
\Requirement{SOMEID}{This is the requirement text.}{This describes the test method.}
\Requirement{SOMEOTHERID}{
This is the other requirement text.
}{
This describes the other test method.
}
\section{Test Methods}
\DescribeRequirements
\end{document}
Antwort2
Sie könnten hierfür \@starttoc
den - -Mechanismus von LaTeX verwenden .\addtocontents
Ich habe versucht, sicherzustellen, dass das folgende Beispiel sowohl mit als auch ohne kompiliert wirdHyperrefwird geladen.
Außerdem habe ich darauf geachtet, dass das \label
Referenzieren \ref
und Setzen von Lesezeichen klappt.
Möglicherweise müssen Sie das Beispiel mehrmals kompilieren, ohne Hilfsdateien zwischen den LaTeX-Läufen zu löschen, damit alles richtig übereinstimmt.
\documentclass{article}
\usepackage{hyperref}
\newcounter{TestMethod}
\newcounter{Requirement}
\makeatletter
\newcommand\listofrequirements{%
\section{Requirements}%
\IfFileExists{\jobname.lfr}{}{\par\noindent No requirements available.}%
\@starttoc{lfr}%
}%
\newcommand\listoftestmethods{%
\section{Testmethods}%
\begin{description}%
\def\makelabel##1{\hspace\labelsep\normalfont\bfseries##1}%
\IfFileExists{\jobname.ltm}{}{\item[\textnormal{No test-methods available.}]\relax}%
\@starttoc{ltm}%
\end{description}%
}%
\newcommand\@multipleRequirements{}%
\AtEndDocument{\@multipleRequirements}%
\begingroup
\catcode`\/=14 %
\catcode`\%=12 /
\@firstofone{/
\endgroup
\newcommand\Requirement[3]{/
\@bsphack
{/
\@ifundefined{Requirement@#1}{\global\@namedef{Requirement@#1}{DEFINED}}{/
\gdef\@multipleRequirements{\@latex@warning@no@line{There were multiply-defined requirements}}/
\@latex@warning{Requirement `#1' multiply defined}/
}/
}/
\begingroup
// Let's have \addtocontents / \protected@write write immediately:
\let\writecopy\write
\def\write{\immediate\writecopy}/
// Prevent all of \protected@write's expansion (\edef-with \protect-mechanism-expansion and \write-expansion)
// by nesting things either into two token-registers or into two \unexpanded.
\toks@{\the\@temptokena}/
\@temptokena\expandafter{\string\l@Requirement{%^^J{#1}%^^J{#2}%^^J}}/
\addtocontents{lfr}{\the\toks@\relax}/
\@temptokena\expandafter{\string\l@TestMethod{%^^J{#1}%^^J{#3}%^^J}}/
\addtocontents{ltm}{\the\toks@\relax}/
/\addtocontents{lfr}{\unexpanded{\unexpanded\expandafter{\string\l@Requirement{%^^J{#1}%^^J{#2}%^^J}}}\relax}/
/\addtocontents{ltm}{\unexpanded{\unexpanded\expandafter{\string\l@TestMethod{%^^J{#1}%^^J{#3}%^^J}}}\relax}/
\endgroup
\@esphack
}/
}%
\newcommand\l@Requirement[1]{%
%#1 = {ID}{<requirement-text>}
\PrintRequirement#1%
}%
\newcommand\l@TestMethod[1]{%
%#1 = {ID}{<requirement-text>}
\PrintTestMethod#1%
}%
\newcommand\PrintRequirement[2]{%
%#1 = ID; #2 = <requirement-text>;
\ifhmode\medskip\fi\par\noindent
\begingroup
\def\theRequirement{#1}%
\refstepcounter{Requirement}%
\def\@currentlabelname{#1}%
\label{RequirementNamespace@Requirement #1}%
\@ifundefined{Hy@raisedlink}{}{%
\@tempcnta\Hy@currentbookmarklevel
\Hy@StepCount\@tempcnta
\expandafter\RequirementPassFirstToSecond\expandafter{\the\@tempcnta}%
{\Hy@writebookmark{}{#1}{\@currentHref}}{toc}%
\advance \@tempcnta by -1 %
\xdef\Hy@currentbookmarklevel{\the \@tempcnta}%
\@ifundefined{r@RequirementNamespace@TestMethod #1}{}{%
\hyperref[{RequirementNamespace@TestMethod #1}]%
}%
}%
{\textbf{Requirement~ID~{#1}}}%
\\{#2}%
\endgroup
}%
\newcommand\Requirement@MoveLabelData{}%
\newcommand\RequirementPassFirstToSecond[2]{#2{#1}}%
\newcommand\PrintTestMethod[2]{%
%#1 = ID; #2 = <requirement-text>;
\item[{%
\def\theTestMethod{#1}%
\refstepcounter{TestMethod}%
\def\@currentlabelname{#1}%
\expandafter\gdef\expandafter\Requirement@MoveLabelData\expandafter{%
\romannumeral0%
\expandafter\RequirementPassFirstToSecond\expandafter{\@currentlabel}{%
\@ifundefined{Hy@raisedlink}{ }{%
\expandafter\RequirementPassFirstToSecond\expandafter{\@currentlabelname}{%
\expandafter\RequirementPassFirstToSecond\expandafter{\@currentHref}{ %<- This space must be!
\def\@currentHref
}%
\def\@currentlabelname
}%
}%
\def\@currentlabel
}%
}%
\label{RequirementNamespace@TestMethod #1}%
\@ifundefined{Hy@raisedlink}{}{%
\@tempcnta\Hy@currentbookmarklevel
\Hy@StepCount\@tempcnta
\expandafter\RequirementPassFirstToSecond\expandafter{\the\@tempcnta}%
{\Hy@writebookmark{}{#1}{\@currentHref}}{toc}%
\advance\@tempcnta by -1 %
\xdef\Hy@currentbookmarklevel{\the \@tempcnta}%
\@ifundefined{r@RequirementNamespace@Requirement #1}{}{%
\hyperref[{RequirementNamespace@Requirement #1}]%
}%
}%
{#1:}%
}]%
\Requirement@MoveLabelData
#2%
}%
\makeatother
\begin{document}
\section{This is just some section}
This is text in the section.
\noindent Reference to the requirement with ID ``SOMEOTHERID'': \ref{AA}.
\noindent Reference to the testing-method with ID ``SOMEOTHERID'': \ref{BB}.
\Requirement{SOMEID}{This is the requirement text.}{This describes the testmethod.}
\Requirement{SOMEOTHERID}{This \label{AA} is some different requirement text.}{This \label{BB} describes some different testmethod.}
\listofrequirements
\listoftestmethods
\end{document}
Falls die Zeilen in den Hilfsdateien zu lang werden, können Sie einige der Argumente nach dem Verbatim-Category-Code-Regime lesen und schreiben lassen. Wenn Sie das tun, kann das Makro \Requirement
nicht innerhalb der Definitionen und/oder Argumente anderer Makros verwendet werden.
Zuerst konnte ich es nicht zum Laufen bringen mitxparse's v+
-Argumenttyp, also habe ich mein eigenes Ding verwendet.
Ich konnte es nicht zum Laufen bringen mitxparse's v+
-Argumenttyp aus folgendem Grund:xparseDer v+
Argumenttyp von verwendet das ^^M
Zeichen = das ⟨Return⟩-Zeichen zur Bezeichnung von Zeilenenden. ( ^^M
= ^^
-Notation für das Zeichen, dessen Codepunkt 13 im internen Zeichenkodierungsschema der TeX-Engine ist – M ist der 13. Buchstabe im Alphabet; Codepunkt 13 des internen Zeichenkodierungsschemas der TeX-Engine bezeichnet wiederum das ⟨Return⟩-Zeichen.) Wenn also das v+
Argument in die Datei geschrieben wird, muss der Integer-Parameter \newlinechar
auch dieses Zeichen bezeichnen. Daher sollten Sie \protected@write
zum Schreiben des v+
Arguments in die Datei besser nicht verwenden, sondern etwas, das dies \write
sofort tut, während die Änderung von \newlinechar
noch wirksam ist. Bei meinen ersten Versuchen mitxparseIch habe beim v+
-Argument-Typ übersehen, dass das \write
sofort erfolgen muss.
Hier kommt mein eigenes Ding, aber dahinter habe ich ein weiteres Beispiel hinzugefügt, mitxparseund sein v+
-Argument-Typ zum Abrufen der verbalisierten Argumente:
\documentclass{article}
\usepackage{hyperref}
\newcounter{TestMethod}
\newcounter{Requirement}
\makeatletter
%%======================Code for \UDcollectverbarg=============================
%% \UDcollectverbarg{^^M-replacement}{<mandatory 1>}{<mandatory 2>}|<verbatim arg>|
%%
%% reads <verbatim arg> under verbatim-catcode-regime and delivers:
%%
%% <mandatory 1>{<mandatory 2>{<verbatim arg>}{|<verbatim arg>|}}
%%
%% Instead of verbatim-delimiter | the <verbatim arg> can be nested in braces.
%% You cannot use percent or spaces or horizontal tab as verbatim-delimiter.
%%
%% You can use <mandatory 1> for nesting calls to \UDcollectverbarg.
%% <mandatory 2> gets the <verbatim arg> twice: Once without verbatim-delimiters/braces,
%% once surrounded by verbatim-delimiters/braces.
%% Reason: When you feed it to \scantokens you don't need the verbatim-delimiters.
%% When you use it for writing to temporary files and reading back,
%% you need them.
%%=============================================================================
%% Check whether argument is empty:
%%=============================================================================
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% Due to \romannumeral0-expansion the result is delivered after two
%% expansion-steps/after two "hits" by \expandafter.
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
\long\def\UD@CheckWhetherNull#1{%
\romannumeral0\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\@firstoftwo\expandafter{} \@secondoftwo}%
{\@firstoftwo\expandafter{} \@firstoftwo}%
}%
%%=============================================================================
\begingroup
\@makeother\^^M%
\@firstofone{%
\endgroup%
\newcommand\UDEndlreplace[2]{\romannumeral0\@UDEndlreplace{#2}#1^^M\relax{}}%
\@ifdefinable\@UDEndlreplace{%
\long\def\@UDEndlreplace#1#2^^M#3\relax#4#5{%
\UD@CheckWhetherNull{#3}%
{ #5{#4#2}}{\@UDEndlreplace{#1}#3\relax{#4#2#1}{#5}}%
}%
}%
}%
\newcommand\UDcollectverbarg[3]{%
\begingroup
\let\do\@makeother % <- this and the next line switch to
\dospecials % verbatim-category-code-régime.
\catcode`\{=1 % <- give opening curly brace the usual catcode so a
% curly-brace-balanced argument can be gathered in
% case of the first thing of the verbatimized-argument
% being a curly opening brace.
\catcode`\ =10 % <- give space and horizontal tab the usual catcode so \UD@collectverbarg
\catcode`\^^I=10 % cannot catch a space or a horizontal tab as its 4th undelimited argument.
% (Its 4th undelimited argument denotes the verbatim-
% syntax-delimiter in case of not gathering a
% curly-brace-nested argument.)
\catcode`\%=14 % <- make percent comment.
\kernel@ifnextchar\bgroup
{% seems a curly-brace-nested argument is to be caught:
\catcode`\}=2 % <- give closing curly brace the usual catcode also.
\UD@collectverbarg{#1}{#2}{#3}{}%
}{% seems an argument with verbatim-syntax-delimiter is to be caught:
\do\{% <- give opening curly brace the verbatim-catcode again.
\UD@collectverbarg{#1}{#2}{#3}%
}%
}%
\newcommand\UD@collectverbarg[4]{%
\do\ % <- Now that \UD@collectverbarg has the delimiter or
\do\^^I% emptiness in its 4th arg, give space and horizontal tab
% the verbatim-catcode again.
\do\^^M% <- Give the carriage-return-character the verbatim-catcode.
\do\%% <- Give the percent-character the verbatim-catcode.
\long\def\@tempb##1#4{%
\def\@tempb{##1}%
\UD@CheckWhetherNull{#4}{%
\def\@tempc{{##1}}%
}{%
\def\@tempc{#4##1#4}%
}%
\@onelevel@sanitize\@tempb % <- Turn characters into their "12/other"-pendants.
% This may be important with things like the
% inputenc-package which may make characters
% active/which give them catcode 13(active).
\expandafter\UDEndlreplace\expandafter{\@tempb}{#1}{\def\@tempb}% <- this starts
% the loop for replacing endline-characters.
\@onelevel@sanitize\@tempc
\expandafter\UDEndlreplace\expandafter{\@tempc}{#1}{\def\@tempc}%
\expandafter\expandafter\expandafter\UD@@collectverbarg% <- this "spits out the result.
\expandafter\expandafter\expandafter{%
\expandafter\@tempb\expandafter}%
\expandafter{\@tempc}{#2}{#3}%
}%
\@tempb
}%
\newcommand\UD@@collectverbarg[4]{%
\endgroup
#3{#4{#1}{#2}}%
}%
%%================= End of code for \UDcollectverbarg =========================
\newcommand\listofrequirements{%
\section{Requirements}%
\IfFileExists{\jobname.lfr}{}{\par\noindent No requirements available.}%
\@starttoc{lfr}%
}%
\newcommand\listoftestmethods{%
\section{Testmethods}%
\begin{description}%
\def\makelabel##1{\hspace\labelsep\normalfont\bfseries##1}%
\IfFileExists{\jobname.ltm}{}{\item[\textnormal{No test-methods available.}]\relax}%
\@starttoc{ltm}%
\end{description}%
}%
\newcommand\@multipleRequirements{}%
\AtEndDocument{\@multipleRequirements}%
\newcommand\Requirement[1]{%
\@bsphack
\UDcollectverbarg{^^J}{%
\UDcollectverbarg{^^J}{\@firstofone}%
}{\InnerRequirement{#1}}%
}%
\newcommand\InnerRequirement[5]{%
{%
\@ifundefined{Requirement@#1}{\global\@namedef{Requirement@#1}{DEFINED}}{%
\gdef\@multipleRequirements{\@latex@warning@no@line{There were multiply-defined requirements}}%
\@latex@warning{Requirement `#1' multiply defined}%
}%
}%
\begingroup
\immediate\write\@auxout{\string\Requirementwritefile{lfr}{Requirement}{#1}#3}%
\immediate\write\@auxout{\string\Requirementwritefile{ltm}{TestMethod}{#1}#5}%
\endgroup
\@esphack
}%
\newcommand\Requirementwritefile[3]{%
\UDcollectverbarg{^^J}{\@firstofone}{%
\expandafter\expandafter\expandafter\RequirementPassFirstToSecond
\expandafter\expandafter\expandafter{\expandafter\string\csname l@#2\endcsname}%
{\RequirementwritefileInner{#1}}{#3}%
}%
}%
\begingroup
\catcode`\/=14 %
\@makeother{\%}/
\@firstofone{/
\endgroup
\newcommand\RequirementwritefileInner[5]{/
\@writefile{#1}{/
#2{%^^J/
{#3}%^^J/
{#4}%^^J/
}%/
}/
}/
}%
\newcommand\l@Requirement[1]{%
%#1 = {ID}{<requirement-text>}
\PrintRequirement#1%
}%
\newcommand\l@TestMethod[1]{%
%#1 = {ID}{<requirement-text>}
\PrintTestMethod#1%
}%
\newcommand\PrintRequirement[2]{%
%#1 = ID; #2 = <requirement-text>;
\ifhmode\medskip\fi\par\noindent
\begingroup
\def\theRequirement{#1}%
\refstepcounter{Requirement}%
\def\@currentlabelname{#1}%
\label{RequirementNamespace@Requirement #1}%
\@ifundefined{Hy@raisedlink}{}{%
\@tempcnta\Hy@currentbookmarklevel
\Hy@StepCount\@tempcnta
\expandafter\RequirementPassFirstToSecond\expandafter{\the\@tempcnta}%
{\Hy@writebookmark{}{#1}{\@currentHref}}{toc}%
\advance\@tempcnta by -1 %
\xdef\Hy@currentbookmarklevel{\the\@tempcnta}%
\@ifundefined{r@RequirementNamespace@TestMethod #1}{}{%
\hyperref[{RequirementNamespace@TestMethod #1}]%
}%
}%
{\textbf{Requirement~ID~{#1}}}%
\\{#2}%
\endgroup
}%
\newcommand\Requirement@MoveLabelData{}%
\newcommand\RequirementPassFirstToSecond[2]{#2{#1}}%
\newcommand\PrintTestMethod[2]{%
%#1 = ID; #2 = <requirement-text>;
\item[{%
\def\theTestMethod{#1}%
\refstepcounter{TestMethod}%
\def\@currentlabelname{#1}%
\expandafter\gdef\expandafter\Requirement@MoveLabelData\expandafter{%
\romannumeral0%
\expandafter\RequirementPassFirstToSecond\expandafter{\@currentlabel}{%
\@ifundefined{Hy@raisedlink}{ }{%
\expandafter\RequirementPassFirstToSecond\expandafter{\@currentlabelname}{%
\expandafter\RequirementPassFirstToSecond\expandafter{\@currentHref}{ %<- This space must be!
\def\@currentHref
}%
\def\@currentlabelname
}%
}%
\def\@currentlabel
}%
}%
\label{RequirementNamespace@TestMethod #1}%
\@ifundefined{Hy@raisedlink}{}{%
\@tempcnta\Hy@currentbookmarklevel
\Hy@StepCount\@tempcnta
\expandafter\RequirementPassFirstToSecond\expandafter{\the\@tempcnta}%
{\Hy@writebookmark{}{#1}{\@currentHref}}{toc}%
\advance\@tempcnta by -1 %
\xdef\Hy@currentbookmarklevel{\the\@tempcnta}%
\@ifundefined{r@RequirementNamespace@Requirement #1}{}{%
\hyperref[{RequirementNamespace@Requirement #1}]%
}%
}%
{#1:}%
}]%
\Requirement@MoveLabelData
#2%
}%
\makeatother
\begin{document}
\section{This is just some section}
This is text in the section.
\noindent Reference to the requirement with ID ``SOMEOTHERID'': \ref{AA}.
\noindent Reference to the testing-method with ID ``SOMEOTHERID'': \ref{BB}.
\Requirement{SOMEID}{This is the requirement text.}{This describes the testmethod.}
\Requirement{SOMEOTHERID}{This \label{AA} is some different requirement text.}{This \label{BB} describes some different testmethod.}
\listofrequirements
\listoftestmethods
\end{document}
Hier ist das Beispiel mit dem wörtlichen Argument unter Verwendungxparse‚s +v
-Argument-Typ:
\documentclass{article}
\usepackage{xparse}
\usepackage{hyperref}
\newcounter{TestMethod}
\newcounter{Requirement}
\makeatletter
\NewDocumentCommand{\listofrequirements}{}{%
\section{Requirements}%
\IfFileExists{\jobname.lfr}{}{\par\noindent No requirements available.}%
\@starttoc{lfr}%
}%
\NewDocumentCommand{\listoftestmethods}{}{%
\section{Testmethods}%
\begin{description}%
\def\makelabel##1{\hspace\labelsep\normalfont\bfseries##1}%
\IfFileExists{\jobname.ltm}{}{\item[\textnormal{No test-methods available.}]\relax}%
\@starttoc{ltm}%
\end{description}%
}%
\NewDocumentCommand{\@multipleRequirements}{}{}%
\AtEndDocument{\@multipleRequirements}%
\NewDocumentCommand{\Requirement}{m}{%
\begingroup
\@makeother{\^^I}%
\InnerRequirement{#1}%
}%
\begingroup
\catcode`\/=14 %
\@makeother{\%}/
\@makeother{\^^M}/
\@firstofone{/
\endgroup/
\NewDocumentCommand{\InnerRequirement}{m+v+v}{/
\endgroup/
{/
\@ifundefined{Requirement@#1}{\global\@namedef{Requirement@#1}{DEFINED}}{/
\gdef\@multipleRequirements{\@latex@warning@no@line{There were multiply-defined requirements}}/
\@latex@warning{Requirement `#1' multiply defined}/
}/
}/
\begingroup/
\newlinechar=\endlinechar/
\immediate\write\@auxout{/
\string\Requirementwritefile{lfr}/
{\unexpanded\expandafter{\string\l@Requirement{%^^M{#1}%^^M{#2}%^^M}}%}/
}/
\immediate\write\@auxout{/
\string\Requirementwritefile{ltm}/
{\unexpanded\expandafter{\string\l@TestMethod{%^^M{#1}%^^M{#3}%^^M}}%}/
}/
\endgroup/
\@esphack/
}/
}%
\NewDocumentCommand{\Requirementwritefile}{m}{%
\begingroup
\@makeother{\^^I}%
\RequirementwritefileInner{#1}%
}%
\NewDocumentCommand{\RequirementwritefileInner}{m+v}{%
\newlinechar=\endlinechar
\@writefile{#1}{#2}%
\endgroup
}%
\NewDocumentCommand{\l@Requirement}{+m}{%
%#1 = {ID}{<requirement-text>}
\PrintRequirement#1%
}%
\NewDocumentCommand{\l@TestMethod}{+m}{%
%#1 = {ID}{<requirement-text>}
\PrintTestMethod#1%
}%
\NewDocumentCommand{\PrintRequirement}{+m+m}{%
%#1 = ID; #2 = <requirement-text>;
\ifhmode\medskip\fi\par\noindent
\begingroup
\def\theRequirement{#1}%
\refstepcounter{Requirement}%
\def\@currentlabelname{#1}%
\label{RequirementNamespace@Requirement #1}%
\@ifundefined{Hy@raisedlink}{}{%
\@tempcnta\Hy@currentbookmarklevel
\Hy@StepCount\@tempcnta
\expandafter\RequirementPassFirstToSecond\expandafter{\the\@tempcnta}%
{\Hy@writebookmark{}{#1}{\@currentHref}}{toc}%
\advance\@tempcnta by -1 %
\xdef\Hy@currentbookmarklevel{\the \@tempcnta}%
\@ifundefined{r@RequirementNamespace@TestMethod #1}{}{%
\hyperref[{RequirementNamespace@TestMethod #1}]%
}%
}%
{\textbf{Requirement~ID~{#1}}}%
\\{#2}%
\endgroup
}%
\NewDocumentCommand{\Requirement@MoveLabelData}{}{}%
\NewDocumentCommand{\RequirementPassFirstToSecond}{+m+m}{#2{#1}}%
\NewDocumentCommand{\PrintTestMethod}{+m+m}{%
%#1 = ID; #2 = <requirement-text>;
\item[{%
\def\theTestMethod{#1}%
\refstepcounter{TestMethod}%
\def\@currentlabelname{#1}%
\expandafter\gdef\expandafter\Requirement@MoveLabelData\expandafter{%
\romannumeral0%
\expandafter\RequirementPassFirstToSecond\expandafter{\@currentlabel}{%
\@ifundefined{Hy@raisedlink}{ }{%
\expandafter\RequirementPassFirstToSecond\expandafter{\@currentlabelname}{%
\expandafter\RequirementPassFirstToSecond\expandafter{\@currentHref}{ %<- This space must be!
\def\@currentHref
}%
\def\@currentlabelname
}%
}%
\def\@currentlabel
}%
}%
\label{RequirementNamespace@TestMethod #1}%
\@ifundefined{Hy@raisedlink}{}{%
\@tempcnta\Hy@currentbookmarklevel
\Hy@StepCount\@tempcnta
\expandafter\RequirementPassFirstToSecond\expandafter{\the\@tempcnta}%
{\Hy@writebookmark{}{#1}{\@currentHref}}{toc}%
\advance \@tempcnta by -1 %
\xdef\Hy@currentbookmarklevel{\the \@tempcnta}%
\@ifundefined{r@RequirementNamespace@Requirement #1}{}{%
\hyperref[{RequirementNamespace@Requirement #1}]%
}%
}%
{#1:}%
}]%
\Requirement@MoveLabelData
#2%
}%
\makeatother
\begin{document}
\section{This is just some section}
This is text in the section.
\noindent Reference to the requirement with ID ``SOMEOTHERID'': \ref{AA}.
\noindent Reference to the testing-method with ID ``SOMEOTHERID'': \ref{BB}.
\Requirement{SOMEID}{This is the requirement text.}{This describes the testmethod.}
\Requirement{SOMEOTHERID}{This \label{AA} is some different requirement text.}{This \label{BB} describes some different testmethod.}
\listofrequirements
\listoftestmethods
\end{document}