
고유 ID로 요구사항을 생성하는 방법을 배웠습니다.이 게시물에서. 이제 각 요구 사항에 대한 테스트 방법을 추가하고 싶습니다. 코드에서는 다음과 같은 것을 생각하고 있습니다.
\Requirement{SOMEID}{This is the requirement text.}{This describes the testmethod.}
나중에 다른 섹션에서 이러한 테스트 방법을 반복하여 나열하고 싶습니다. 결국 나는 다음과 같은 것을 찾고 있습니다.
첫 번째 부분은 분명합니다. 하지만 나중에 사용하기 위해 매개변수(테스트 방법)를 어떻게 "저장"할 수 있습니까?
답변1
\csname
NET에서 이미 제공하는 데이터 구조를 사용하여 구현할 수 있는 "연관 메모리"가 필요합니다 expl3
.
여기에는 \Requirement
인덱싱을 위해 ID를 순서대로 저장한 다음 속성 목록에 두 텍스트를 모두 저장합니다. 요구 사항 텍스트를 저장하는 것은 여기서 실제로 사용되지 않지만 다른 방식으로 사용하기로 결정할 수 있으므로 저장하는 것이 좋습니다.
필요한 경우 시퀀스를 매핑하여 정의 시 저장된 모든 테스트 방법을 제공할 수 있습니다.
\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}
답변2
이를 위해 LaTeX의 \@starttoc
- - 메커니즘을 사용할 수 있습니다 .\addtocontents
나는 다음 예제가 유무에 관계없이 컴파일되는지 확인하려고 노력했습니다.하이퍼레프로드 중입니다.
\label
또한 - \ref
참조 및 북마크가 작동하는지 확인하려고 노력했습니다 .
모든 것이 올바르게 일치하도록 하려면 LaTeX 실행 사이의 보조 파일을 삭제하지 않고 예제를 여러 번 컴파일해야 할 수도 있습니다.
\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}
보조 파일에 너무 긴 줄이 있는 경우, verbatim-category-code-régime에서 일부 인수를 읽고 쓰도록 할 수 있습니다. 그렇게 하면 해당 매크로를 \Requirement
다른 매크로의 정의 및/또는 인수 내에서 사용할 수 없습니다.
처음에는 제대로 작동하지 못했습니다.xparse의 v+
-argument-type이므로 나만의 것을 사용했습니다.
나는 그것을 작동시킬 수 없었다xparse의 v+
-argument-type은 다음과 같은 이유 때문입니다.xparse의 v+
-argument-type은 ^^M
줄 끝을 표시하기 위해 -character = ⟨return⟩ 문자를 사용합니다. ( ^^M
= ^^
TeX 엔진의 내부 문자 인코딩 체계에서 코드 포인트가 13인 문자에 대한 표기법 - M은 알파벳의 13 번째 문자입니다. TeX 엔진의 내부 문자 인코딩 체계의 코드 포인트 13은 다음을 나타냅니다. ⟨return⟩-문자.) 따라서 -인수를 파일에 쓸 때 v+
정수 매개변수 \newlinechar
도 해당 문자를 나타내야 합니다. 따라서 -argument를 파일에 \protected@write
기록하는 데 사용하는 것이 아니라 변경 사항이 여전히 유효한 동안 즉시 수행하는 것을 사용하는 것이 좋습니다 . 나의 첫 번째 시도에서v+
\write
\newlinechar
xparse의 -argument-type 이 작업이 즉시 수행되어야 한다는 v+
점을 간과했습니다 .\write
여기에 나만의 것이 있지만 그 뒤에 다음을 사용하여 또 다른 예를 추가했습니다.xparse그리고 v+
축자된 인수를 가져오기 위한 -argument-type:
\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}
다음은 축어화된 인수가 포함된 예입니다.xparse님의 +v
-인수 유형:
\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}