5

Following the post How to enable smart references when using xr-hyper package for producing multi-volume book? I tried to elaborate required solution using zref package as was suggested by @Andrew Swann. Unfortunatly, I ran into another problem which seems to be a bug in zref. So I decided to post the problem description here. I am not sure if is it a proper place for posting such a question but Heiko Oberdiek, the author of zref did not answer to my email.

As suggested by @Andrew Swann, I tried to provide cross-references between 2 volumes of a multivolume book using Heiko's package zref. I addition, I introduced a property chaptervalue in order to provide smart references, which hide a chapter part of an equation number in case when the equation goes from the same chapter where it is referred from. Here is MWE. It contains 3 files.

Common code is saved in test-zref-common.tex:

% Load packages abd declare external docs.
\usepackage[user,xr]{zref}
\ifnum\Volume=1
    % comment the line below to avoid errors
    \zexternaldocument{test-zref-2}% <============
    \makeatletter
        \zref@ifpropundefined{volume}{
            \zref@newprop{volume}{\Volume}
            \zref@newprop{chaptervalue}{\the\value{chapter}}
        }{}
        \zref@localaddprops{main}{volume,chaptervalue}
    \makeatother
\else
    \zexternaldocument{test-zref-1}
    \makeatletter
        \zref@ifpropundefined{volume}{
            \zref@newprop{volume}{\Volume}
            \zref@newprop{chaptervalue}{\the\value{chapter}}
        }{}
        \zref@localaddprops{main}{volume,chaptervalue}
    \makeatother
\fi

% Reset default equation numbering
\usepackage{amsmath}
\numberwithin{equation}{chapter}
\renewcommand{\theequation}{\arabic{equation}}

