3
  • I want to have (visible) IDs that are persistent (maybe there is a better term in English than 'persistent') and unique within a document.
  • With persistent, I mean, that if I add additional stuff with IDs, then the old IDs will stay the same (even I delete the standard aux files).
  • At the moment I use the \subparagraph level of the KOMA book class. The \subparagraph number serves as the ID. The ID is unique but not persistent.
  • Context: The use case is that the IDs label requirements in a specification.

Do you have any idea how to achive persistent and unique IDs? I would like to use pdflatex and (if possible) stick to KOMA class. I am open for suggestions!

PS: I did not know which tags to use for this question.

// Update because of the lively discussion in the comments

  • First of all, thanks!
  • I do not have a clear vision/perception of the compromises that I can handle. So far I just have unique IDs an nothing more.
  • I use the headings because it was a lazy way to get unique numbers and they do not interfer with other stuff (this was my initial solution: \everypar in section (or chapter) command not working).
  • I am interested in what would be possible.
  • If the solutions cause some restictions, then I am willing to try them.


\documentclass[parskip=full]{scrbook}
\usepackage{xcolor}

% Number \subparagraph
\setcounter{secnumdepth}{5}

% Add \subparagraph to TOC (not important for the MWE)
\setcounter{tocdepth}{5}

% Color \subparagraph
\addtokomafont{subparagraph}{\color{red}}

\begin{document}
\tableofcontents
\chapter{Chapter}
Test text. Test text. Test text.
\section{Section}
Test text. Test text. Test text.
\subsection{Subsection}
Test text. Test text. Test text.
\subsubsection{Subsubsection}
Test text. Test text. Test text.
\paragraph{Paragraph}
Test text. Test text. Test text.
\subparagraph{Subparagraph: Should have a Persistent and Unique ID / Number}
Test text. Test text. Test text.
\end{document}

enter image description here

  • 3
    'cross-referencing' is probably still not the best tag, but since the problem as such has nothing to do with KOMA-script it seemed like a better option. – moewe Feb 11 at 9:34
  • 2
    It's an interesting question and my initial feeling is that the only way to get a truly persistent ID is by writing it directly into the source, but I'm eagerly waiting to be proven wrong. (Though I must say that I would disqualify solutions that cheat by writing to a different temporary file than .aux.) – moewe Feb 11 at 9:36
  • 2
    Well one easy way to cheat would be to write the label to a file that is not the .aux, say .mklabel. That might technically satisfy your 'even I delete the aux files', but that has the same structural limitations as writing to the .aux: If the file is gone, the info is gone. Now you could try to write to a designated system file that you always keep around, but then you make your file dependent on your machine (plus I doubt that LaTeX can just write to any location willy nilly). – moewe Feb 11 at 9:40
  • 3
    What about introducing md5sum hashes? I.e. \pdfmdfivesum{subparagraph title} will give a persistent, unique hash ID -- unless the same paragraph title is more than once – user31729 Feb 11 at 9:42
  • 2
    Your question has a lot of comments as it is basically not clear enough to answer. You mention deleting aux files, but that has no effect on the numbering, so do you want a unique id even if the document is edited and the number changes, as in HTML where you can go <li id="zzz">... and then use a reference of href="foo.html#zzz that is stable even if that <li> changes from item 2. to item 3. ? If so then \label is the direct analogue. If you mean something else than can you edit the question to make it clearer what you mean....? – David Carlisle Feb 11 at 11:04
3

"persistent ID", "unique ID" - it is still not clear to me what you are actually after.

What instance(s) shall create these IDs?
What instance(s) shall use these IDs in which ways?
What is the use/purpose of these IDs?

Is the machine/the LaTeX-compiler to create these IDs automatically?

If this is what you are after:

When it comes to using these IDs—will there be some intervention by an instance other than the (La)TeX-program itself that needs to know about these IDs/that needs to know what exactly is to be identified by which ID? (Such an instance could, e.g., be the instance which delivers/creates the (La)TeX source code. ;-) )

If this is the case: In which ways shall that instance obtain the information she/he/it needs?

If this is not the case, then it seems that there are to be routines that without intervention both create the IDs and handle all the usage of these IDs.

It seems, the requirement of persistence throughout LaTeX-runs in any case implies:

With each call to routines that automatically generate and use pieces of information in form of IDs that are to be persistent throughout LaTeX-runs, additional information would need to be left for future LaTeX-runs which these routines could with each call in the next LaTeX-run use for detecting the information that was left by that call in the current LaTeX-run to which the call in question of the next LaTeX-run corresponds.

Thus you would need unique non-changing identifiers for the calls of the routines themselves and you would need to have LaTeX preserve these unique non-changing identifiers throughout all LaTeX runs.

A problem with this:
The only way known to me of preserving pieces information created during LaTeX-runs throughout LaTeX-runs is by means of temporary files which can be read within the next LaTeX-run. The info will be lost when the temporary files in question cease to exist.

Another problem with this:
Above I already mentioned that you would need unique non-changing identifiers for the single calls of the routines themselves and that you would need to have LaTeX preserve these identifiers throughout LaTeX-runs.
Thus you would need a mechanism for automatically creating and preserving throughout LaTeX-runs these unique and non-changing identifies of the single calls of the ID-producing routines.
And voilà: You would face the initial problem, just on an underlying level.

Therefore I assume that in any case there will be some level of identification where unique non-changing identifiers need to be provided by the instance that provides the (La)TeX source code.

Here the cross-referencing-mechanism of LaTeX 2e comes to my mind:

With LaTeX 2e's \label{⟨name of referencing-label⟩}-\...ref{⟨name of referencing-label⟩}-cross-referencing-mechanism the instance that provides the tex-source-code is urged to provide unique names for cross-referencing-labels.
If that instance doesn't, LaTeX 2e will complain via warnings about labels that are multiply defined.
You can see these warnings on the screen of the terminal/shell in use and in the .log-file.
These names for cross-referencing-labels will be persistent as long as no one changes them within the tex-source-code.

After reading the comments to the question it seems that a \label-\ref-mechanism which does not only provide referencing-commands for placing textual phrases like page numbers and counter values and the like into the output-file (pdf-file) but does also provide a referencing-command for placing a textual phrase denoting the name of the referencing-label itself into the output-file (pdf-file) might probably be what you need.

Usually with the \label-\ref-mechanism you can only obtain page numbers and counter values.
Using Heiko Oberdiek's zref-package you can easily enhance the \label-\ref-mechanism so that label-commands store and referencing-commands deliver other pieces of information as well. Such a piece of information could be the name of the referencing-label itself.

In the example below I used Heiko Oberdiek's zref-package for creating a command \LabelWhoseNameCanBeShown which works like the \label command. The difference is that besides referencing via \ref, \pageref, \hyperref[...]{...}, etc, it makes it also possible to reference the name of the label itself via a command \ReferNameOfLabelWhoseNameCanBeShown.

\ReferNameOfLabelWhoseNameCanBeShown{⟨name of referencing-label⟩} should act as follows:

In case the referencing-label ⟨name of referencing-label⟩ was defined/introduced via \LabelWhoseNameCanBeShown{⟨name of referencing-label⟩}, \ReferNameOfLabelWhoseNameCanBeShown should (within the second LaTeX-run) deliver ⟨name of referencing-label⟩ as textual phrase into the .pdf-output-file.

In case defining/introducing the referencing-label ⟨name of referencing-label⟩ via \LabelWhoseNameCanBeShown{⟨name of referencing-label⟩} did not take place, \ReferNameOfLabelWhoseNameCanBeShown should deliver an error-message and some questionmarks.

\documentclass[a4paper]{article}
\usepackage{hyperref}
\usepackage{zref}

