# Convert string to file name and use in \href

I have a bunch of individual .tex files and want to be able to click on a link in one PDF file and have the appropriate PDF file open. These are small files, so don't really need to index into them, just have them open.

The file name to open can (in most cases) be determined from the descriptive link text -- algorithm below. There will be a few cases where the file name can not be easily determined, so for that I want to also be able to manually specify it. So, I define:

\NewDocumentCommand{\CrossReference}{O{\NoValue} m}


where

#1 = optional file name (determined from #2 if not provided)


I have the case where I manually specify the file name working in the MWE below. However, since the file names can easily be determined, I would like to not have to provide it. That is where \ConvertToFileNameWithPath is supposed to do its job.

## File Naming Algorithm:

If the file name is not specified, it is obtained form the given link text by:

1. Change all characters to lower case.
2. Replace any blanks with a dash.
3. Add the .pdf extension

## Notes:

1. For the MWE below to work (ie, to test that the links are click able), the file equation-of-circle.pdf must exist in the current directory.

2. Eventually, the macro \ConvertToFileNameWithPath will search for this file name in a particular list of directories -- will tackle that next. So that will be step 4 in the above algorithm.

3. I did look at the xr package and not sure it is appropriate for this case, mostly due to Note 2 (there may be multiple files with the same name).

## References/Failed Attempts:

• I attempted to adapt Joseph Wright's answer at Are there purely expandable variants of \MakeUppercase?, but was not successful. Also on the same question it mentions that \tl_expandable_lowercase:n is now available so that should certainly help. But not understanding expl3, I can't get much further than this.

• My start at this is based on Bruno Le Floch's answer to my question: Text being output when none should be. Not that I was able to get very far with this, but perhaps this might help others figure this out.

• I also attempted to use a sequence of \StrSubstitute{\Temp}{A}{A}[\Temp], \StrSubstitute{\Temp}{B}{b}[\Temp] to make the conversion, but this runs into expansion issues, and using \tl_expandable_lowercase:n should be easier.

## Code:

When the text above and below the \hrule is that same then this should be working: assuming of course you have equation-of-circle.pdf in the current directory, and can open it via lines 1 and 3. Currently I can only open it via line 1 where I have manually specified the file name:

\documentclass{article}
\usepackage{xparse}
\usepackage{xcolor}
\usepackage{hyperref}

%\ExplSyntaxOn -- am guessing that this will be needed...
\DeclareExpandableDocumentCommand{\ConvertToFileNameWithPath}{o m}{%
% This will eventually also locate a file in a given path
\IfNoValueTF{#1}{% file name not specified so need to figure it out
% ????????? What goes here ???????
./#2.pdf% Need to convert #2 to a file name. ????????
}{% We were given, the file name -- Even I can handle this case
./#1.pdf%
}%
}
%\ExplSyntaxOff

