[Tex/LaTex] How to convince hyperref and xindy to play together nicely

hyperrefindexingxindy

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:

Missing page range numbers

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?

Best Answer

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.

Ad 3.

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.

Related Question