TransWikia.com

Cross-reference with `xr` package and final PDF combination?

TeX - LaTeX Asked on September 3, 2021

So I have been using cross-references so far in Overleaf using this idea from StackExchange, which was adapted in Overleaf itself here. My question is, when I am finally combining main.tex and SI.tex in a single PDF file, how does that work? Or is it better to use the subfiles package?

I need a way in which to put these files in a single PDF and still have the cross-references work. Externally combining them will of course result in reference jump fail.

One Answer

What exactly do you mean when talking about combining two .tex-files (i.e. TeX source codes for two documents) into a single .pdf-file? What workflow do you have in mind?
I ask because source-code and resulting .pdf-file are different things.

Be that as it may.

In case overleaf can also produce .dvi-files instead of .pdf-files and you can run the programs dviconcat and dvipdfm or dvipdfmx, concatenating documents and creating a .pdf-file might be feasible.

One problem one might encounter when concatenating files are the names of destinations for hyperlinks:

When creating all .pdf-files by means of LaTeX, using the hyperref-package, different .pdf-files may have named destinations of equal name. (The names of the destinations usually come from the names of LaTeX-counters and the values of these counters at the time of creating the destination in question.) Thus there is the need of taking steps for ensuring uniqueness of destination names for hyperlinks within that .pdf-file that comes into being as the result of concatenating.

As a means of ensuring uniqueness of destination-names, the hyperref-package nowadays has the HyperDestNameFilter-feature.

HyperDestNameFilter is explained in section 3.2 Options for destination names of the manual of the hyperref package.

Here is a quote from that section:

If the final PDF file is going to be merged with another file, then the destination names might clash, because both documents might contain chapter.1 or page.1. Also hyperref sets anchor with name Doc-Start at the begin of the document. This can be resolved by redefining HyperDestNameFilter. Package hyperref calls this macro each time, it uses a destination name. The macro must be expandable and expects the destination name as only argument. As example, the macro is redefined to add a prefix to all destination names:

