0

I maintain a set of open calculus texts for our calculus sequence, which has four courses (Calculus I-IV). Each course has its own corresponding open text. Occasionally the text for a later course will need to refer back to a result in one of the earlier texts.

As usual, I accomplish this using the xr package, loading the previous texts as external documents, and everything works fine, except for the following issue:

Because an instructor for a prerequisite course in the sequence might not get through all the material they need to, I repeat some sections. For example the first chapter in Calculus III might contain several sections from the last chapter of Calculus II.

This results in a proliferation of multiply-defined references from the repeated sections when using xr to cross-reference the earlier texts.

Is there any way to configure the xr package to ignore references from the repeated sections?

Example: overall project has BookA.tex and BookB.tex in the top level of the directory tree. There are subdirectories such as /text (containing the .tex files for each section), /figures, etc.

BookA has two sections, included using

\input{text/Section1}

\input{text/Section2}

BookB is a continuation of BookA, but due to overlap between courses that use BookA and BookB, it also includes Section2. So BookB has

\usepackage{xr}

\externaldocument{BookA}

in the preamble, and in the document, has

\input{text/Section2}

\input{text/Section3}

Since Section2 appears in both BookA and BookB, using BookA for cross referencing creates multiply-defined references.

I want a way to reference BookA (because Section3 has references to Section1, say) but omit the sections that also occur in BookB.

7
  • 2
    do you mean you already have duplicate label references in the original document, before you consider xr to it? Is "don't do that2 an acceptable answer? :-) May 28, 2018 at 16:55
  • 1
    if you mean they are only repeated after you include them then use the optional argument \externaldocument[cii-]{cii.tex}\externaldocument[ciii-]{ciii.tex} will give you \ref{cii-foo} and \ref{ciii-foo} even if both files have \label{foo} May 28, 2018 at 17:12
  • The issue is that there would be a single file for a section (e.g. 07_Area_Between_Curves.tex) and two master documents that both include that file. If document B uses document A for cross-referencing, and both A and B use that section, then there will be multiply-defined labels, even if the optional argument is used. May 28, 2018 at 17:25
  • The best option I have is to maintain two versions of any repeated section, and modify the labels in the second version to avoid conflicts. But this is not a very elegant solution. May 28, 2018 at 17:26
  • 1
    I can't see why you get duplicate references, please add an example to the question so it reproduces the problem, it should only take three very short (but complete) documents (if I understand your description, which I clearly don't:-) May 28, 2018 at 17:30

1 Answer 1

1

You could use the optional argument to \externaldocument, it will prefix the imported labels with a string to make them unique.

\externaldocument[booka-]{BookA}

would make all imported labels have the name booka-<label>. This of course requires you to remember whether or not a reference was in this file or in an external file.


The following slightly redefines the core macro of xr and xr-hyper in a way that a label is only created if it is not already present in the current document (a label is present if r@<label> is defined). This requires that \externaldocument be called at a time where the main .aux file has been read, luckily \AtBeginDocument works.

Save the following file as bookb.tex. The file uses filecontents to create all other .tex files. Warning: filecontents overwrites existing files without warning, please run the code only in an empty test directory.

Compile it as follows

pdflatex bookb
pdflatex booka
pdflatex booka
pdflatex bookb
\RequirePackage{filecontents}
\begin{filecontents}{section1.tex}
\section{Section 1}\label{sec:1}
\kant[1-4]
\end{filecontents}
\begin{filecontents}{section2.tex}
\section{Section 2}\label{sec:2}
\kant[5-7]
\end{filecontents}
\begin{filecontents}{section3.tex}
\section{Section 3}\label{sec:3}
\kant[8-9]
\end{filecontents}
\begin{filecontents}{booka.tex}
\documentclass[british]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage{kantlipsum}
\usepackage{hyperref}

\begin{document}
\input{section1}
\input{section2}
\end{document}
\end{filecontents}

\documentclass[british]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage{etoolbox}
\usepackage{kantlipsum}

\usepackage{xr-hyper}
\usepackage{hyperref}

\makeatletter
\@ifpackageloaded{xr}
  {\def\sf@safe@newlabel#1{%
     \ifcsundef{r@#1}
       {\newlabel{#1}}
       {\PackageInfo{xr}{label `#1' already defined, skipping}%
        \@gobble}}
   \long\def\XR@test#1#2#3#4\XR@{%
     \ifx#1\newlabel
       \sf@safe@newlabel{\XR@prefix#2}{#3}%
     \else\ifx#1\@input
        \edef\XR@list{\XR@list#2\relax}%
     \fi\fi
     \ifeof\@inputcheck\expandafter\XR@aux
     \else\expandafter\XR@read\fi}}
  {}%
\@ifpackageloaded{xr-hyper}
  {\long\def\XR@test#1#2#3#4\XR@{%
     \ifx#1\newlabel
       \ifcsundef{r@#2}
         {\expandafter\protected@xdef\csname r@\XR@prefix#2\endcsname
            {\XR@addURL{#3}}}
         {\PackageInfo{xr-hyper}{label `#2' already defined, skipping}}%
     \else\ifx#1\@input
       \edef\XR@list{\XR@list\filename@area#2\relax}%
    \fi\fi
    \ifeof\@inputcheck\expandafter\XR@aux
    \else\expandafter\XR@read\fi}}
  {}
\makeatother

\AtBeginDocument{\externaldocument{booka}}

\begin{document} 
\ref{sec:1} (in old doc) 

\ref{sec:2} (in both docs, but numbering goes out to this one)

\ref{sec:3} (only in this doc)
\input{section2}
\input{section3}
\end{document}
5
  • Thanks. I'll try to digest this code and then give it a try. The reason I didn't consider the optional argument for the external document is this: Let's say I have a section that appears in two volumes (e.g. Taylor polynomials). In that section there is a labelled theorem; say \label{thm:taylor}. Within that same section I'm likely to have references to that label. It seems like there would be conflicts with the referencing, but I could be wrong. May 31, 2018 at 16:20
  • @SeanFitzpatrick My complicated seconds solution should actually detect these problems and only link to the label in this volume.
    – moewe
    May 31, 2018 at 16:35
  • Yes, I think it's necessary. At first I thought I could get away with the optional argument in \externaldocument. But here's the example where it fails: Area Between Curves is a section that appears at the end of Calculus I, and is repeated in the applications chapter of Calculus II. There is a reference there to the Fundamental Theorem of Calculus (which is in the Calculus I book). If I use \ref{thm:FTC} the reference works in the Calculus I book, but not Calculus II. If I use \ref{I-thm:FTC} it's the other way around. May 31, 2018 at 16:59
  • @SeanFitzpatrick Have you tried with my second example (modified default behaviour without optional argument)? What you describe should work automatically there. If it does not work, please consider asking a new question with a concise MWE.
    – moewe
    May 31, 2018 at 18:17
  • I have not tried it yet. But yes, your second solution should work. The following alternative workaround also occurred to me: In BookA preamble: \newboolean{BookA} \setboolean{BookA}{true} In BookB, same, but set to false. Then for conflicting references in a section, do: \ifthenelse{\boolean{BookA}}{\ref{thm:FTC}}{\ref{I-thm:FTC}} May 31, 2018 at 19:51

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.