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? :-) Commented 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} Commented 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. Commented 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. Commented 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:-) Commented 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. Commented 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
    Commented 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. Commented 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
    Commented 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}} Commented May 31, 2018 at 19:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .