Extended reference for enumerate item using parent environment

I want to reference an item of an enumerate list by it's normal label, if we are still in that same enumeration and by an parent.item syntax if we are somewhere else in the document. For example:

\documentclass{scrartcl}

\makeatletter
\newcounter{entity}
\def\theentity{\Roman{entity}}
\newenvironment{entity}[1]{\refstepcounter{entity}\@startsection{entity}{4}{-1em}{\baselineskip}{.1\baselineskip}{\bfseries}{\theentity. Entity: #1}}{}
\newcommand\entitymark{\@gobble}
\newcommand\toclevel@entity{3}
\newcommand\l@entity{\@gobbletwo}
\newcommand\entityautorefname{Entity}
\newcommand\entityname{Entity}
\makeatother

\begin{document}

\begin{entity}{Test1}
\begin{enumerate}
\item Some text \label{label}!
\item Some more text, oh and \autoref{label}.
\end{enumerate}
\end{entity}

Even more text and here: \autoref{label}.

\begin{entity}{Test2}
Referencing \ref{label} again.
\end{entity}

\end{document}


Now the references are item 1, item 1 and 1. But I want them to be printed as item 1, entity 1 item 1 and 1.1.

The aux file contains a line like:

\newlabel{label}{{1}{1}{\theentity . Entity: Test1\relax }{Item.1}{}}


which I could maybe access via \r@label if I understand egreg correctly. But currently it does not contain any information about which entity it was defined in. Can I add that somehow?

Here is my suggestion how to do it. I only used the very powerful zref-package which can store a lot more (label)informations than the standard label-command. Additionally there are new commands (\entityLabel and \entityRef) which are used in the entity environment. I don't want to explain all lines of the given code, because I think using the zref-package documentation in parallel and the commented lines makes it easy to understand the code.

\documentclass{scrartcl}
\usepackage{zref-user}

\makeatletter
% new properties in zref
\zref@newprop{EntityName}{}
\zref@newprop{EntityTag}{}
\zref@newprop{EntityCounter}{}
\zref@newprop{ItemCounter}{}

% add the new properties to the main list

% define some hyper references
\def\entityRef@EntityName#1{%
\def\tag{\zref@extractdefault{\zprefix#1}{EntityTag}{}}%
\def\name{\zref@extractdefault{\zprefix#1}{EntityName}{}}%
\hyperref[\zprefix\tag]{\name}}

\def\entityRef@EntityCounter#1{%
\def\tag{\zref@extractdefault{\zprefix#1}{EntityTag}{}}%
\def\count{\zref@extractdefault{\zprefix#1}{EntityCounter}{0}}%
\hyperref[\zprefix\tag]{\count}}

\def\entityRef@ItemCounter#1{%
\def\icount{\zref@extractdefault{\zprefix#1}{ItemCounter}{0}}%
\hyperref[\zprefix#1]{\icount}}

\def\entityRef@EntityPage#1{%
\def\pagenum{\zref@extractdefault{\zprefix#1}{page}{0}}%
\hyperpage{\pagenum}}

% counter for the entities
\newcounter{EntityCounter}

% prefix for all labels and references
\def\zprefix{entity:}

% boolean to check if we work inside an entity environment
\newif\ifIsInEntity

% the new entity environment
\newenvironment{entity}[1]{%
\IsInEntitytrue
\refstepcounter{EntityCounter}%
\def\entityName{#1}
\def\entityTag{Entity\theEntityCounter}
\noindent\textbf{\label{\zprefix\entityTag}\theEntityCounter. Entity: #1}%
\begin{enumerate}
}{%
\IsInEntityfalse
\end{enumerate}
}%

% a new label
\def\entityLabel#1{%
\zref@setcurrent{EntityName}{\entityName}%
\zref@setcurrent{EntityTag}{\entityTag}%
\zref@setcurrent{EntityCounter}{\the\value{EntityCounter}}%
\zref@setcurrent{ItemCounter}{\theenumi}%
\zlabel{\zprefix#1}\label{\zprefix#1}}

% a new ref
% the output depends on the place where the reference is used
\def\entityRef#1{%
\ifIsInEntity
% reference is inside an entity
% compare the saved EntityCounter with the current EntityCounter
\ifnum\zref@extractdefault{\zprefix#1}{EntityCounter}{-1}=\theEntityCounter
% reference is inside the same entity
see Item \entityRef@ItemCounter{#1}%
\else
% reference is in an other entity
see \entityRef@EntityCounter{#1}.\entityRef@ItemCounter{#1}%
\fi
\else
% reference is outside of an entity
see Entity "\entityRef@EntityName{#1}" (Nr. \entityRef@EntityCounter{#1}) Item \entityRef@ItemCounter{#1} on page \entityRef@EntityPage{#1}%
\fi
}

\makeatother

\begin{document}
\tableofcontents
\newpage
\begin{entity}{First Test}
\item Some text with label \entityLabel{Entity1Item1}
\item Some more text, oh and \entityLabel{Entity1Item2}
\item More text \entityRef{Entity1Item1}
\end{entity}
\noindent
Refernce in text: \entityRef{Entity1Item1}\\
Refernce in text: \entityRef{Entity2Item2}\\
Refernce in text: \entityRef{Entity3Item2}\\

\begin{entity}{Second Test}
\item Referencing \entityRef{Entity2Item2}
\item Referencing \entityLabel{Entity2Item2}\entityRef{Entity1Item2}
\item Referencing \entityRef{Entity1Item2}
\end{entity}
\newpage
\begin{entity}{Third Test}
\item Referencing \entityRef{Entity1Item1}
\item Referencing \entityLabel{Entity3Item2}\entityRef{Entity2Item2}
\item Referencing \entityRef{Entity1Item2}
\end{entity}
\end{document}


I think it's a near-certainty that if you have several entity instances, each containing several instances of enumerate, your readers will quickly become confused by the fact that some items are cross-referenced only by their numbers (if either within the current entity environment or somewhere outside an entity environment but before the next entity instance starts up) while others are cross-referenced by both the (Roman) entity number and the item number (if in a different entity environment). What, say, do you think is going to happen if there are two cross-references within one and the same entity, the first to an item numbered 1 and the second to an item numbered II.1?

Whatever measure of elegance you may hope to achieve -- by prefixing the entity number to an item number only if the item in question belongs to a different entity than the current one (or immediately preceding one, if currently between entities...) -- is therefore very likely going to be offset by confusion and puzzlement over which items exactly are being cross-referenced. The fact that the cross-referencing call-outs may be hyper-targets is of little help; in fact, it may even be detrimental to the overall readability of the document because it might invite your readers to click on the call-out(s) just to ascertain which items are being cross-referenced.

If you don't want to number the items within an entity environment in the \theentity.\theenumi style, you could issue the command

\renewcommand\p@enumi{\theentity.}


(inside a \makeatletter ... \makeatother pair, of course). This will instruct LaTeX, when constructing the "number" of a cross-reference, to automatically prefix the entity's (Roman) number to the enumi number.

• Your objections are duly noted and I agree that a high density of such references could lead to some confusion. Usually this does not happen, but even if it would, some descriptive text can help and the name of the referenced entity can be provided for more clarity. Also it should certainly not be the case, that multiple enumerations occur within one entity. At most one could use description lists or labelings and thereby avoid any ambiguity.
– bodo
Jul 24, 2012 at 14:32

Based on Holle's answer, I build the following, which incorporates functionality similar to \autoref and \nameref (actually what I call \doubleref; see also using \nameref only if there is a name). Also the hyperref link is stretched out over the whole reference and only points directly to the item. Here is the MWE version:

\documentclass{scrartcl}
\usepackage{zref-user}
\usepackage[english]{babel}
\RequirePackage{xcolor}
\definecolor{darkred}{rgb}{0.5,0,0}

\makeatletter
% new properties in zref
\zref@newprop{EntityTitle}{}
\zref@newprop{EntityType}{}
\zref@newprop{EntityNr}{}
\zref@newprop{ItemNr}{}

% add the new properties to the main list

% counter for the entities
\newcounter{entity}

% prefix for all labels and references
\def\zprefix{entity:}

% boolean to check if we work inside an entity environment
\newif\ifIsInEntity

% the new entity environment
\newcommand\entitymark{\@gobble}
\newcommand\toclevel@entity{3}
\newcommand\l@entity{\@gobbletwo}
\newcommand\entityautorefname{Entity}
\newcommand\entityname{Entity}
\newenvironment{entity}[1]{%
\IsInEntitytrue
\refstepcounter{entity}%
\def\entityTitle{#1}
\def\entityType{entity}
\@startsection{entity}{4}{-1em}{\baselineskip}{.1\baselineskip}{\bfseries}{\theentity. Entity: #1}
\begin{enumerate}
}{%
\IsInEntityfalse
\end{enumerate}
}%

% a new label
\newcommand\ilabel[1]{%
\zref@setcurrent{EntityTitle}{\entityTitle}%
\zref@setcurrent{EntityType}{\entityType}%
\zref@setcurrent{EntityNr}{\the\value{entity}}%
\zref@setcurrent{ItemNr}{\theenumi}%
\zlabel{\zprefix#1}\label{\zprefix#1}}

% a new ref
% the output depends on the place where the reference is used
\newcommand\iref[1]{%
%my zref version is too old for:
%\zref@def@extractdefault{\z@inr}{\zprefix#1}{ItemNr}{0}
%\zref@def@extractdefault{\z@entitynr}{\zprefix#1}{EntityNr}{0}
\def\z@inr{\zref@extractdefault{\zprefix#1}{ItemNr}{0}}%
\def\z@entitynr{\zref@extractdefault{\zprefix#1}{EntityNr}{-1}}%
\hyperref[\zprefix#1]{%
\ifIsInEntity
% reference is inside an entity
% compare the saved EntityNr with the current EntityNr
\ifnum\z@entitynr=\theentity
% reference is inside the same entity
(\z@inr)%
\else
% reference is in an different entity
\z@entitynr(\z@inr)%
\fi
\else
% reference is outside of an entity
\z@entitynr(\z@inr)%
\fi
}%
}
\newcommand\iautoref[1]{%
\def\z@inr{\zref@extractdefault{\zprefix#1}{ItemNr}{0}}%
\def\z@entitynr{\zref@extractdefault{\zprefix#1}{EntityNr}{-1}}%
\def\z@entitytype{\zref@extractdefault{\zprefix#1}{EntityType}{entity}}%
\hyperref[\zprefix#1]{%
\ifIsInEntity
% reference is inside an entity
% compare the saved EntityNr with the current EntityNr
\ifnum\z@entitynr=\the\value{entity}
% reference is inside the same entity
\itemautorefname~(\z@inr)%
\else
% reference is in an different entity
\csname\z@entitytype name\endcsname~\z@entitynr\-~\itemautorefname~\z@inr%
\fi
\else
% reference is outside of an entity
\csname\z@entitytype name\endcsname~\z@entitynr\-~\itemautorefname~\z@inr%
\fi
}%
}
\newcommand\idoubleref[1]{%
\def\z@inr{\zref@extractdefault{\zprefix#1}{ItemNr}{0}}%
\def\z@entitynr{\zref@extractdefault{\zprefix#1}{EntityNr}{-1}}%
\def\z@entitytype{\zref@extractdefault{\zprefix#1}{EntityType}{entity}}%
\def\z@entityname{\zref@extractdefault{\zprefix#1}{EntityTitle}{}}%
\hyperref[\zprefix#1]{%
\ifIsInEntity
% reference is inside an entity
% compare the saved EntityNr with the current EntityNr
\ifnum\z@entitynr=\theentity
% reference is inside the same entity
\itemautorefname~(\z@inr)%
\else
% reference is in an different entity
\csname\z@entitytype name\endcsname~\z@entitynr\-~\itemautorefname~\z@inr%
\ifx\empty\z@entityname\relax\else
~(\z@entityname)%
\fi
\fi
\else
% reference is outside of an entity
\csname\z@entitytype name\endcsname~\z@entitynr\-~\itemautorefname~\z@inr%
\ifx\empty\z@entityname\relax\else
~(\z@entityname)%
\fi
\fi
}%
}


\makeatother

\begin{document}
\begin{entity}{First Test}
\item Some text with label \ilabel{Entity1Item1}
\item Some more text; oh and \ilabel{Entity1Item2}
\item More text \iref{Entity1Item1}
\end{entity}
\noindent
Reference in text: \iref{Entity1Item1}\\
Reference in text: \iautoref{Entity2Item2}\\
Reference in text: \idoubleref{Entity3Item2}

\begin{entity}{Second Test}
\item Referencing \iref{Entity2Item2}
\item Referencing \ilabel{Entity2Item2}\iautoref{Entity1Item2}
\item Referencing \iautoref{Entity1Item2}
\end{entity}
\newpage
\begin{entity}{Third Test}
\item Referencing \iref{Entity1Item1}
\item Referencing \ilabel{Entity3Item2}\iautoref{Entity2Item2}
\item Referencing \iautoref{Entity1Item2}
\end{entity}
\end{document}