# Extracting the “parent” counter of a sectional unit

I am interested in finding the "parent" counter of a specific sectional unit. For example, in the following document structure

1. A section
1.1 A subsection
1.1.1 A subsubsection
1.1.2 A subsubsection
1.1.2.1 A paragraph
1.2 A subsection
1.2.1 A subsubsection
1.2.1.1 A paragraph
1.2.1.2 A paragraph
1.2.2 A subsubsection


the (immediate) "parent" of subsubsection 1.2.1 is (subsection) 1.2. The (immediate) "parent" of (paragraph) 1.1.2.1 is (subsubsection) 1.1.2.

The solution should be

• of the form \parentlabel that one can call within some sectional unit;
• be able to work with sectional units that have no parent. For example, if the sectional unit is \chapter, with \thechapter defined as \arabic{chapter}, \parentlabel should be empty {} (say); and
• flexible enough so that redefinition of (say) counter displays does not play a role. That is, if one chooses to use - instead of ., the solution should still hold. So I don't think string parsing (using, say, xstring) would be useful.

Here is one attempt and a minimal playground:

\documentclass{article}
\def\parentlabel{\relax}% Placeholder for parent counter/level/label
\makeatletter
\let\oldsection\section
\renewcommand{\section}{\edef\parentlabel{\@currentlabel}\oldsection}%
\let\oldsubsection\subsection
\renewcommand{\subsection}{\edef\parentlabel{\@currentlabel}\oldsubsection}%
\let\oldsubsubsection\subsubsection
\renewcommand{\subsubsection}{\edef\parentlabel{\@currentlabel}\oldsubsubsection}%
\let\oldparagraph\paragraph
\renewcommand{\paragraph}{\edef\parentlabel{\@currentlabel}\oldparagraph}%
\newcommand{\showparent}{Current: \@currentlabel; Parent: \parentlabel}
\makeatother
\setcounter{secnumdepth}{4}
\begin{document}
\section{A section} \showparent
\subsection{A subsection} \showparent
\subsubsection{A subsubsection} \showparent
\subsubsection{A subsubsection} \showparent
\paragraph{A paragraph} \showparent
\subsection{A subsection} \showparent
\subsubsection{A subsubsection} \showparent
\paragraph{A paragraph} \showparent
\paragraph{A paragraph} \showparent
\subsubsection{A subsubsection} \showparent
\end{document}


The method relies on capturing \@currentlabel before it is updated via a sectional command.

It is obvious that this methods works fine while drilling down the sectional levels. However, stepping back to a higher level leaves \parentlabel to not accurately represent the "parent" label.

-
Also it wouldn't work for classes with chapters. –  Marc van Dongen Feb 15 '12 at 6:06
@MarcvanDongen: This is true. I'm hoping I could generalize it myself once I have something established that solves this for article. –  Werner Feb 15 '12 at 6:07
Hint: in a section, \thesubsection ends in .0 if you're not in a subsection. –  Marc van Dongen Feb 15 '12 at 6:56

\documentclass{article}
\def\determinecurrentlevel{%
\ifnum\value{section}=0
0
\else
\ifnum\value{subsection}=0
1
\else
\ifnum\value{subsubsection}=0
2
\else
\ifnum\value{paragraph}=0
3
\else
4
\fi
\fi
\fi
\fi
}
\def\showparent{%
\ifcase\determinecurrentlevel
\or
\ifdefined\chapter\thechapter\fi
\or
\thesection
\or
\thesubsection
\or
\thesubsubsection
\or
\theparagraph
\fi}

\setcounter{secnumdepth}{4}
\begin{document}
\section{A section} \showparent
\subsection{A subsection} \showparent
\subsubsection{A subsubsection} \showparent
\subsubsection{A subsubsection} \showparent
\paragraph{A paragraph} \showparent
\subsection{A subsection} \showparent
\subsubsection{A subsubsection} \showparent
\paragraph{A paragraph} \showparent
\paragraph{A paragraph} \showparent
\subsubsection{A subsubsection} \showparent
\end{document}


The long concatenation of conditionals can be reduced with \numexpr:

\def\determinecurrentlevel{%
\numexpr
\ifnum\value{section}>0       1+\fi
\ifnum\value{subsection}>0    1+\fi
\ifnum\value{subsubsection}>0 1+\fi
\ifnum\value{paragraph}>0     1+\fi
0\relax}

-

A flexible approach would be to define hooks in every sectioning command indicating the parent counter, without worrying for any formatting, which will be available in the relevant \the command such as \thesection. Suggestion:

\@namedef{part}{}
\@namedef{parent@chapter}{\the\c@part}
\@namedef{parent@section}{\the\c@chapter}
\@namedef{parent@subsection}{\the\c@section}
\@namedef{parent@subsubsection}{\the\c@subsection}
\@namedef{parent@paragraph}{\the\c@subsubsection}


What you store in the parent@section macros depends on your needs. You can store only the c@section part, if you want to do any detail manipulation after that. It is just a way of creating a pointer to the parent.

We also define two convenience macros for testing:

\def\sectionlist{part,chapter,section,subsection,
subsubsection,paragraph}
\def\checkall{\@for\next:=\sectionlist\do{
\next\ has parent = \csname parent@\next\endcsname\\
}


The full minimal is shown below:

\documentclass{book}
\makeatletter
\makeatletter
\setcounter{secnumdepth}{6}
\def\sectionlist{part,chapter,section,subsection,
subsubsection,paragraph}
\@namedef{part}{}
\@namedef{parent@chapter}{\the\c@part}
\@namedef{parent@section}{\the\c@chapter}
\@namedef{parent@subsection}{\the\c@section}
\@namedef{parent@subsubsection}{\the\c@subsection}
\@namedef{parent@paragraph}{\the\c@subsubsection}
\def\checkall{\@for\next:=\sectionlist\do{
\next\ has parent = \csname parent@\next\endcsname\\
}
}
\makeatother
\begin{document}
\part{One}
\checkall
\chapter{One}
\checkall
\chapter{Two}
\checkall

\section{One}
\checkall
\subsection{One}
\checkall
\subsubsection{One}
\checkall
\paragraph{Test paragraph}
\checkall
\end{document}

-

This is a fairly general solution based on using expl3's data type prop. The complete code is somewhat longer than the other solutions. However, it provides a fully general solution that would work with arbitrary counter combinations out of the box.

The main idea is that in LaTeX2e there is already a good part of support for this as counters are usually reset by their parent counter. So as a starting point we assume that this reset defines the parent structure and add code to \@addtoreset to store the parent counter away. If that is not sufficient we provide \setparent to specify the parent counter by hand.

The second component we need is to provide a \@currentcounter in parallel to \@currentlabelwhich we add to \refstepcounter. Finally we provide \builtcurrentlabel to form a label from a counter name for typesetting (that just one of the lines from \refstepcounter put into a separate macro.

\showparent then just has to typeset the current label and a label generated from the parent counter (if any):

\makeatletter
\expandafter\@cons\csname cl@#2\endcsname {{#1}}%
% NEW: store parent info
\setparent {#1}{#2}%
}
\def\refstepcounter#1{\stepcounter{#1}%
\protected@edef\@currentlabel
{\csname p@#1\endcsname\csname the#1\endcsname}%
% NEW: save current counter
\protected@edef\@currentcounter{#1}%
}
% NEW: taken from refstepcounter
\def\builtcurrentlabel #1{%
\csname p@#1\endcsname
\csname the#1\endcsname
}
\def\showparent{%
Current: \@currentlabel; Parent: \typesetparentlabel{\@currentcounter}%
}
\makeatother


Now all that remains to do is to actually store and retrieve the parent counter mappings. By the way all this has to happen before \documentclass so that the counters are still to be defined otherwise \@addtoreset would not act. So we have to use \RequirePackage to load expl3.

We store the parent counter name in a property list (\g_pcnt_parent_counter_prop) with the current counter name as key and the parent as value. The only extra complexitiy here is that a new counter without parent is added to the counter @ckpt (for the include mechanism) and we do not want to consider that one as a parent:

\RequirePackage{expl3}

\ExplSyntaxOn

\prop_new:N \g_pcnt_parent_counter_prop
\tl_new:N \l_pcnt_result_tl

\cs_new:Npn \pcnt_store_parent_counter:nn #1#2 {
\str_if_eq:nnF{@ckpt}{#2}
{  \prop_gput:Nnn \g_pcnt_parent_counter_prop {#1}{#2} }
}


Retrieving is equally simple: if we do not find a value we return an empty tokenlist

\cs_new:Npn \pcnt_get_parent_counter:nN #1#2 {
\prop_get:NnN \g_pcnt_parent_counter_prop {#1} #2
\quark_if_no_value:NT #2
{ \tl_clear:N #2 }
}
\cs_generate_variant:Nn \pcnt_get_parent_counter:nN {o} % needed below


Finally the interfaces: typesetting the parentlabel means retrieving the parent counter name and if not empty run it though \builtcurrentlabel:

\cs_new_eq:NN \setparent \pcnt_store_parent_counter:nn

\cs_new:Npn \typesetparentlabel #1 {
\pcnt_get_parent_counter:oN {#1} \l_pcnt_result_tl
\tl_if_empty:NF \l_pcnt_result_tl
{ \builtcurrentlabel{\l_pcnt_result_tl} }
}


And if we want we could also peak at our data structures we can define:

%% for tracing %%
\cs_new:Npn \showparentcounters {\prop_show:N \g_pcnt_parent_counter_prop }
\cs_new:Npn \showparentcounter #1 {
\pcnt_get_parent_counter:nN {#1} \l_pcnt_result_tl
\tl_show:N  \l_pcnt_result_tl
}


In the example document from the question \showparentcounterswould produce

The property list \g_pcnt_parent_counter_prop contains the pairs (without
outer braces):
>  {subsection}  =>  {section}
>  {subsubsection}  =>  {subsection}
>  {paragraph}  =>  {subsubsection}
>  {subparagraph}  =>  {paragraph}.

-