1

I am writing a document using KOMAscript's scrreprt class, and I am writing a custom macro (\xref) to format text used for cross-references.

This macro takes the label name as an argument: \xref{mylabel}

I want to generate a different text depending on whether the label refers to a chapter/section/subsection (numbered by default) or to a subsubsection/paragraph (unnumbered by default).

How can I check this? Any of the following two would do:

  1. Check if the label refers to a chapter/section/subsection (or the opposite: Check if the label refers to a subsubsection/paragraph)
  2. Check if the label refers to a numbered item
Grodriguez
  • 1,149
  • 2
    Package zref is a good friend, see for example my answer to this question here: http://tex.stackexchange.com/questions/312060/how-to-reference-sections-in-other-parts-mentioning-the-part –  Feb 01 '17 at 12:38
  • 3
    You can use cleveref as well –  Feb 01 '17 at 12:44
  • 1
    Well, what do you think scrreport makes use of in the final end? ;-) Using no extra packages, this you have to do redefinitions in the \label - \ref system. This requires some LaTeX skills. I don't see the point to reinvent the wheel. –  Feb 01 '17 at 12:47
  • Even hyperref's \autoref can be used for this. – Schweinebacke Feb 01 '17 at 12:51
  • Thank you for all the suggestions of alternative packages. What I am looking for is a way to test the type of element a label refers to. – Grodriguez Feb 01 '17 at 12:52
  • 1
    @Schweinebacke: But that's not expandable (as far as I can remember), which is necessary, to make it working in checks... and it is in an extra package ;-) –  Feb 01 '17 at 12:52
  • @ChristianHupfer: Depends on what is wanted. Maybe the output of \autoref is just the wanted result. Maybe redefining the names may be enough. Maybe not. – Schweinebacke Feb 01 '17 at 12:54
  • 1
    @Grodiguez: LaTeX itself does not provide a type of element for labels. So you either need to use an additional package or you have to extend the label mechanism of LaTeX similar to such existing packages. I would recommend to use an existing package. – Schweinebacke Feb 01 '17 at 12:55
  • Your second test idea -- "Check if the label refers to a numbered item" -- has no chance of working, unless you somehow massively rewrite the code that underlies the \label macro (and likely break all kinds of stuff in the process...). By default, the \label instruction looks for the counter variable that was most recently incremented via a \refstepcounter instruction. However, if some item is not numbered to begin with, there is simply no such association to latch on to. (to be continued) – Mico Feb 01 '17 at 13:14
  • (continued from preceding comment) You should probably look into the far more general (but also more elaborate) \hyperlink-\hypertarget machinery of the hyperref package. But then, you seem to be averse to loading any external packages... – Mico Feb 01 '17 at 13:15
  • @Mico I am not averse to loading external packages if they help me to do what I want to do. – Grodriguez Feb 01 '17 at 13:18
  • @Mico: In fact, it is possible (with some assumptions) to check whether the label refers to a numbered identity: hyperref uses a * in the anchor name. As long as nobody screws up the \theH.... output zref can be used to exploit the anchor name and check, whether there is a * inside (and of course nobody should define a counter name with * inside) –  Feb 03 '17 at 13:37
  • @ChristianHupfer - Thanks for pointing this out. When I wrote the earlier comment, I was thinking mostly about the "basic"-LaTeX \label instruction. Good to know that hyperref modifies the \label macro in interesting ways. – Mico Feb 03 '17 at 15:08
  • @Mico: Actually, I had to think about it for some days until I had the idea with the anchor check. As said above ... it is not failsafe, of course –  Feb 03 '17 at 15:12

1 Answers1

5

See the update for referring to unnumbered/numbered structure unit and checking at the end.

Without using any extra packages, only \renewcommand, \let, \pdfstrcmp etc. are used and writing a \@namedef to the .aux file.