\makeatletter
\newskip\UD@savsk
\newcommand*\UD@bsphack{%
  \relax
  \ifhmode\UD@savsk\lastskip\@savsk\lastskip\@savsf\spacefactor\fi
}%
\newcommand*\UD@esphack{%
  \relax
  \ifhmode
    \spacefactor\@savsf
    \ifdim\@savsk>\z@
      \ifdim\lastskip=\z@\nobreak\hskip\z@skip\fi
      % The following \hskips are used for restoring \lastskip.
      % I hope there are no evil side-effects. ;-)
      \nobreak\hskip-\UD@savsk
      \nobreak\hskip\UD@savsk
      \ignorespaces
    \fi
  \fi
}%
%
%
\zref@newprop{labelname}{}%
\DeclareRobustCommand\LabelWhoseNameCanBeShown[1]{%
  \UD@bsphack
  \zref@setcurrent{labelname}{#1}%
  \zref@labelbyprops{#1}{labelname}%
  \label{#1}%
  \UD@esphack
}%
\DeclareRobustCommand\ReferNameOfLabelWhoseNameCanBeShown[1]{%
  \zref@extractdefault{#1}%
                      {labelname}%
                      {\nfss@text{\reset@font\bfseries ??}\refused{#1}}%
}%
\makeatother

\pagestyle{empty}
\textwidth=\paperwidth
\addtolength\textwidth{-4cm}%
\oddsidemargin=2cm
\addtolength\oddsidemargin{-1in}%
\addtolength\oddsidemargin{-\hoffset}%
\evensidemargin=\oddsidemargin
\marginparwidth=1.5cm
\marginparsep=0.25cm
\parindent=0ex
\parskip=\medskipamount

\begin{document}

Referencing the thing:

\sloppy

\verb|\ReferNameOfLabelWhoseNameCanBeShown{A unique label name}|:
\mbox{\ReferNameOfLabelWhoseNameCanBeShown{A unique label name}}

\verb|\ref{A unique label name}|:
\mbox{\ref{A unique label name}}

\verb|\pageref{A unique label name}|:
\mbox{\pageref{A unique label name}}

\verb|\nameref{A unique label name}|:
\mbox{\nameref{A unique label name}}

\verb|\hyperref[{A unique label name}]{\ReferNameOfLabelWhoseNameCanBeShown{A unique label name}}|:
\mbox{\hyperref[{A unique label name}]{\ReferNameOfLabelWhoseNameCanBeShown{A unique label name}}}

\null\hrulefill\null

\begin{verbatim}
\section{A section}
\section{Another section}
% Introducing the thing:
\LabelWhoseNameCanBeShown{A unique label name}%
% If you wish to see the thing immediately, just reference it immediately:
\ReferNameOfLabelWhoseNameCanBeShown{A unique label name} 
Some text. Some text. Some text. Some text. Some text. Some text. 
Some text. Some text. Some text. Some text. Some text. Some text. 
Some text. Some text. Some text. Some text. Some text. Some text. 
\end{verbatim}

\section{A section}
\section{Another section}
% Introducing the thing:
\LabelWhoseNameCanBeShown{A unique label name}%
% If you wish to see the thing immediately, just reference it immediately:
\ReferNameOfLabelWhoseNameCanBeShown{A unique label name} 
Some text. Some text. Some text. Some text. Some text. Some text. 
Some text. Some text. Some text. Some text. Some text. Some text. 
Some text. Some text. Some text. Some text. Some text. Some text. 

\end{document}

enter image description here


Alternatively you can, e.g., create macros
\IDpar{⟨Unique ID⟩},
\ReferIDpar{⟨Unique ID⟩} and
\HyperReferIDpar{⟨Unique ID⟩}
whereof

  • \IDpar creates a new paragraph and writes the ID of it into a margin-note.
  • \ReferIDpar lets you refer to that ID, yielding error-messages in case the ID wasn't introduced via \IDpar.
  • \HyperReferIDpar additionally turns the reference into a clickable hyperlink for navigating to the referenced paragraph.

Still you need to provide the IDs manually and therefore you may wish to maintain a list of already used IDs as a comment in your TeX source file:

\documentclass[parskip=full, mpinclude=true, twoside=semi]{scrbook}
\usepackage{marginnote}
\usepackage{xcolor}
\usepackage{hyperref}
% Number \subparagraph
\setcounter{secnumdepth}{5}
% Add \subparagraph to TOC (not important for the MWE)
\setcounter{tocdepth}{5}
% Color \subparagraph
% \addtokomafont{subparagraph}{\color{red}}
%
\makeatletter
\DeclareRobustCommand\FormatIDOfPar[1]{%
  \hbox to 2cm{\null\hfill\textnormal{#1}\hbox to 5mm{}}%
}%
\newcommand\IDlabelPrefix{SPEC.}%
\newcommand\IDPrefix{SPEC\protect~}%
\DeclareRobustCommand\IDpar[1]{%
  \par\leavevmode
  \marginpar{%
    \FormatIDOfPar{%
      \begingroup
      \@ifundefined{Hy@raisedlink}{}{%
        \Hy@raisedlink{\hyper@anchorstart{\IDlabelPrefix#1}\hyper@anchorend}%
      }%
      \ReferIDpar{#1}%
      \def\@currentlabel{\IDPrefix#1}%
      \def\@currentHref{\IDlabelPrefix#1}%
      \label{\IDlabelPrefix#1}%
      \endgroup
    }%
  }%
  \ignorespaces
}%
\@ifpackageloaded{hyperref}{%
  \DeclareRobustCommand\ReferIDpar[1]{%
    \ref*{\IDlabelPrefix#1}%
  }%
  \DeclareRobustCommand\HyperReferIDpar[1]{%
    \hyperref[\IDlabelPrefix#1]{\ref*{\IDlabelPrefix#1}}%
  }%
}{%
  \DeclareRobustCommand\ReferIDpar[1]{%
    \ref{\IDlabelPrefix#1}%
  }%
  \DeclareRobustCommand\HyperReferIDpar[1]{%
    \ref{\IDlabelPrefix#1}%
  }%
}%
\makeatother

\reversemarginpar

% List of IDs used so far:
% ========================
% (As in this example IDs are continuously numbered and I increased the
%  number whenever introducing another ID, it is sufficient to keep
%  track of the number of the ID that was introduced as the last one.)
%
% Last ID introduced: 12
% Date of introduction: Feb 11, 2019; 22:08:34 (UTC)
%
% Otherwise you could maintain a list of IDs for looking up whether
% an ID you intend to introduce already exists:
%
%   \IDpar   | currently in capter/section
% -----------------------------------------
%    1       |  Nice chapter 
%    2       |  Nice section
%    3       |  Nice subsection
%    4       |  Nice subsubsection
%    5       |  Nice paragraph
%    5a      |  - existed in some previous relase(s) of the document/meanwhile removed. - 
%    6       |  Nice subparagraph
%    7       |  Nice subparagraph
%    8       |  Nice other section
%    9       |  Nice other subsection  
%   10       |  Nice other subsubsection
%   11       |  Nice other paragraph
%   12       |  Nice other subparagraph 
% 
% (I suggest keeping track of removed IDs also for ensuring that with
%  later versions of the document, where probably specifications got
%  removed, you don't erroneously -eh- "recycle" old removed
%  specification-IDs ...)

\begin{document}
%\tableofcontents
\chapter{Nice chapter}
\IDpar{1} Test text. Test text. Test text.
\section{Nice section}
\IDpar{2} Test text. Test text. Test text.
\subsection{Nice subsection}
\IDpar{3} Test text. Test text. Test text.
\subsubsection{Nice subsubsection}
\IDpar{4} Test text. Test text. Test text.
\paragraph{Nice paragraph}
\IDpar{5} Test text. Test text. Test text.
\subparagraph{Nice subparagraph}
\IDpar{6} Test text. Test text. Test text.\\
\verb|\ReferIDpar{7}|: \ReferIDpar{7}\\
\verb|\HyperReferIDpar{7}|: \HyperReferIDpar{7}\\
\verb|\ReferIDpar{8}|: \ReferIDpar{8}\\
\verb|\HyperReferIDpar{8}|: \HyperReferIDpar{8}\\
\verb|\ReferIDpar{9}|: \ReferIDpar{9}\\
\verb|\HyperReferIDpar{9}|: \HyperReferIDpar{9}\\
\verb|\ReferIDpar{10}|: \ReferIDpar{10}\\
\verb|\HyperReferIDpar{10}|: \HyperReferIDpar{10}\\
\verb|\ReferIDpar{11}|: \ReferIDpar{11}\\
\verb|\HyperReferIDpar{11}|: \HyperReferIDpar{11}\\
\verb|\ReferIDpar{12}|: \ReferIDpar{12}\\
\verb|\HyperReferIDpar{12}|: \HyperReferIDpar{12}\\
\IDpar{7} Test text. Test text. Test text.
\section{Nice other Section}
\IDpar{8} Test text. Test text. Test text.
\subsection{Nice other subsection}
\IDpar{9} Test text. Test text. Test text.
\subsubsection{Nice other subsubsection}
\IDpar{10} Test text. Test text. Test text.
\paragraph{Nice other paragraph}
\IDpar{11} Test text. Test text. Test text.
\subparagraph{Nice other subparagraph}
\IDpar{12} Test text. Test text. Test text.
\verb|\ReferIDpar{1}|: \ReferIDpar{1}\\
\verb|\HyperReferIDpar{1}|: \HyperReferIDpar{1}\\
\verb|\ReferIDpar{2}|: \ReferIDpar{2}\\
\verb|\HyperReferIDpar{2}|: \HyperReferIDpar{2}\\
\verb|\ReferIDpar{3}|: \ReferIDpar{3}\\
\verb|\HyperReferIDpar{3}|: \HyperReferIDpar{3}\\
\verb|\ReferIDpar{4}|: \ReferIDpar{4}\\
\verb|\HyperReferIDpar{4}|: \HyperReferIDpar{4}\\
\verb|\ReferIDpar{5}|: \ReferIDpar{5}\\
\verb|\HyperReferIDpar{5}|: \HyperReferIDpar{5}\\
\verb|\ReferIDpar{6}|: \ReferIDpar{6}\\
\verb|\HyperReferIDpar{6}|: \HyperReferIDpar{6}\\

\end{document}

enter image description here enter image description here

  • +1: I will have a close look at it at the weekend. Thanks! – Dr. Manuel Kuehner Feb 12 at 20:50
  • A lot of good input - thanks. The zref package seems quite useful. – Dr. Manuel Kuehner Feb 17 at 15:29

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.