\NewDocumentCommand{\CrossReference}{O{\NoValue} m}{%
% #1 = optional file name (determined from #2 if not provided)
\edef\PdfFileName{\ConvertToFileNameWithPath[#1]{#2}}%
\IfFileExists{\PdfFileName}{%
\href{run:\PdfFileName}{#2}%
}{%
\fcolorbox{red}{yellow}{#2}%
\footnote{Unable to locate \PdfFileName}%
}%
}%

\begin{document}
Manual References: \CrossReference[equation-of-circle]{Equation of Circle}%

Manual References: \CrossReference[non-existant-file]{Non Existant File}%

\medskip\hrule\medskip

Automatic References: \CrossReference{Equation of Circle}%

Automatic References: \CrossReference{Non Existant File}%
\end{document}

-
For the record (since you asked me to look on another thread), I agree with egreg and David that you don't need expandability. \tl_expandable_lowercase is a rather specialized function, which should in most cases not be needed. Also, it is very slow. Actually, thinking about it again, we may want to generalize it, I need to think. –  Bruno Le Floch Mar 17 '12 at 1:45

\documentclass{article}
\usepackage{xparse}
\usepackage{xcolor}
\usepackage{hyperref}

\ExplSyntaxOn
\NewDocumentCommand{\CrossReference}{ o m }
{
\IfNoValueTF{#1}
{ \grill_convert_name:n { #2 } }
{ \tl_set:Nn \l_grill_file_name_tl { #1 } }
}

\tl_new:N \l_grill_file_name_tl

\cs_new:Npn \grill_convert_name:n #1
{
\tl_to_lowercase:n { \tl_set:Nn \l_grill_file_name_tl { #1 } }
\tl_replace_all:Nnn \l_grill_file_name_tl { ~ } { - }
}

{
\file_if_exist:nTF { \l_grill_file_name_tl .pdf }
{
\group_begin:
\cs_set:Npx\grill_temp:
{
\group_end:
\exp_not:N \href{run\token_to_str:N : \l_grill_file_name_tl .pdf}{ #1 }
}
\grill_temp:
}
{
\fcolorbox{red}{yellow}{#1}
\footnote{Unable~to~locate~\l_grill_file_name_tl}
}
}

\ExplSyntaxOff

\begin{document}
\CrossReference{Abc Def}
\CrossReference[abc-def]{abc def}
\end{document}


The replacement of spaces by hyphens and the conversion to lowercase are easy.

-
Hmmm.. The output looks correct, but if I click on the link the file does not open for either the first or third link. For the code I posted it opened for the first link. Also noticed that spaces are being stripped in the footnote -- perhaps that's a clue. –  Peter Grill Mar 17 '12 at 3:39
@PeterGrill You're right under both respects; the \href has to be inside an \edef and the colon must be "normalized". Spaces in text written when \ExplSyntaxOn must be denoted by ~. –  egreg Mar 17 '12 at 10:25

I can't imagine why you need the lowercasing expandable here (making the link won't be) so why not just

\def\foo#1#2{{%
\lccode\ \-%
\lowercase{#1{#2.pdf}}}}

\foo{\write20}{AB cd  / eFG}

\bye


which produces:

 tex lc
This is TeX, Version 3.1415926 (Web2C 2010)
(./lc.tex [1
ab-cd-/-efg.pdf
] )


Using this in LaTeX and adjusting it a bit to match your MWE:

\documentclass{article}

\textheight10\baselineskip
\usepackage{hyperref,color}

\def\xCrossReference#1#2{%
\IfFileExists{#1}{%
\href{#1}{#2}}{%
\fcolorbox{red}{yellow}{#2}%
\footnote{Unable to locate #1}}}

\newcommand\CrossReference[2][\relax]{%
\ifx\relax#1%
\bgroup\lccode\ \-\lowercase{\egroup
\xCrossReference{#2.pdf}}{#2}%
\else
\xCrossReference{#1.pdf}{#2}%
\fi}

\begin{document}
Manual References: \CrossReference[equation-of-circle]{Equation of Circle}%

Manual References: \CrossReference[non-existant-file]{Non Existant File}%

\medskip\hrule\medskip

Automatic References: \CrossReference{Equation of Circle}%

Automatic References: \CrossReference{Non Existant File}%
\end{document}

\end{document}

-
I think my rep has made you think that I know more than I do, but I am not able to figure out how to use this. When I replace ./#2.pdf with \foo{./}{#2}, I get the error message: Improper alphabetic constant. <to be read again> \discretionary –  Peter Grill Mar 17 '12 at 4:04
@PeterGrill Odd. Try to replace \- by \noexpand\-. –  Bruno Le Floch Mar 17 '12 at 10:32
Using \def\foo#1#2{{% \lccode'\ '\noexpand\-% \lowercase{#1{#2.pdf}}}} yields Too many }'s. \PdfFileName ...case {./{Equation of Circle.pdf}}}. The nested back ticks were resulting in an issue in the display of the code here, so I replaced the back tick in the code with a ' for display purposes here. –  Peter Grill Mar 17 '12 at 16:21
Ok, there was indeed an extra set of {} in the \def. With this change, then lines 1 & 2 are correct (as they were in the original MWE), and clicking on line 1 does indeed open the file. However, lines 3 and 4 are incorrectly displayed in that extra text is shown, similar to problem outlined in text being output when none should be, and clicking on the link on line 3 does not open the PDF. Also line 4 is displayed as if the file was found. –  Peter Grill Mar 17 '12 at 16:29
Yes the issue is exactly the sane as the previous question the lccode assignment is an assignment same as a def and so if you put them in an expansion context the arguments expand but the assignment doesn't happen. You don't put that in the edef or special, foo applies #1 to '#2 after lowercasing the latter. So I use \write20 for #1 but you could use \href`. I may expand the answer later (been out all day) –  David Carlisle Mar 17 '12 at 21:01