2

I would like to use the contentsline command in hyperref to add a reference to a document and be able to create a table of contents (list) where the entries do not necessarily appear in the order of the entries referenced (e.g., the first entry may point to page 7 and the second entry to page 5, to cite an example). For that purpose, I am using the fourth-argument version of \contentsline defined in hyperref.

If I manually set the value of the fourth argument, this works well, as shown in the following working example.

Minimal Working Example. I include below a minimal example of the code that I am currently using, where I set the target links manually:

\documentclass[a4paper,twoside]{book}

\usepackage[final]{pdfpages}
\usepackage[bookmarks=true, bookmarksnumbered=true, bookmarksopen=true]{hyperref}
\usepackage{tocloft}

\begin{document}

\pagenumbering{Roman}

\newcommand{\indexNumberOne}{}
\newlistof{myIndexOne}{myIndOne}{\indexNumberOne}
\setcounter{myIndOnedepth}{4}
\newlistentry{myIndexOnechapter}{myIndOne}{0}
\newlistentry[myIndexOnechapter]{myIndexOnesection}{myIndOne}{1}
\newlistentry[myIndexOnesection]{myIndexOnesubsection}{myIndOne}{2}
\newlistentry[myIndexOnesubsection]{myIndexOnesubsubsection}{myIndOne}{3}

\pagenumbering{arabic}
\setcounter{page}{1}

\pdfbookmark[1]{Main TOC (documents appear in sequential order)}{MainTOC}
\tableofcontents
\cleardoublepage

\pdfbookmark[1]{Additional index (documents DO NOT appear in sequential order)}{AdditionalIndex}
\listofmyIndexOne
\cleardoublepage

\addtocontents{myIndOne}{\centerline{\underline{Additional Index}}} 
\addtocontents{myIndOne}{\string\contentsline{subsection}{Document 2}{\pageref*{docTwo}}{section*.2}}
\cleardoublepage

\addtocontents{myIndOne}{\string\contentsline{subsection}{Document 1}{\pageref*{docOne}}{section*.1}}
\cleardoublepage

\phantomsection
\label{docOne}
\addcontentsline{toc}{section}{Document 1}
\includepdf[pages=-,fitpaper=true]{doc1.pdf}
\cleardoublepage

\phantomsection
\label{docTwo}
\addcontentsline{toc}{section}{Document 2}
\includepdf[pages=-,fitpaper=true]{doc2.pdf}
\cleardoublepage

\end{document}

Question. What I would like is a general solution to replace things like "section*.2" and "section*.1" in such a way that this is computed automatically from the labels (the current links, as they have been set manually, will end up pointing to the wrong place if the order of documents is moved). Is there any way to compute the right hyperlink for the last argument of \contentsline in the hyperref package automatically, based on its label? Or is there any other alternative to achieve my goal (avoiding the use of literal target links like section*.1 and section*.2)?

An alternative that I tried (with no success). I tried with things like:

\addtocontents{myList}{\string\contentsline{subsection}{Title of the entry}{\pageref*{labelForTheEntry}}{\ref{labelForTheEntry}}}

but it does not work.

Another alternative that I tried (with no success). I tried to use \csname r@labelForTheEntry\endcsname on the minimal working example. However, it does not seem to work, as I explain below:

By replacing

\addtocontents{myIndOne}{\string\contentsline{subsection}{Document 2}{\pageref*{docTwo}}{section*.2}}

by

\addtocontents{myIndOne}{\string\contentsline{subsection}{Document 2}{\pageref*{docTwo}}{\csname r@labelForTheEntry\endcsname}}

The line generated in the .myIndOne file is

\contentsline {subsection}{Document 2}{\pageref *{docTwo}}{{}{7}{}{section*.2}{}}

instead of

\contentsline {subsection}{Document 2}{\pageref *{docTwo}}{section*.2}

So, both strategies are not equivalent. Directly specifying {section*.2} works but with {\csname r@labelForTheEntry\endcsname} it does not work.

This question is related to contentsline in hyperref: setting the target link. Here I am providing code that can be compiled and all the details needed, as suggested.

Any ideas?

  • Try using \getpagerefnumber and \getrefbykeydefault. They are defined in hyperref, but documented in refcount. – John Kormylo Oct 29 '18 at 13:51
1
\documentclass[a4paper,twoside]{book}

\usepackage[T1]{fontenc}
% \usepackage[utf8]{inputenc}% not needed with recent latex

\usepackage[final]{pdfpages}
\usepackage[bookmarks=true, bookmarksnumbered=true, bookmarksopen=true]{hyperref}
% \usepackage[titles]{tocloft}

\usepackage{etoc}% only to get toc contents stored

\makeatletter
\newcommand{\storetocentries}{%
  \begingroup
    \def\contentsline##1##2##3##4{%
        \global\@namedef{tOcEnTrY-\detokenize{##2}}%
                        {\contentsline{##1}{##2}{##3}{##4}}%
    }%
    \setbox0\vbox{{\the\Etoc@toctoks}}% uses an internal etoc register
  \endgroup
}

\newcommand{\tocentry}[1]{%
  \begingroup
  \let \label \@gobble \let \index \@gobble \let \glossary \@gobble
  \let \protect \@unexpandable@protect
  \edef\x{\endgroup\noexpand\csname
          tOcEnTrY-\noexpand\detokenize{#1}\endcsname}%
  \x
}

\makeatother


\begin{document}
\pagenumbering{arabic}
\setcounter{page}{1}


\pdfbookmark[1]{Main TOC (documents appear in sequential order)}{MainTOC}
\tableofcontents

\storetocentries

\cleardoublepage

\pdfbookmark[1]{Additional index (documents DO NOT appear in
  sequential order)}{AdditionalIndex}

\markboth{Additional Index}{Additional Index}
\centerline{\underline{Additional Index}}
% ids must be unique
\tocentry{ééçàù 3}
\tocentry{Document 2}
\tocentry{Document 1}
\tocentry{I do not exist, but no error raised}
\cleardoublepage

\markboth{}{}

\phantomsection
\addcontentsline{toc}{section}{Document 1}
\includepdf[pages=-,fitpaper=true]{example-image-a.pdf}
\cleardoublepage

\phantomsection
\addcontentsline{toc}{section}{Document 2}
\includepdf[pages=-,fitpaper=true]{example-image-b.pdf}
\cleardoublepage

\phantomsection
\addcontentsline{toc}{section}{ééçàù 3}
\includepdf[pages=-,fitpaper=true]{example-image-c.pdf}
\cleardoublepage

\end{document}

enter image description here

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.