# How can I convince hyperref and xindy to play together nicely?

I'm using xindy to generate indexes for a manual that gets translated into multiple languages. Unfortunately, hyperref and xindy don't like to play nicely together. I found some older mailing list threads that suggest that fixing this in xindy would require too much effort.

My question is: how can I get xindy and hyperref to play nicely together. What is the best workaround for this incompatibility?

An example document will demonstrate the problem:

\documentclass{article}

\usepackage{lipsum}
\usepackage{makeidx}
\usepackage{hyperref}

\makeindex

\begin{document}

\index{single}
\index{range|(}
\lipsum
\index{range|)}

\printindex

\end{document}


I compile this document (named x.tex) using xelatex and xindy:

xelatex x
xindy -C utf8 -M texindy -L english x.idx
xelatex x
xelatex x


Page numbers that are part of a range are missing from the index:

The xindy output makes a few complaints:

WARNING: Found no :close-range matching an already opened one!
Location-reference is 1 in keyword (range).
Maybe I lost some of the regular location-references.

WARNING: Found a :close-range in the index that wasn't opened before!
Location-reference is 2 in keyword (range)
I'll continue and ignore this.


These errors make sense when we look at the x.idx file:

\indexentry{single|hyperpage}{1}
\indexentry{range|(hyperpage}{1}
\indexentry{range|)}{2}


The hyperpage command isn't used in the close-range entry.

In order of preference, here are my desired outcomes:

1. xindy and hyperref work perfectly together and generate indexes with hyperlinked page numbers without any external processing.
2. xindy and hyperref can generate indexes with hyperlinked page numbers with the aid of an external script to pre- or post-process the index files before/after passing them through xindy. (I'm not currently using any special formatting for page numbers if that simplifies things.)
3. xindy can be pacified by removing hyperlinks from the page numbers (with or without the use of an external script).

Alternatively, is there a different indexing program that can work with UTF-8-encoded files, hyperref, and knows to collate various languages?

-
@Stephen: That perl script failed to run for me. It initially complained about an unmatched ( in the regex. I escaped the ( with backslashes, but then it just made a message of the .idx file. –  godbyk Nov 4 '12 at 19:57
@Stephen: That only adjusts the second line of the .idx file shown above. xindy reports the following: WARNING: unknown cross-reference-class hyperindexformat'! (ignored)' and the pagae range still doesn't appear in the index. –  godbyk Nov 5 '12 at 20:22
OK, another experiment (Lacking the knowledge I'm doing trial and error here, sorry): What happens when you remove the hyperpage from \indexentry{range|(hyperpage}{1}? –  Stephen Nov 6 '12 at 20:45
Then I get “range, 1, 2” in the index (as opposed to the expected “range, 1–2”. But at least xindy doesn't balk. –  godbyk Nov 6 '12 at 21:06
No hyperlinks, just the page numbers. –  godbyk Nov 6 '12 at 21:27

## Simple ranges

In hyperref 2012/11/06 v6.83m the encapsulating command will be repeated, if it is not explicitly given for the closing range entry. Then both Makeindex and xindy should be happy in case of simple ranges:

\index{...|(}
\index{...|)}


The .idx file will contain hyperpage in both cases.

## Formatting commands

From the manual page of xindy:

For raw index entries in LaTeX syntax, \index{aaa|bbb} is interpreted differently. For MakeIndex bbb is markup that is output as a LaTeX tag for this page number. For xindy, this is a location attribute, an abstract identifier that will be later associated with markup that should be output for that attribute.

For straight-forward usage, when bbb is textbf or similar, we supply location attribute definitions that mimic MakeIndex's behaviour.

For more complex usage, when bbb is not an identifier, no such compatibility definitions exist and may also not been created with current xindy. In particular, this means that by default the LaTeX package hyperref will create raw index files that cannot be processed with xindy. This is not a bug, this is the unfortunate result of an intented incompatibility. It is currently not possible to get both hyperref's index links and use xindy.

A similar situation is reported to exist for the memoir LaTeX class.

Programmers who know Common Lisp and Lex and want to work on a remedy should please contact the author.

Easy, hyperref index redefinitions are suppressed by

\usepackage[hyperindex=false]{hyperref}


Maybe there is a way to insert \hyperpage for linked page numbers in xindy.

## Minimal page range

Xindy make page ranges starting with three consecutive page numbers. This can changed by setting :min-page-range to 1 (default is 2). The following file mypagerange.xdy also includes page-ranges.xdy that contains the definition of the range separator:

; File mypagerange.xdy
(require "page-ranges.xdy")
(define-location-class "arabic-page-numbers"
("arabic-numbers") :min-range-length 1)


Then xindy is called with option -M mypagerange.xdy.

-
thanks for the hyperref update! It looks like it pacifies xindy for the most part. The only remaining problem is that xindy shows the “range” entry as “range, 1, 2” instead of “range, 1–2” (despite my specifying -M page-ranges.xdy to xindy). xindy lodges no complains against the new index file. Any ideas there? –  godbyk Nov 15 '12 at 4:42
The mypagerange.xdy script worked perfectly. Thanks, Heiko! –  godbyk Nov 21 '12 at 7:30
\hyperpage for linked page numbers can be inserted with (markup-locref :open "\hyperpage{" :close "}). –  michal.h21 Jan 23 '13 at 22:16

Here's the solution that worked for me (based on Heiko's and michal's replies).

\documentclass{article}

\usepackage{lipsum}
\usepackage[xindy]{imakeidx}
\usepackage[hyperindex=false]{hyperref}
\def\xindyopt{-M indexstyle}
\makeindex[options=\xindyopt]

\begin{filecontents*}{indexstyle.xdy}
(require "page-ranges.xdy")
(define-location-class "arabic-page-numbers"
("arabic-numbers") :min-range-length 1)
(markup-locref :open "\hyperpage{" :close "}")
\end{filecontents*}

\begin{document}

\index{single}
\index{range|(}
\lipsum
\index{range|)}

\printindex

\end{document}

-
Does this solution reveal anything new? –  Christian Hupfer Aug 25 at 20:44
It corrects a syntax error in michal's answer and simply puts everything together for struggling texnicians like me that are trying to compile their first index. –  emav Aug 26 at 7:48