renewcommand*{HyperDestNameFilter}[1]{jobname-#1}

In document docA the destination name chapter.2 becomes docA-chapter.2.

Another problem one might encounter when concatenating .pdf-files are cross-references between those files that get concatenated.

The only solution to this problem I found by now is not creating .pdf-files from the single .tex-documents but creating .dvi-files while having hyperref loaded with the dvipdfm- or dvipdfmx-driver-option.

Then you can concatenate the single .dvi-files, using the program dviconcat (dviconcat is part of many TeX distributions, e.g., texlive and MiKTeX), and afterwards convert the resulting .dvi-file to .pdf-file, using the dvipdfm-program or the dvipdfmx-program which also is part of many TeX distributions.

(I also tried the dvips-route but that did not work out.)

Instead of the xr-package you need to use the xr-hyper-package and when creating .dvi-files for concatenation you need to redefine XR@@dURL to take the HyperDestNameFilter-prefix into account and to disregard XR@URL (which holds the url of the external file) for those external documents that are to be concatenated with the current document.

In the examples below

  • all documents to be concatenated must use a HyperDestNameFilter-prefix.
  • no two documents may have the same HyperDestNameFilter-prefix.
  • it is assumed that all files that are to be concatenated use different HyperDestNameFilter-prefixes which have in common that they all contain the phrase MyDocument while no destination-name itself may contain that phrase.
    Thus the presence/absence of the phrase MyDocument within the name of a destination is taken as an indicator by the macro HyperDestNameFilter for deciding whether a HyperDestNameFilter-prefix needs to be attached or not:
  • HyperDestNameFilter is (re)defined to attach a prefix only in case the name of the destination neither contains the phrase MyDocument nor contains the token empty.
  • additional infrastructure is provided for xr-hyper's command externaldocument:
    1. The command SetNextExternalFilesHyperDestNameFilterPrefix{...} is to be used for specifying the HyperDestNameFilter-prefix that was in use when creating the external document in question. (In case no HyperDestNameFilter-prefix was in use, you can specify SetNextExternalFilesHyperDestNameFilterPrefix{empty}.)
    2. The commands UseURL and DoNotUseURL. These commands are to be used for specifying whether externaldocument shall/shall not take URLs to .pdf-files containing external documents into account. (In case the URL deviates from externaldocument's first non-optional argument + .pdf/filename-extension, the URL can be specified in externaldocument's last optional argument.)
      URLs shall not be taken into account with external documents that are to be concatenated with the current document.
      URLs shall be taken into account with external documents that are not to be concatenated with the current document. (As URL specify the URL of the .pdf-file which contains the external document in question.)
  • XR@@dURL is redefined
    • to be capable of disregarding the url where the .pdf-file containing the external document in question can be found:
      Urls are disregarded in case the externaldocument-command in question is preceded by DoNotUseURL.
      Urls are not disregarded in case the externaldocument-command in question is preceded by UseURL.
    • to attach to the argument #4 (that argument denotes the name of the named destination connected to the external referencing-label in question) the HyperDestNameFilter-prefix which was used with the external document in question.
  • each externaldocument-command for importing referencing-data of an external document that is to be concatenated with the current document must go along with a command SetNextExternalFilesHyperDestNameFilterPrefix{MyDocument...} and with a command DoNotUseURL.
  • each externaldocument-command for importing referencing-data of an external document that is not to be concatenated with the current document must go along with a command SetNextExternalFilesHyperDestNameFilterPrefix{...} for providing information about the HyperDestNameFilter-prefix that was in use when creating the external document in question and with a command UseURL. In case a HyperDestNameFilter-Prefix was not in use when creating such a file, you can specify SetNextExternalFilesHyperDestNameFilterPrefix{empty}.

The examples below are to form a scenario with three documents.

The title of the first document is "My Document 1".
The file containing the source code of the first document is MyDocument1.tex.

The title of the second document is "My Document 2".
The file containing the source code of the second document is MyDocument2.tex.

The title of the third document is "My Document 3".
The file containing the source code of the third document is MyDocument3.tex.

The documents "My Document 1" and "My Document 2" will end up in the .pdf-file MyDocument1and2.pdf.

The document "My Document 3" will remain separate and end up in the .pdf-file MyDocument3.pdf.

Compiling/concatenating-instructions:

Have MyPatches.tex and MyDocument1.tex, MyDocument2.tex and MyDocument3.tex in the same directory.

Make that directory the active directory/current directory/whatsoever.

Alternatingly compile MyDocument1.tex, MyDocument2.tex, MyDocument3.tex using latex until both MyDocument1.dvi and MyDocument2.dvi and MyDocument3.dvi exist in that directory and MyDocument1.log and MyDocument2.log and MyDocument3.log neither contain requests to run latex again nor contain warnings about undefined references.

Call the program dviconcat for concatenating MyDocument1.dvi and MyDocument2.dvi into MyDocument1and2.dvi:
dviconcat -o MyDocument1and2.dvi MyDocument1.dvi MyDocument2.dvi

Call dvipdfmx for converting MyDocument1and2.dvi to MyDocument1and2.pdf:
dvipdfmx MyDocument1and2.dvi

Call dvipdfmx for converting MyDocument3.dvi to MyDocument3.pdf:
dvipdfmx MyDocument3.dvi

If everything worked out,

  • MyDocument1and2.pdf should consist of the content of "My Document 1" and "My Document 2". Cross-references within MyDocument1and2.pdf between "My Document 1" and "My Document 2" should cause navigation within MyDocument1and2.pdf. Cross-references within MyDocument1and2.pdf to "My Document 3" should cause opening and showing and scrolling within MyDocument3.pdf.
  • MyDocument3.pdf should consist of the content of "My Document 3". Cross-references within MyDocument3.pdf to "My Document 1" or "My Document 2" should cause loading and showing and scrolling within MyDocument1and2.pdf.

MyPatches.tex

%%====================================================================
%% Fixes for hyperref-drivers xetex and dvipdfm/dvipdfmx - apply them
%% _after_ loading the hyperref package:
%%====================================================================
begingroup
deftempa{hxetex}%
ifxHy@drivertempaexpandafter@secondoftwoelseexpandafter@firstofonefi
{%
  deftempa{hdvipdfm}%
  ifxHy@drivertempaexpandafter@firstofoneelseexpandafterendgroupexpandafter@gobblefi
}{%
  endgroup
  %%--------------------------------------------------------------------
  %% Fix hxetex's and hdvipdfm's  hyper@linkfile  by adding a group for
  %% preventing erroneous warnings
  %%
  %%  Package hyperref Warning: Invalid page number (0)
  %%  (hyperref)                for remote PDF file.
  %%  (hyperref)                Using page 1 on input line ...
  %%
  %% For more information see:
  %%  <https://github.com/latex3/hyperref/issues/107#issue-513025725>
  %%--------------------------------------------------------------------
  defhyper@linkfile#1#2#3{%
    begingroup % <--- begingroup inserted
    leavevmode
    Hy@BeginAnnot{%
      defHy@pstringF{#2}%
      Hy@CleanupFileHy@pstringF
      Hy@pstringdefHy@pstringFHy@pstringF
      Hy@pstringdefHy@pstringD{#3}%
      Hy@MakeRemoteAction %<-- Without the group the effects of Hy@MakeRemoteAction 
                           %    will be global, causing erroneous warnings.
      @pdfm@mark{%
        bann<<%
          /Type/Annot%
          /Subtype/Link%
          ifHy@pdfa /F 4fi
          Hy@setpdfborder
          Hy@setpdfhighlight
          ifx@filebordercolorrelax
          else
            /C[@filebordercolor]%
          fi
          /A<<%
            /S/GoToR%
            /F(Hy@pstringF)%
            /D%
            ifx#3%
              [Hy@href@page@pdfremotestartview]%
            else
              (Hy@pstringD)%
            fi
            Hy@SetNewWindow
            Hy@href@nextactionraw
          >>%
        >>%
      }%
      Hy@colorlink@filecolor
    }%
    #1Hy@xspace@end
    Hy@EndAnnot
    endgroup % <--- endgroup inserted
  }%
  %%--------------------------------------------------------------------
  %% Add special for making named destinations reachable from "outside":
  %% For more information see:
  %%  <https://tug.org/pipermail/dvipdfmx/2019-May/000003.html>
  %%--------------------------------------------------------------------
  special{dvipdfmx:config C 0x10}%
}%
%%=============================================================================
%% Additional infrastructure for xr-hyper's externaldocument so you can
%% specify 
%% - external files' HyperDestNameFilter-pefix
%% - whether URLs of external files shall be used or not be used.
%%   (They shall not be used when dvi-files get concatenated via dviconcat
%%    before converting to pdf.)
%%=============================================================================
%%-----------------------------------------------------------------------------
%% Fork whether argument contains the phrase "MyDocument"
%%.............................................................................
@ifdefinableUD@GobbleToMyDocument{longdefUD@GobbleToMyDocument#1MyDocument{}}%
newcommandUD@CheckWhetherNoMyDocument[1]{%
  expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToMyDocument#1MyDocument}%
}%
%%-----------------------------------------------------------------------------
%% Fork whether argument contains the token "empty"
%%.............................................................................
@ifdefinableUD@GobbleToEmpty{longdefUD@GobbleToEmpty#1empty{}}%
newcommandUD@CheckWhetherNoEmpty[1]{%
  expandafterUD@CheckWhetherNullexpandafter{UD@GobbleToEmpty#1empty}%
}%
newcommandUD@CheckWhetherNull[1]{%
  romannumeral0expandafter@secondoftwostring{expandafter
  @secondoftwoexpandafter{expandafter{string#1}expandafter
  @secondoftwostring}expandafter@firstoftwoexpandafter{expandafter
  @secondoftwostring}@firstoftwoexpandafter{} @secondoftwo}%
  {@firstoftwoexpandafter{} @firstoftwo}%
}%
%%--------------------------------------------------------------------
%% A place-holder for external files'  HyperDestNameFilter-pefix
%%.............................................................................
newcommandNextExternalFilesHyperDestNameFilterPrefix{}%
%%-----------------------------------------------------------------------------
%% Set external files'  HyperDestNameFilter-pefix
%%.............................................................................
newcommandSetNextExternalFilesHyperDestNameFilterPrefix[1]{%
 renewcommandNextExternalFilesHyperDestNameFilterPrefix{#1}%
}%
%%-----------------------------------------------------------------------------
%% Take into account URL of external file/
%% don't take into account URL of external file.
%%.............................................................................
newcommandUseURL{globalDontUseURLfalse}%
newcommandDoNotUseURL{globalDontUseURLtrue}%
newififDontUseURL
%%-----------------------------------------------------------------------------
%% Change XR@@dURL to take the HyperDestNameFilter-prefix of the external file
%% into account and to omit XR@URL
%%-----------------------------------------------------------------------------
defXR@@dURL#1#2#3#4#5{%
  {#1}{#2}%
  if!#4!%
  else
    {#3}{NextExternalFilesHyperDestNameFilterPrefix#4}%
    ifDontUseURL{}else{XR@URL}fi
  fi
}%

MyDocument1.tex

documentclass{article}

usepackage{xr-hyper}
usepackage[dvipdfmx]{hyperref}

makeatletter
input MyPatches.tex
%%-----------------------------------------------------------------------------
%% Change HyperDestNameFilter to add the prefix "MyDocument1-" in case the name
%% of the destination doses not already contain the phrase "MyDocument" or the 
%% token "empty":
%%
%% !!!! The HyperDestNameFilter-prefix varies from file to file/
%% !!!! from document to document
%%.............................................................................
renewcommand*{HyperDestNameFilter}[1]{%
  UD@CheckWhetherNoEmpty{#1}{UD@CheckWhetherNoMyDocument{#1}{MyDocument1-}{}}{}#1%
}%
%%-----------------------------------------------------------------------------
makeatother

DoNotUseURL
SetNextExternalFilesHyperDestNameFilterPrefix{MyDocument2-}%
externaldocument[MyDocument2-]{MyDocument2}[MyDocument1and2.pdf]%

UseURL
SetNextExternalFilesHyperDestNameFilterPrefix{MyDocument3-}%
externaldocument[MyDocument3-]{MyDocument3}%


begin{document}

title{My Document 1}
author{Me, Myself and I}    
maketitle
newpage

section{First section of My Document 1}
label{LabelInMyDocument1}

noindent
The source code of textbf{My Document 1} is contained in textbf{MyDocument1.tex.}
The source code of section textbf{First section of My Document 1} contains
the referencing-label textbf{LabelInMyDocument1}.
The target-file of textbf{My Document 1} will be textbf{MyDocument1and2.pdf}.

bigskipnoindent
The source code of textbf{My Document 2} is contained in textbf{MyDocument2.tex.}
The source code of section textbf{First section of My Document 2} contains
the referencing-label textbf{LabelInMyDocument2}.
The target-file of textbf{My Document 2} will be textbf{MyDocument1and2.pdf}.

bigskipnoindent
The source code of textbf{My Document 3} is contained in textbf{MyDocument3.tex.}
The source code of section textbf{First section of My Document 3} contains
the referencing-label textbf{LabelInMyDocument3}.
The target-file of textbf{My Document 3} will be textbf{MyDocument3.pdf}.


bigskipnoindent
textbf{Referencing}

bigskipnoindent
verb|ref{LabelInMyDocument1}| yields:ref{LabelInMyDocument1}
verb|pageref{LabelInMyDocument1}| yields:pageref{LabelInMyDocument1}
verb|ref{MyDocument2-LabelInMyDocument2}| yields:ref{MyDocument2-LabelInMyDocument2}
verb|pageref{MyDocument2-LabelInMyDocument2}| yields:pageref{MyDocument2-LabelInMyDocument2}
verb|ref{MyDocument3-LabelInMyDocument3}| yields:ref{MyDocument3-LabelInMyDocument3}
verb|pageref{MyDocument3-LabelInMyDocument3}| yields:pageref{MyDocument3-LabelInMyDocument3}

end{document}

MyDocument2.tex

documentclass{article}

usepackage{xr-hyper}
usepackage[dvipdfmx]{hyperref}

makeatletter
input MyPatches.tex
%%-----------------------------------------------------------------------------
%% Change HyperDestNameFilter to add the prefix "MyDocument2-" in case the name
%% of the destination doses not already contain the phrase "MyDocument" or the 
%% token "empty":
%%
%% !!!! The HyperDestNameFilter-prefix varies from file to file/
%% !!!! from document to document
%%.............................................................................
renewcommand*{HyperDestNameFilter}[1]{%
  UD@CheckWhetherNoEmpty{#1}{UD@CheckWhetherNoMyDocument{#1}{MyDocument2-}{}}{}#1%
}%
%%-----------------------------------------------------------------------------
makeatother

DoNotUseURL
SetNextExternalFilesHyperDestNameFilterPrefix{MyDocument1-}%
externaldocument[MyDocument1-]{MyDocument1}[MyDocument1and2.pdf]%

UseURL
SetNextExternalFilesHyperDestNameFilterPrefix{MyDocument3-}%
externaldocument[MyDocument3-]{MyDocument3}%


begin{document}

title{My Document 2}
author{Me, Myself and I}    
maketitle
newpage

section{First section of My Document 2}
label{LabelInMyDocument2}

noindent
The source code of textbf{My Document 1} is contained in textbf{MyDocument1.tex.}
The source code of section textbf{First section of My Document 1} contains
the referencing-label textbf{LabelInMyDocument1}.
The target-file of textbf{My Document 1} will be textbf{MyDocument1and2.pdf}.

bigskipnoindent
The source code of textbf{My Document 2} is contained in textbf{MyDocument2.tex.}
The source code of section textbf{First section of My Document 2} contains
the referencing-label textbf{LabelInMyDocument2}.
The target-file of textbf{My Document 2} will be textbf{MyDocument1and2.pdf}.

bigskipnoindent
The source code of textbf{My Document 3} is contained in textbf{MyDocument3.tex.}
The source code of section textbf{First section of My Document 3} contains
the referencing-label textbf{LabelInMyDocument3}.
The target-file of textbf{My Document 3} will be textbf{MyDocument3.pdf}.


bigskipnoindent
textbf{Referencing}

bigskipnoindent
verb|ref{MyDocument1-LabelInMyDocument1}| yields:ref{MyDocument1-LabelInMyDocument1}
verb|pageref{MyDocument1-LabelInMyDocument1}| yields:pageref{MyDocument1-LabelInMyDocument1}
verb|ref{LabelInMyDocument2}| yields:ref{LabelInMyDocument2}
verb|pageref{LabelInMyDocument2}| yields:pageref{LabelInMyDocument2}
verb|ref{MyDocument3-LabelInMyDocument3}| yields:ref{MyDocument3-LabelInMyDocument3}
verb|pageref{MyDocument3-LabelInMyDocument3}| yields:pageref{MyDocument3-LabelInMyDocument3}

end{document}

MyDocument3.tex

documentclass{article}

usepackage{xr-hyper}
usepackage[dvipdfmx]{hyperref}

makeatletter
input MyPatches.tex
%%-----------------------------------------------------------------------------
%% Change HyperDestNameFilter to add the prefix "MyDocument3-" in case the name
%% of the destination doses not already contain the phrase "MyDocument" or the 
%% token "empty":
%%
%% !!!! The HyperDestNameFilter-prefix varies from file to file/
%% !!!! from document to document
%%.............................................................................
renewcommand*{HyperDestNameFilter}[1]{%
  UD@CheckWhetherNoEmpty{#1}{UD@CheckWhetherNoMyDocument{#1}{MyDocument3-}{}}{}#1%
}%
%%-----------------------------------------------------------------------------
makeatother

UseURL
SetNextExternalFilesHyperDestNameFilterPrefix{MyDocument1-}%
externaldocument[MyDocument1-]{MyDocument1}[MyDocument1and2.pdf]%

UseURL
SetNextExternalFilesHyperDestNameFilterPrefix{MyDocument2-}%
externaldocument[MyDocument2-]{MyDocument2}[MyDocument1and2.pdf]%


begin{document}

title{My Document 3}
author{Me, Myself and I}    
maketitle
newpage

section{First section of My Document 3}
label{LabelInMyDocument3}

noindent
The source code of textbf{My Document 1} is contained in textbf{MyDocument1.tex.}
The source code of section textbf{First section of My Document 1} contains
the referencing-label textbf{LabelInMyDocument1}.
The target-file of textbf{My Document 1} will be textbf{MyDocument1and2.pdf}.

bigskipnoindent
The source code of textbf{My Document 2} is contained in textbf{MyDocument2.tex.}
The source code of section textbf{First section of My Document 2} contains
the referencing-label textbf{LabelInMyDocument2}.
The target-file of textbf{My Document 2} will be textbf{MyDocument1and2.pdf}.

bigskipnoindent
The source code of textbf{My Document 3} is contained in textbf{MyDocument3.tex.}
The source code of section textbf{First section of My Document 3} contains
the referencing-label textbf{LabelInMyDocument3}.
The target-file of textbf{My Document 3} will be textbf{MyDocument3.pdf}.


bigskipnoindent
textbf{Referencing}

bigskipnoindent
verb|ref{MyDocument1-LabelInMyDocument1}| yields:ref{MyDocument1-LabelInMyDocument1}
verb|pageref{MyDocument1-LabelInMyDocument1}| yields:pageref{MyDocument1-LabelInMyDocument1}
verb|ref{MyDocument2-LabelInMyDocument2}| yields:ref{MyDocument2-LabelInMyDocument2}
verb|pageref{MyDocument2-LabelInMyDocument2}| yields:pageref{MyDocument2-LabelInMyDocument2}
verb|ref{LabelInMyDocument3}| yields:ref{LabelInMyDocument3}
verb|pageref{LabelInMyDocument3}| yields:pageref{LabelInMyDocument3}

end{document}

Answered by Ulrich Diez on September 3, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP