9

Consider the following piece of code:

\documentclass{book}
\usepackage{cleveref}
\usepackage{lipsum}

\begin{document}
  \chapter{Chapter One}
  \section{Section One.One}
  \label{mysection}
  \lipsum

  \section{Section One.Two}
  Please ignore \cref{mysection}.

  \chapter{Chapter Two}
  \section{Section Two.One}

  As you may have noticed, \cref{mysection} is useless.
\end{document}

By default, in both uses of \cref I get Section 1.1 as expected.

Is it possible to change the way the reference is shown in such a way that the second use of \cref above will print Section 1 of Chapter 1? i.e., naming the parent counter as well.

However, this should be done only outside the own chapter, so the first use of \cref in the above example should print Section 1.

This comes from a use case of a normative text where the document is divided in "articles" and "commas", and it is good to have references like "Comma 1 of Article 2" or "Article 2, Comma 1".

  • 1
    Does the recent posting different labels for the same equation for choosing the appropriate one in different references speak to your posting as well? Please advise. – Mico Feb 12 '17 at 17:05
  • 1
    This is difficult with cleveref, I think. Apart from Mico's link, see tex.stackexchange.com/questions/346918/… (also an answer by me) – user31729 Feb 12 '17 at 17:41
  • @ChristianHupfer zref would be the ideal solution, but the information about the parent is kept already by cref I think. Can one get the parent counter of a counter? – gigabytes Feb 12 '17 at 21:08
  • @gigabytes: I am working on a solution right now ;-) It's easy if a counter has only one parent counter (this most time the case) – user31729 Feb 12 '17 at 21:09
  • Yes, that's a reasonable assumption :) – gigabytes Feb 12 '17 at 21:16
13

Update 2017/03/05 at the end

Update 2017/06/07: Similar question https://tex.stackexchange.com/a/373769/31729

Determining the parent counter of a counter is easy, if there is only one parent counter, so this is a unique mapping then.

I stored all counters being defined at the begin of the document in a sequence and 'cracked' the \cl@X list (X being a driver counter name, such as, say, chapter), storing their content into a property list which contains the parent counter.

The \getparentcounter macro can be used to retrieve the value.

Now the zref package stores the properties childcountervalue, parentcountervalue and parentcountername in order to retrieve them later with \zref@extract.

The anchor is stored as well, just in case we're using hyperref.

The macros \parentcref and \parentCref will output the parent counter and the child counter with the first character in lower case (which is the counter name, actually) and the first character in upper case, i.e. section → Section etc.

The code assumes that the counters are using numbers only, i.e. \arabic{foo}. I'll try to remove this limitation.

\documentclass{book}
\usepackage{etoolbox}
\usepackage{lipsum}
\usepackage{hyperref}
\usepackage[user,counter,hyperref]{zref}
\usepackage{cleveref}

\makeatletter
\AtEndPreamble{
\newif\if@hyperrefloaded

\@ifpackageloaded{hyperref}{%
  \@hyperrefloadedtrue
}{
  \@hyperrefloadedfalse
}
}
\makeatother

\usepackage{letltxmacro}



\usepackage{xparse}
\makeatletter

\ExplSyntaxOn
\prop_new:N \g_latex_parentcounters_prop 
\seq_new:N  \g_latex_counters_seq

\cs_generate_variant:Nn \seq_gset_from_clist:Nn {Nx,cx}
\cs_generate_variant:Nn \prop_item:Nn {Nx,cx,No}
\cs_generate_variant:Nn \str_head:n {x,o,V}
\cs_generate_variant:Nn \str_tail:n {x,o,V}
\cs_generate_variant:Nn \str_upper_case:n {x,o,V}
\cs_generate_variant:Nn \str_set:Nn {Nx,No}

% Store all reset lists and make a property list for each counter and its possible parent counter
\cs_new_nopar:Npn \GetAllResetLists {%
  \def\@elt##1{%
    \seq_gput_right:Nn \g_latex_counters_seq {##1}%
    \seq_new:c { g_latex_cntr_##1_seq }
  }
  \cl@@ckpt%
  \seq_map_inline:Nn \g_latex_counters_seq {%
    \def\@elt####1{####1,}
    \seq_gset_from_clist:cx { g_latex_cntr_##1_seq } { \use:c{cl@##1} }
  }
  % Now fill the parent counter lists
  \seq_map_inline:Nn \g_latex_counters_seq {%
    \seq_map_inline:cn { g_latex_cntr_##1_seq }{ %
      \prop_gput:Nnn \g_latex_parentcounters_prop {####1} {##1}
    }
  }
}

% Gives the parent counter of a specific counter (or nothing)
\cs_new:Npn \getparentcounter #1{%
  \prop_item:No \g_latex_parentcounters_prop {#1}
}

% Make the first character of a word upper case
\newcommand{\FirstUpcase}[1]{%
  \str_set:Nx \l_tmpa_str {#1}%
  \str_upper_case:x {\str_head:N \l_tmpa_str}\str_tail:V {\l_tmpa_str}%
}

\ExplSyntaxOff

\GetAllResetLists

\def\LastRefSteppedCounter{}

% Define new properties
\zref@newprop{childcountervalue}{\arabic{\LastRefSteppedCounter}}% This is the naked value
\zref@newprop{parentcountervalue}{\csname the\getparentcounter{\LastRefSteppedCounter}\endcsname}
\zref@newprop{parentcountername}{\getparentcounter{\LastRefSteppedCounter}}

% Add the new properties to the main property list stored with \zlabel
\zref@addprops{main}{childcountervalue,parentcountervalue,parentcountername}

\AtBeginDocument{%

  \LetLtxMacro\latex@@label\label
  \let\latex@@refstepcounterorig\refstepcounter

  \RenewDocumentCommand{\refstepcounter}{m}{%
    \global\xdef\LastRefSteppedCounter{#1}%
    \latex@@refstepcounterorig{#1}%
  }
  %Make the ordinary label and a \zlabel
  \RenewDocumentCommand{\label}{om}{%
    \IfValueTF{#1}{%
      \latex@@label[1]{#2}%
    }{%
      \latex@@label{#2}%
    }%
    \zlabel{#2}%
  }%
}

% Command for uppercase output
\NewDocumentCommand{\parentCref}{m}{%
  \zref@ifrefundefined{#1}{%
    \Cref{#1}%
  }{%
    \edef\@tmpb@{\zref@extract{#1}{parentcountervalue}}%
    \edef\@tmpa@{\csname the\zref@extract{#1}{parentcountername}\endcsname}%
    \ifx\@tmpb@\@tmpa@
    \Cref{#1}%
    \else
    \if@hyperrefloaded
    \FirstUpcase{\zref@extract{#1}{counter}} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{childcountervalue}} of \FirstUpcase{\zref@extract{#1}{parentcountername}} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{parentcountervalue}}%
    \else
    \FirstUpcase{\zref@extract{#1}{counter}} \zref@extract{#1}{childcountervalue} of \FirstUpcase{\zref@extract{#1}{parentcountername}} \zref@extract{#1}{parentcountervalue}%
    \fi
    \fi
  }%
}

% Command for lowercase output
\NewDocumentCommand{\parentcref}{m}{%
  \zref@ifrefundefined{#1}{%
    \cref{#1}%
  }{%
    \edef\@tmpb@{\zref@extract{#1}{parentcountervalue}}%
    \edef\@tmpa@{\csname the\zref@extract{#1}{parentcountername}\endcsname}%
    \ifx\@tmpb@\@tmpa@
    \Cref{#1}%
    \else
    \if@hyperrefloaded
    \zref@extract{#1}{counter} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{childcountervalue}} of \zref@extract{#1}{parentcountername} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{parentcountervalue}}%
    \else
    \zref@extract{#1}{counter} \zref@extract{#1}{childcountervalue} of \zref@extract{#1}{parentcountername} \zref@extract{#1}{parentcountervalue}%
    \fi
    \fi
  }%
}
\makeatother

\begin{document}
  \chapter{Chapter One}
  Please look at \parentCref{othersection} or at \parentCref{foosubsection} or at \parentcref{foosubsection}


  \section{Section One.One}
  \label{mysection}
  \lipsum

  \section{Section One.Two}

  \subsection{A subsection} \label{foosubsection}
  Please ignore \parentCref{mysection}.

  \chapter{Chapter Two}
  \section{Section Two.One}

  As you may have noticed, \parentCref{mysection} is useless.


  \chapter{Chapter Three}
  \section{Section Three.One}
  \section{Section Three.Two}\label{othersection}

\end{document}

enter image description here

See Renumbering chapter after part, include part number as suffix in cross-reference to chapter number for a similar question, but that's not a duplicate!

Update 2017/03/06 Some features of this answer has been added to the xassoccnt v1.3 package (Download from xassoccnt until it is available on CTAN, TeXLive (since 2017/03/06) and MikTeX) The solution is much shorter now:

\documentclass{book}
\usepackage{lipsum}
\usepackage{xassoccnt}
\usepackage{xpatch}
\usepackage{hyperref}
\usepackage[user,counter,hyperref]{zref}
\usepackage{cleveref}

\makeatletter
\AtEndPreamble{
  \newif\if@hyperrefloaded

\@ifpackageloaded{hyperref}{%
  \@hyperrefloadedtrue
}{
  \@hyperrefloadedfalse
}
}
\makeatother




\usepackage{xparse}
\makeatletter

\ExplSyntaxOn
\prop_new:N \g_latex_parentcounters_prop 
\seq_new:N  \g_latex_counters_seq

\cs_generate_variant:Nn \str_head:n {x,o,V}
\cs_generate_variant:Nn \str_tail:n {x,o,V}
\cs_generate_variant:Nn \str_upper_case:n {x,o,V}
\cs_generate_variant:Nn \str_set:Nn {Nx,No}

% Store all reset lists and make a property list for each counter and its possible parent counter

% Make the first character of a word upper case
\newcommand{\FirstUpcase}[1]{%
  \str_set:Nx \l_tmpa_str {#1}%
  \str_upper_case:x {\str_head:N \l_tmpa_str}\str_tail:V {\l_tmpa_str}%
}

\ExplSyntaxOff




% Define new properties
\zref@newprop{childcountervalue}{\arabic{\LastRefSteppedCounter}}% This is the naked value
\zref@newprop{parentcountervalue}{\csname the\GetParentCounter{\LastRefSteppedCounter}\endcsname}
\zref@newprop{parentcountername}{\GetParentCounter{\LastRefSteppedCounter}}

% Add the new properties to the main property list stored with \zlabel
\zref@addprops{main}{childcountervalue,parentcountervalue,parentcountername}

% Command for uppercase output
\NewDocumentCommand{\parentCref}{m}{%
  \zref@ifrefundefined{#1}{%
    \Cref{#1}%
  }{%
    \edef\@tmpb@{\zref@extract{#1}{parentcountervalue}}%
    \edef\@tmpa@{\csname the\zref@extract{#1}{parentcountername}\endcsname}%
    \ifx\@tmpb@\@tmpa@
    \Cref{#1}%
    \else
    \if@hyperrefloaded
    \FirstUpcase{\zref@extract{#1}{counter}} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{childcountervalue}} of \FirstUpcase{\zref@extract{#1}{parentcountername}} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{parentcountervalue}}%
    \else
    \FirstUpcase{\zref@extract{#1}{counter}} \zref@extract{#1}{childcountervalue} of \FirstUpcase{\zref@extract{#1}{parentcountername}} \zref@extract{#1}{parentcountervalue}%
    \fi
    \fi
  }%
}

% Command for lowercase output
\NewDocumentCommand{\parentcref}{m}{%
  \zref@ifrefundefined{#1}{%
    \cref{#1}%
  }{%
    \edef\@tmpb@{\zref@extract{#1}{parentcountervalue}}%
    \edef\@tmpa@{\csname the\zref@extract{#1}{parentcountername}\endcsname}%
    \ifx\@tmpb@\@tmpa@
    \Cref{#1}%
    \else
    \if@hyperrefloaded
    \zref@extract{#1}{counter} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{childcountervalue}} of \zref@extract{#1}{parentcountername} \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{parentcountervalue}}%
    \else
    \zref@extract{#1}{counter} \zref@extract{#1}{childcountervalue} of \zref@extract{#1}{parentcountername} \zref@extract{#1}{parentcountervalue}%
    \fi
    \fi
  }%
}

\makeatother


\GetAllResetLists
\RegisterPostLabelHook{\zlabel}



\begin{document}
\chapter{Chapter One}
  Please look at \parentCref{othersection} or at \parentCref{foosubsection} or at \parentcref{foosubsection}


  \section{Section One.One}
  \label{mysection}
  \lipsum

  \section{Section One.Two}

  \subsection{A subsection} \label{foosubsection}
  Please ignore \parentCref{mysection}.

  \chapter{Chapter Two}
  \section{Section Two.One}

  As you may have noticed, \parentCref{mysection} is useless.


  \chapter{Chapter Three}
  \section{Section Three.One}   %
  \section{Section Three.Two}\label{othersection}

\end{document}
  • 1
    @Mico: It's a counter - related question... don't expect too much ;-) But thanks! (The usual complainers will show up soon ;-)) – user31729 Feb 12 '17 at 22:35
  • That does indeed what I needed! I'm not at all familiar with the expl3 syntax. What is going on more precisely? – gigabytes Feb 12 '17 at 22:48
  • 1
    @Mico: See the bunch of upvotes :D :D – user31729 Feb 19 '17 at 12:03
  • 1
    @ChristianHupfer - What's really difficult is to gauge the demand for such a feature. Speaking for myself, I find it discouraging that there's been only very limited uptake to date of the zref package. Of course, this may be because the machinery of the zref package is, on the whole, rather very "low level" and doesn't lend itself easily to adoption by "end users", i.e., the "average" writer of a LaTeX-based document. If you can figure out how to provide a straightforward front end, which hides the programming complexity, from end users, some end users might actually start using it. – Mico Feb 24 '17 at 12:04
  • 1
    @Mico: The zref package is brilliant in its technique, but its main downside is the splitting between \label and \zlabel or the explicit need of \label@byprops etc. If it would hijack \label completely, many tasks could be simplified, but of course, this would break other \label/\ref related packages. I'll think about it – user31729 Feb 24 '17 at 12:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.