
Я узнал, как создавать требования с уникальными идентификаторами.в этом посте. Теперь я хотел бы добавить тестовый метод для каждого требования — в коде я представляю что-то вроде этого:
\Requirement{SOMEID}{This is the requirement text.}{This describes the testmethod.}
Позже, в другом разделе я хочу перебрать эти тестовые методы, чтобы составить их список. В итоге я ищу что-то вроде этого:
Первая часть мне ясна, но как можно «сохранить» параметр (тестовые методы), чтобы использовать его позже?
решение1
Вам нужна «ассоциативная память», которую можно реализовать с помощью \csname
структур данных, уже предоставляемых expl3
.
Здесь \Requirement
хранится идентификатор в последовательности для индексации, затем оба текста в списке свойств. Хранение текста требования на самом деле не используется здесь, но вы можете решить использовать его по-другому, поэтому лучше сохранить его также.
При необходимости последовательность можно сопоставить для предоставления всех методов тестирования, сохраненных на момент определения.
\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-argument v+
-type, поэтому я использовал свой собственный.
Я не смог заставить его работать сxparse-argument v+
-type по следующей причине:xparse-argument v+
-type использует -character ^^M
= символ ⟨return⟩ для обозначения концов строк. ( ^^M
= ^^
-обозначение для символа, кодовая точка которого равна 13 во внутренней схеме кодировки символов движка TeX — M — 13-я буква в алфавите; кодовая точка 13 внутренней схемы кодировки символов движка TeX в свою очередь обозначает символ ⟨return⟩.) Таким образом, во время записи аргумента v+
в файл целочисленный параметр \newlinechar
также должен обозначать этот символ. Таким образом, вам лучше не использовать \protected@write
для записи v+
аргумента в файл, а что-то, что делает \write
немедленно, пока изменение \newlinechar
все еще действует. В моих первых попытках сxparse's v+
-argument-type Я упустил из виду, что \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}