It requires two runs (which are needed anyway, since we're dealing with labels!)

Use \extractlabeltype{labelname} and \checklabeltype with true/false branch.

It assumes that no other package is involving with \label and \ref, i.e. no hyperref or cleveref is supported.

\documentclass{book}


\makeatletter
\let\latex@@refstepcounter\refstepcounter
\let\latex@@label\label%


\renewcommand{\refstepcounter}[1]{%
  \gdef\lastrefsteppedcounter{#1}%
  \latex@@refstepcounter{#1}%
}

\renewcommand{\label}[1]{%
  \immediate\write\@auxout{\string\global\string\@namedef{label#1}{\lastrefsteppedcounter}}
   \latex@@label{#1}%
}

\newcommand{\extractlabeltype}[1]{%
  \@nameuse{label#1}%
}

\makeatother

\newcommand{\checklabeltype}[4]{%
\ifnum0=\pdfstrcmp{\extractlabeltype{#1}}{#2}
#3%
\else
#4%
\fi
}


\begin{document}



\chapter{Foo} \label{foo}


\section{Foosection}\label{foosection}

\checklabeltype{foosection}{section}{Yes, it is section}{No, it is something different}

\checklabeltype{foo}{section}{Yes, it is section}{No, it is something different}


\end{document}

enter image description here

Update with checking for unnumbered/numbered issues.

Please not that this deliberately depends on the assumption that the anchor name of a unnumbered structure unit has a * in it, so playing around with \theH... macros is no good idea ;-)

\documentclass{book}

\usepackage{xparse}
\usepackage[hyperref,counter]{zref}% Using the counter mechanism behind `nameref`
\usepackage{hyperref}


\makeatletter
\AtBeginDocument{%
  \let\latex@@label\label%

  \renewcommand{\label}[1]{%
    \zref@label{#1}%
    \latex@@label{#1}%
  }
  % Get the underlying counter type
  \newcommand{\extractlabelcounter}[1]{%
    \zref@ifrefundefined{#1}{%
      ???????}{%
      \zref@extract{#1}{counter}%
    }%
  }
  % Get the anchor name for hyperref or nameref -> has a `*` inside if it is unnumbered
  \newcommand{\extractlabelanchor}[1]{%
    \zref@ifrefundefined{#1}{%
      ???????}{%
      \zref@extract{#1}{anchor}%
    }%
  }
}

% Check if there's a `*` inside of the anchor name
\ExplSyntaxOn
\cs_new:Npn \checkifnumbered#1#2#3{%
  \tl_set:Nx \l_tmpa_tl {\extractlabelanchor{#1}}
  \tl_if_in:NnTF \l_tmpa_tl {*} {#2} {#3}
}
\ExplSyntaxOff

\makeatother


\newcommand{\checklabeltype}[4]{%
  \ifnum0=\pdfstrcmp{\extractlabelcounter{#1}}{#2}
  #3%
  \else
  #4%
  \fi
}

\begin{document}
\chapter{Foo} \label{foo}

\section*{An unnumbered section} \label{unnumbered}

\section{Foosection}\label{foosection}

\checklabeltype{foosection}{section}{Yes, it is section}{No, it is something different}

\checklabeltype{foo}{section}{Yes, it is section}{No, it is something different}

\begin{enumerate}
\item First \label{enumfirst}
\item Second \label{enumsecond}
\end{enumerate}

\checklabeltype{enumsecond}{enumi}{It is a numbered item and has the value \ref{enumsecond}}{}

In \nameref{unnumbered} we have an \checkifnumbered{unnumbered}{unnumbered}{numbered} \extractlabelcounter{unnumbered}


In \nameref{foo} we have an \checkifnumbered{foo}{unnumbered}{numbered} \extractlabelcounter{foo} whereas
 \nameref{foosection} is a \checkifnumbered{foosection}{unnumbered}{numbered} \extractlabelcounter{foosection}.


\end{document}

enter image description here

  • +1 for a solution that's compatible with the hyperref and cleveref packages. :-) – Mico Feb 01 '17 at 13:25
  • @Mico: Is it? I did not check. I doubt that cleveref's \label[...]{...} will like this ;-). –  Feb 01 '17 at 13:27
  • @Grodriguez: It's a little bit more complicate with zref but more flexible, currently I am not sure that cleveref is the right package for your needs –  Feb 01 '17 at 13:45
  • @ChristianHupfer On testing this a bit more I noticed that it does not work as required. If you define a label for a subsubsection (which is unnumbered in the book class), extractlabeltype thinks it is a "subsection".... – Grodriguez Feb 01 '17 at 18:23
  • @Grodriguez: Yes, but in this case labelling a unnumbered subsubsection does not make any sense, does it? ;-) Using my solution or not, it will still use the label of the preceding subsection, that's how LaTeX is defined. –  Feb 01 '17 at 18:56
  • @ChristianHupfer Well, that was exactly the point of my original question. I want to check the label type so that I can use \nameref for subsubsections and paragraphs, but \ref for chapters, sections and subsections. And I want to do this in an automated way (not manually) – Grodriguez Feb 01 '17 at 18:59
  • @Grodriguez: An unnumbered section level does not use \refstepcounter, so you won't have a working label (it will use the label value of the last \refstepcounter before (which is the case I've described in my last comment) and that label is wrong then. It won't work with hyperref, zref, cleveref etc. That's why I wrote it requires some insight into the label/ref mechanism and LaTeX skills... –  Feb 01 '17 at 19:03
  • \label to unnumbered structure level fails. Period! –  Feb 01 '17 at 19:05
  • @ChristianHupfer No, \label doesn't fail. I can \nameref to an unnumbered section just fine. It is \ref with an unnumbered section that will fail. That is why I am looking for a way to tell if a label refers to an unnumbered section or to a numbered one, so that I know whether I need to use \nameref or \ref. – Grodriguez Feb 01 '17 at 22:54
  • 1
    @Grodiguez: That's just because hyperref changes refstepcounter. \nameref is not expandable, by the way –  Feb 01 '17 at 22:59
  • @Grodriguez: Alright, but nearly impossible without using other packages –  Feb 03 '17 at 14:44
  • 1
    @ChristianHupfer Your updated solution works like a charm. This is just what I was looking for. – Grodriguez Feb 06 '17 at 11:50
  • @Grodriguez: Well, that's nice. Happy TeXing! –  Feb 06 '17 at 12:27