% Define \sref and \seqref macros for smart cross-references of equations
\makeatletter
\newcommand\ifcurrentchapter[3]{%
  \def\temp@a{\number\value{chapter}}%
  \def\temp@b{\zref@extract{#1}{chaptervalue}}%
  \if\temp@a\temp@b%
    #2%
  \else%
    #3%
  \fi%
}
\newcommand{\sref}[1]{\hbox{\ifcurrentchapter{#1}{}{\zref[chaptervalue]{#1}.}\zref{#1}}}
\newcommand{\seqref}[1]{(\sref{#1})}
\makeatother

% Define a macro to print test text
\newcommand{\testtext}{
    Compare \number\value{chapter} with \zref[chaptervalue]{ch:1}. Equal: \ifcurrentchapter{ch:1}{Yes}{No}
    \par\noindent
    Compare \number\value{chapter} with \zref[chaptervalue]{ch:2}. Equal: \ifcurrentchapter{ch:2}{Yes}{No}
    \par\noindent
    Compare \number\value{chapter} with \zref[chaptervalue]{ch:17}. Equal: \ifcurrentchapter{ch:17}{Yes}{No}
    \par\noindent
    Compare \number\value{chapter} with \zref[chaptervalue]{ch:18}. Equal: \ifcurrentchapter{ch:18}{Yes}{No}
}

The common file is read in by Volume 1 (test-zref-1.tex)

\documentclass[oneside]{book}
\newcommand{\Volume}{1}
\input{test-zref-common}

\begin{document}
\chapter{1 in Volume 1}
\label{ch:1}\zlabel{ch:1}

\testtext

\begin{equation}
  eq1
  \label{1.1}\zlabel{1.1}
\end{equation}
\begin{equation}
  eq2
  \label{1.2}\zlabel{1.2}
\end{equation}

\seqref{1.1}, \seqref{1.2}; \seqref{2.1}, \seqref{2.2}.
\seqref{17.1}, \seqref{17.2}; \seqref{18.1}, \seqref{18.2}.

\chapter{2  in Volume 2}
\label{ch:2}\zlabel{ch:2}

\testtext

\begin{equation}
  eq3
  \label{2.1}\zlabel{2.1}
\end{equation}

\begin{equation}
  eq4
  \label{2.2}\zlabel{2.2}
\end{equation}

\seqref{1.1}, \seqref{1.2}; \seqref{2.1}, \seqref{2.2}.
\seqref{17.1}, \seqref{17.2}; \seqref{18.1}, \seqref{18.2}.
\end{document} 

and by Volume 2 (test-zref-1.tex):

%\documentclass{scrbook}
\documentclass[oneside]{book}
\newcommand{\Volume}{2}
\setcounter{chapter}{16}
\input{test-zref-common}

\begin{document}

\chapter{1 in Volume 2}
\label{ch:17}\zlabel{ch:17}

\testtext

\begin{equation}
  eq1
  \label{17.1}\zlabel{17.1}
\end{equation}

\begin{equation}
  eq2
  \label{17.2}\zlabel{17.2}
\end{equation}

\seqref{1.1}, \seqref{1.2}; \seqref{2.1}, \seqref{2.2}.
\seqref{17.1}, \seqref{17.2}; \seqref{18.1}, \seqref{18.2}.

\chapter{2  in Volume 2}
\label{ch:18}\zlabel{ch:18}

\testtext

\begin{equation}
  eq3
  \label{18.1}\zlabel{18.1}
\end{equation}

\begin{equation}
  eq4
  \label{18.2}\zlabel{18.2}
\end{equation}

\seqref{1.1}, \seqref{1.2}; \seqref{2.1}, \seqref{2.2}.
\seqref{17.1}, \seqref{17.2}; \seqref{18.1}, \seqref{18.2}.
\end{document} 

It works fine if I refer to Volume #1 from Volume #2 (ie. when the line

\zexternaldocument{test-zref-2}

is removed from test-zref-common.tex). However it fails when I am trying to refer to both volumes, to Volume #1 from Volume #2 and to Volume #2 from Volume #1. zref complains that the chaptervalue property has been already defined. Attached files demonstrate this problem.

Is a bug in zref or a bug in MWE?

5

The bugs are in your code, all in the common file. Firstly, you should define the properties before specifying the external documents. Secondly, you need to use \ifnum not \if in your tests. Here is the revised common file:

% Load packages abd declare external docs.
\usepackage[user,xr]{zref}
\makeatletter
\zref@newprop{volume}{\Volume}
\zref@newprop{chaptervalue}{\the\value{chapter}}
\zref@localaddprops{main}{volume,chaptervalue}
\makeatother
\ifnum\Volume=1
    \zexternaldocument{test-zref-2}% <============
\else
    \zexternaldocument{test-zref-1}
\fi

% Reset default equation numbering
\usepackage{amsmath}
\numberwithin{equation}{chapter}
\renewcommand{\theequation}{\arabic{equation}}

% Define \sref and \seqref macros for smart cross-references of equations
\makeatletter
\newcommand\ifcurrentchapter[3]{%
  \def\temp@a{\number\value{chapter}}%
  \def\temp@b{\zref@extract{#1}{chaptervalue}}%
  \if\relax\temp@a\else\if\relax\temp@b\else
  \ifnum\temp@a=\temp@b%
    #2%
  \else%
    #3%
  \fi%
  \fi\fi
}
\newcommand{\sref}[1]{\hbox{\ifcurrentchapter{#1}{}{\zref[chaptervalue]{#1}.}\zref{#1}}}
\newcommand{\seqref}[1]{(\sref{#1})}
\makeatother

% Define a macro to print test text
\newcommand{\testtext}{
    Compare \number\value{chapter} with \zref[chaptervalue]{ch:1}. Equal: \ifcurrentchapter{ch:1}{Yes}{No}
    \par\noindent
    Compare \number\value{chapter} with \zref[chaptervalue]{ch:2}. Equal: \ifcurrentchapter{ch:2}{Yes}{No}
    \par\noindent
    Compare \number\value{chapter} with \zref[chaptervalue]{ch:17}. Equal: \ifcurrentchapter{ch:17}{Yes}{No}
    \par\noindent
    Compare \number\value{chapter} with \zref[chaptervalue]{ch:18}. Equal: \ifcurrentchapter{ch:18}{Yes}{No}
}

This produces the following page at Chatper 17 in the second document:

Sample output

  • This works but isues an error at first compilation (! Missing number, treated as zero.) So it will hardly be impossble to compile a big document if the number of errors exceeds 100. That's why I used \if\temp@a=\temp@b instead of \ifnum\temp@a=\temp@b. Can you suggest a better solution? – Igor Kotelnikov Jan 6 '14 at 7:25
  • @IgorKotelnikov Thanks for pointing that out; extra tests now added before the \ifnum. Note \if1717 compares 1 with 7, which is not want you want. If you are prepared to load etoolbox, then you could just write \ifcurrentchapter as \ifdefequal{\value{chapter}}{\zref@extract{#1}{chaptervalue}}{#2}{#3} – Andrew Swann Jan 6 '14 at 10:00
  • With this added check (\if\temp@a\relax\else\if\temp@b\relax\else \ifnum\temp@a=\temp@b%) my XeTeX compiler outputs unexpected Greek capital omega at first run, so I finally choose solution described in 2nd answer. – Igor Kotelnikov Jan 7 '14 at 11:56
  • @IgorKotelnikov Sorry, should have had \if\relex\temp@b... not \if\temp@b\relax.... In any case, there is \zref@extractdefault and \zref@def@extractdefault one could have used. – Andrew Swann Jan 7 '14 at 13:18
1

Expanding the answer given by @Andrew Swann, I updated his code in the common block to avoid generating errors at the first run of LaTeX over source files when the value of the labels are not known yet. A key point here is that the chaptervalue property should be defined with a default value. I take it equal to -1. Then, \ifcurrentchapter macro could be modified to check if \temp@b is negative as it is at the first run. In addition, I added hyperref and xr-hyper packages in order to allow for hyper-references between the volumes of the book.

Here is a final version of test-zref-common.tex:

% Load packages and declare external docs.
\usepackage{xr-hyper}%                     <== load xr-hyper package
\usepackage[unicode,colorlinks]{hyperref}% <== load hyperref package
\usepackage[user,xr]{zref}
\makeatletter
\zref@newprop{volume}{\Volume}
\zref@newprop{chaptervalue}[-1]{\the\value{chapter}}% <= note the default value [-1]
\zref@localaddprops{main}{volume,chaptervalue}
\makeatother
\ifnum\Volume=1
    \externaldocument{test-zref-2}%  <== declare external doc for xr-hyper
    \zexternaldocument{test-zref-2}% <== declare external doc for zref
\else
    \externaldocument{test-zref-1}
    \zexternaldocument{test-zref-1}
\fi

% Reset default equation numbering
\usepackage{amsmath}
\numberwithin{equation}{chapter}
\renewcommand{\theequation}{\arabic{equation}}

% Define \sref and \seqref macros for smart cross-references of equations
\makeatletter
\newcommand\ifcurrentchapter[3]{%
  \def\temp@a{\number\value{chapter}}%
  \def\temp@b{\zref@extract{#1}{chaptervalue}}%
  \ifnum\temp@a=\temp@b%
    #2%
  \else%
    \ifnum\temp@b<0
      #2%
    \else
      #3%
    \fi%
  \fi%
}
%\newcommand{\sref}[1]{\hbox{\ifcurrentchapter{#1}{}{\zref[chaptervalue]{#1}.}\zref{#1}}}
% note \hyperref in the definition of \sref
\newcommand{\sref}[1]{\hyperref[#1]{\hbox{\ifcurrentchapter{#1}{}{\zref[chaptervalue]{#1}.}\zref{#1}}}}
\newcommand{\seqref}[1]{(\sref{#1})}
%\newcommand{\seqref}[1]{(\hyperref[#1]{\hbox{\sref{#1}}})}
\makeatother

% Define a macro to print test text
\newcommand{\testtext}{
    Chapter \sref{ch:1}, Chapter \sref{ch:2},
    Chapter \sref{ch:17}, Chapter \sref{ch:18}.
    \par\noindent
    Compare \number\value{chapter} with \zref[chaptervalue]{ch:1}. Equal: \ifcurrentchapter{ch:1}{Yes}{No}
    \par\noindent
    Compare \number\value{chapter} with \zref[chaptervalue]{ch:2}. Equal: \ifcurrentchapter{ch:2}{Yes}{No}
    \par\noindent
    Compare \number\value{chapter} with \zref[chaptervalue]{ch:17}. Equal: \ifcurrentchapter{ch:17}{Yes}{No}
    \par\noindent
    Compare \number\value{chapter} with \zref[chaptervalue]{ch:18}. Equal: \ifcurrentchapter{ch:18}{Yes}{No}
    \par
    \seqref{1.1}, \seqref{1.2}; \seqref{2.1}, \seqref{2.2}.
    \par
    \seqref{17.1}, \seqref{17.2}; \seqref{18.1}, \seqref{18.2}.
}

\endinput

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.