# Index that picks up on example numbers, not page numbers

I am producing some glossed linguistic texts in a Native American language. The sentences are labeled as, e.g., (2.3)—meaning “text 2, sentence 3”—and I’d like the index to pick up on these numbers, rather than page numbers. In terms of the picture below, I’d like:

Bratwurst, (2.1)

Sauerkraut, (2.2)

as opposed to what’s shown (Bratwurst, 2; Sauerkraut, 2).

How can I achieve this?

I’m using a version of expex for the example numbers. It's too long to include here, but I can email it to any interested parties.

*Clarification. I know how to label examples (by putting e.g., <label> after \ex) and how to call labels at a later point (\getref{label}). This questions isn't about example labelling however: I don't want to have to manually link cabbage to, say, \getref{Sauerkraut}, \getref{Kohl}, \getref{Wirsing}. I want to piggyback off makeindex to produce an index that lists example numbers instead of page numbers.

\documentclass{report}
\usepackage{expex-x2}
\usepackage{expexchapno}

\lingset{aboveexskip=0pt,glspace=1em plus .5em minus.2em,
glrightskip=0pt plus 8em,aboveglftskip=0pt,glneveryline={\it},
glstyle=nlevel,everygl={\hangindent=1.2em \hangafter=1},
exnotype=chapter.arabic}

\usepackage{makeidx}
\makeindex

\begin{document}

\gathertags

\chapter{First chapter}

\chapter{Second chapter}

\ex Bratwurst --- this example is followed by \verb"\index{Bratwurst}"
\xe \index{Bratwurst}

\ex Sauerkraut --- this example is followed by
\verb"\index{Sauerkraut}" \xe \index{Sauerkraut}

\printindex
\end{document}

• Chapter 13 (Referring to examples and labeled parts of examples) of the ExPex documentation provides some solutions. AFAIK \index is meant to refer to page numbers only. Mar 14, 2014 at 19:46
• As another German, I am also deeply shocked about your selection of words concerning Native American Language;-)
– user31729
Mar 15, 2014 at 22:36
• The lineno package will compute (and usually display) line numbers. \linelablel{} creates a number which can be displayed using ref{}. \renewcommand\LineNumber{\relax} will (probably) turn off the display. Mar 15, 2014 at 23:45
• I got it! You modify \thepage to format page numbers the way you want them in the index, and modify the footer to NOT use \thepage. Use \arabic{page} instead. Mar 16, 2014 at 1:24
• @JohnKormylo: Are you suggesting: (a) make the index pick up on line number; (b) make the line number counter pick up on example numbers? Mar 16, 2014 at 19:31

Longer post

Please allow me to share my findings with you. I've divided my answer into three parts: no traffic, one-way traffic and two-way traffic, each part resulting in its own compilable TeX file.

I have used Xindy because MakeIndex is rather limited for non-English languages. On the other hand, I am using rather old makeidx package, but I would recommend to use the imakeidx package because we could save one I/O write slot in the last part. I wanted to compare methods, I used that way.

I am using lualatex to process the TeX files, but any major latex engine can be used.

No transportation: remarks on the mal-expex-1.tex file

As it was already pointed out on it, we can redefine \@wrindex as it is the key part called by the \index command. We can store the information directly by calling for \ep@rawexnoprint, see line 19 in the first file. That's the command the expex package uses to store information.

Next problem is how to notify the index processor about number dot number location. Xindy uses location class for this purpose, it uses several of them and we can create a new one. It can be done by define-location-class plus we define accompanying markup-locref for this new class, in addition to that we are adding parentheses. The last step would be to define the order of new location classes, with your permission, I will show you later how it can be done.

We run:

lualatex mal-expex-1.tex
xindy -M texindy -M expex-1 -L general -C utf8 mal-expex-1.idx
lualatex mal-expex-1.tex

The content of the mal-expex-1.idx file is as follows:

\indexentry{Bratwurst}{2.1}
\indexentry{Sauerkraut}{2.2}
\indexentry{Striz}{2.3}
\indexentry{Oldman}{2.4}
\indexentry{Sauerkraut}{2.5}


I enclose the TeX code and a preview of three cropped pages. As we can see from the last page, this is the requested form, but Houston, we have a problem! Once we want clickable version of our document, the index cross-references are not working.

% run: *latex mal-expex-1.tex
\documentclass{report}
\pagestyle{empty}
\usepackage{expex}
\lingset{aboveexskip=0pt,glspace=1em plus .5em minus.2em,
glrightskip=0pt plus 8em,aboveglftskip=0pt,glneveryline={\it},
glstyle=nlevel,everygl={\hangindent=1.2em \hangafter=1},
exnotype=chapter.arabic}
\usepackage{makeidx}
\makeindex
\usepackage{filecontents}
\begin{filecontents*}{expex-1.xdy}
;; expex-1.xdy
(define-location-class "expexnumber" ("arabic-numbers" :sep "." "arabic-numbers"))
(markup-locref :open "(" :close ")" :class "expexnumber")
\end{filecontents*}
\makeatletter
\def\@wrindex#1{%
\protected@write\@indexfile{}%
{\string\indexentry{#1}{\ep@rawexnoprint}}%
\endgroup
\@esphack#1%
}%End of \def\@wrindex...
\makeatother

\begin{document}
%\gathertags
\chapter{First chapter}
Some initial text.
\chapter{Second chapter}
The first approach.
\ex Bratwurst --- this example is followed by \index{Bratwurst} \xe
\ex Sauerkraut --- this example is followed by \index{Sauerkraut} \xe
\ex By \index{Striz} \xe
\ex By \index{Oldman} \xe
\ex Again \index{Sauerkraut} \xe
%\begingroup
%\def\thispagestyle#1{}%
\printindex
%\endgroup
\end{document}


One-way traffic: remarks on the mal-expex-2.tex file

Well, I have already opened that Pandora's box, let me inform you how we can save our souls. That major problem brings me to load the hyperref package and explore our further possibilities.

The idea was to use regular cross-references as we know it from \label+\ref+\pageref combination, no matter of what will be typeset in the index location of index entries.

I have redefined the \@wrindex, added |myhyperlink{\ep@rawexnoprint} which helps us to control the output. The key step was adding \label{\ep@rawexnoprint}#1 into this command. It stores reference information and prints the reference for us, therefore we don't have to type it twice.

We notify the index processor about a new command by define-attributes and we define a new class as in the first example. The result of our efforts is that the number is clickable, the parentheses are not.

There is a small problem as hyperref is redefining commands that it is clickable but it leads us to the page not to the line where \index command was called. If we explore the mal-expex-2.aux file further we can see what's going on:

\newlabel{2.1}{{1}{2}{Second chapter}{chapter.2}{}}


It stored all the necessary information, but it leads to the second chapter. That's not the best result we can achieve here as the title itself could be typeset several pages earlier than the expex examples. Well, we have got some improvement. We are getting error messages from xindy about cross-reference-targets not existing, but we can ignore them, we manage that part by ourselves.

We run these three lines:

lualatex mal-expex-2.tex
xindy -M texindy -M expex-2 -L general -C utf8 mal-expex-2.idx
lualatex mal-expex-2.tex

The content of the mal-expex-2.idx file is this:

\indexentry{Bratwurst|myhyperlink{2.1}}{2.1}


I enclose the TeX code and a preview of the result.

% run: *latex mal-expex-2.tex
\documentclass{report}
\pagestyle{empty}
\usepackage{expex}
\lingset{aboveexskip=0pt,glspace=1em plus .5em minus.2em,
glrightskip=0pt plus 8em,aboveglftskip=0pt,glneveryline={\it},
glstyle=nlevel,everygl={\hangindent=1.2em \hangafter=1},
exnotype=chapter.arabic}
\usepackage{makeidx}
\makeindex
\usepackage{filecontents}
\begin{filecontents*}{expex-2.xdy}
;; expex-2.xdy
\end{filecontents*}
\makeatletter
\def\@wrindex#1{%
\protected@write\@indexfile{}%
\endgroup
\@esphack\label{\ep@rawexnoprint}#1}%
\makeatother%End of \def\@wrindex...

\begin{document}
%\gathertags
\chapter{First chapter}
Some initial text.
\chapter{Second chapter}
The first approach.
\ex Bratwurst --- this example is followed by \index{Bratwurst} \xe
\ex Sauerkraut --- this example is followed by \index{Sauerkraut} \xe
\ex By \index{Striz} \xe
\ex By \index{Oldman} \xe
\ex Again \index{Sauerkraut} \xe
%\begingroup
%\def\thispagestyle#1{}%
\printindex
%\endgroup
\end{document}


Two-way traffic: remarks on the mal-expex-3.tex file

Once we can improve something, we will. We wish to have clickable version of the document with cross-references leading to the proper locations. Moreover, we can try to have cross-references from both directions. From \index to the index and from index entries in index back to its \index counterparts. We must bear in mind that index entries are grouped and we may lose some hyperlinks in index, generally speaking.

For this I used a couple of \hypertarget and \hyperlink commands assuring I provide them unique markers, see lines 40-47 in the code below. It is corrected version, it goes to the original location, but there is no way back. Let's focused on that feature.

I have prepared a new file for next experiments to separate them from regular idx file for purpose of this post. I will use myi extension (reflects the idx file) and iym extension (reflects the ind file).

The core of this method is to use \hypertarget and \hyperlink twice: one pair handling one way, the other pair handling the way back. Please see lines 50-65 in the code. I needed to use \raisebox to get location from left baseline of the box to the left top corner.

I also prepared a new set of commands for regular use. We can store page numbers (it is a common method; plain arabic number), we can store number of expex example (arabic number dot arabic number wrapped in the parentheses) and chapter number (arabic number wrapped in the brackets). Using this approach, see lines 68-70, we can store almost anything there.

The only remaining thing we must do is to notify xindy about all this. Let's extend our xdy style file, please see lines 20-36 in the TeX code.

To make our work easier I have done one more improvement. I have redefined the \ex...\xe statements to the form of just \ex... by defining the end of the line (^^M) as a command and using it afterwards. This step is of course not necessary in production, I just wanted to show you that it can be done and we can save typing of \xe.

We run the following four lines:

lualatex mal-expex-3.tex
xindy -M texindy -M expex-3 -L general -C utf8 -o mal-expex-3.ind mal-expex-3.idx
xindy -M texindy -M expex-3 -L general -C utf8 -o mal-expex-3.iym mal-expex-3.myi
lualatex mal-expex-3.tex

The content of the mal-expex-3.idx file is the same as in the second part, because we redefined commands at the TeX level. The content of the mal-expex-3.myi file is something new for us and it looks like this:

\indexentry{on purpose|malchapter{2-2-1}}{2}
\indexentry{paja|malpage{2-2-2}}{2}
\indexentry{malipivo|malpage{2-2-3}}{2}
\indexentry{next a|malexpex{2.8-2-4}}{2}
\indexentry{more a|malexpex{2.9-2-5}}{2}
\indexentry{next b|malchapter{2-2-6}}{2}
\indexentry{more b|malchapter{2-2-7}}{2}
\indexentry{paja|malexpex{2.12-2-8}}{2}
\indexentry{paja|malchapter{2-2-9}}{2}


I enclose the last example and a preview of our efforts.

% run: *latex mal-expex-3.tex
\documentclass{report}
\pagestyle{empty}
\usepackage{expex}
\lingset{aboveexskip=0pt,glspace=1em plus .5em minus.2em,
glrightskip=0pt plus 8em,aboveglftskip=0pt,glneveryline={\it},
glstyle=nlevel,everygl={\hangindent=1.2em \hangafter=1},
exnotype=chapter.arabic}
\usepackage{makeidx}
\makeindex

\usepackage{filecontents}
\begin{filecontents*}{expex-3.xdy}
;; expex-3.xdy
(define-location-class "expexnumber" ("arabic-numbers" :sep "." "arabic-numbers"))
(define-location-class "expexchapter" ("arabic-numbers" :sep "."))
(define-location-class-order ("expexnumber" "expexchapter" "arabic-numbers"))

(define-crossref-class "malpage")
(markup-crossref-list :class "malpage" :sep ",\,")
(markup-crossref-layer :open "\myhyper{" :close "}" :class "malpage")

(define-crossref-class "malexpex")
(markup-crossref-list :class "malexpex" :sep ",\,")
(markup-crossref-layer :open "(\myhyper{" :close "})" :class "malexpex")

(define-crossref-class "malchapter")
(markup-crossref-list :class "malchapter" :sep ",\,")
(markup-crossref-layer :open "[\myhyper{" :close "}]" :class "malchapter")
\end{filecontents*}

% Redefinition in common index... (one-way approach)
\makeatletter
\def\@wrindex#1{%
\protected@write\@indexfile{}%
\endgroup
\@esphack\raisebox{\baselineskip}[0pt][0pt]{\hypertarget{\ep@rawexnoprint}{\raisebox{-\baselineskip}[0pt][0pt]{#1}}}}%
\makeatother

% A new index file...
\makeatletter
\let\temphere=\ep@rawexnoprint
\makeatother
\newwrite\myindexfile
\immediate\openout\myindexfile=\jobname.myi
\def\myhyper#1{\myhypertemp #1 }
% Two-way approach...
\newcount\mycounter
\mycounter=0
\def\myshipping#1#2{%
\raisebox{\baselineskip}[0pt][0pt]{\hypertarget{\the\mycounter}{}}%
\immediate\write\myindexfile{\string\indexentry{#1|\material{#2-\thepage-\the\mycounter}}{\thepage}}%
}% End of \myshipping...

% Regular definitions to be used in document body...
\def\pageindex#1{\def\material{malpage}\myshipping{#1}{\thepage}}
\def\expexindex#1{\def\material{malexpex}\myshipping{#1}{\temphere}}
\def\chapterindex#1{\def\material{malchapter}\myshipping{#1}{\thechapter}}

\begin{document}
% The form of \ex...\xe rewritten to the form of \ex... only
% We are hacking the end of the line...
\catcode\^^M=13
\def^^M{\par}
\let\extemp=\ex
\def\ex#1^^M{\extemp#1\xe}

%\gathertags
\chapter{First chapter}
Some initial text.

\chapter{Second chapter}
The first approach.

\ex Bratwurst --- this example is followed by \index{Bratwurst}
\ex Sauerkraut --- this example is followed by \index{Sauerkraut}
\ex By \index{Striz}
\ex By \index{Oldman}

\ex an experiment \chapterindex{on purpose}
\ex hello 1 \pageindex{paja}
\ex hello 2 \pageindex{malipivo}
\ex hello 3 \expexindex{next a}
\ex hello 4 \expexindex{more a}
\ex hello 5 \chapterindex{next b}
\ex hello 6 \chapterindex{more b}
\ex hello 7 \expexindex{paja}
\ex hello 8 \chapterindex{paja}
\ex finish \index{Sleep}

% A common index...
%\begingroup % Redefinition of \indexname...
%\def\thispagestyle#1{}%
\def\indexname{Common index\\ with example numbers\\(one-way traffic)}
\printindex

% An improved version of index...
\def\indexname{Index of\\ page, (exercise), [chapter]\\(two-way traffic)}
\immediate\closeout\myindexfile
\IfFileExists{\jobname.iym}{\input \jobname.iym}{}%
%\endgroup
\end{document}


• Thank you belatedly for the effort that went into this answer. This is neater than the hack that I've been deploying, namely, of using hyphen to separate chapter and example numbers [e.g., (2-1)], letting makeidx compile that (it doesn't object), then opening up the .idn file and doing a search and replace of hyphen for dot. Sep 23, 2014 at 15:32

I wanted to post a solution that amounts to the same thing, but which may be a bit simpler. It uses the index package. You can instruct index to use a specific macro (below, \PageExample) to generate a reference in the index. Below I have it printing entries in the format "Page-Example" (e.g., 2-7). A different format is discussed below.

\documentclass{book}
\usepackage{expex,lipsum,index}
% use this definition if using makeindex
\newcommand{\PageExample}{\thepage-\the\excnt}
% use this definition if using xindy
% \newcommand{\PageExample}{\thepage (\the\excnt)}
\newindex[PageExample]{my-index}{idx}{ind}{My Custom Index}
\makeindex
\begin{document}
\ex \lipsum[1]\index[my-index]{First example} \xe

\ex \lipsum[2] \index[my-index]{Second example}\xe

\ex \lipsum[3] \index[my-index]{Third example}\xe

\ex \lipsum[4] \index[my-index]{Fourth example}\xe

\ex \lipsum[5] \index[my-index]{Fifth example}\xe

\ex \lipsum[6] \index[my-index]{Sixth example}\xe

\ex \lipsum[6] \index[my-index]{Seventh example}\xe

\printindex[my-index]
\end{document}


The punctuation that can occur in the index references is limited by makeindex. If you're happy with the format "2-7" the above example works perfectly.

If you use xindy to process the index there is more flexibility. I wanted references like this "Page-number (Example-number)" i.e., 2(7). It's easy to generate that with the alternate definition of \PageExample above, but the index file then needs to be processed by xindy.

After compiling with latex, I invoke xindy as follows:

texindy -L english example.idx -M page-example.xdy


The file page-example.xdy instructs xindy about my "Page-number (Example-number)" format. It contains just one line:

(define-location-class "page-example" ("arabic-numbers" :sep "(" "arabic-numbers" :sep ")" ))


Modifying \thepage turned out not be a good idea, for reasons stated below. So instead I now write to the .idx file directly.

The main problem remaining is that makeindex only recognizes {-} as a delimiter, not {.}. Also, the counter \excnt is incremented AFTER it is used instead of BEFORE it is used.

Following Nicoloa Talbot's advice I was able to fix the delimeter problem. Note that I have windows installed on drive G, which is probably not the case for anyone else.

First I copied and renamed an ist file from G:\programfiles\MikTex 2.9\makeindex as "period.ist". Any subdirectory will do. I also edited it to consist of

page_compositor "."

Then I used the Build/Define Output Profiles menu from TeXnic Center to add -s "period.ist" to the Makeindex argument list. If any of these steps are not done correctly (for your installation) then Makeindex will not work.

\documentclass{report}
\usepackage{expex}

\lingset{aboveexskip=0pt,glspace=1em plus .5em minus.2em,
glrightskip=0pt plus 8em,aboveglftskip=0pt,glneveryline={\it},
glstyle=nlevel,everygl={\hangindent=1.2em \hangafter=1},
exnotype=chapter.arabic}

\usepackage{makeidx}
\makeindex

\makeatletter
\newcommand{\ExIndex}[1]% same as \index
{%
\immediate\write\@indexfile
{\string\indexentry{#1}%
{\thechapter.\the\excnt}}%
}%
\makeatother

\begin{document}

\gathertags

\chapter{First chapter}

\chapter{Second chapter}

\ExIndex{Bratwurst}
\ex Bratwurst --- this example is preceded by \verb"\ExIndex{Bratwurst}"
\xe

\ExIndex{Sauerkraut}
\ex Sauerkraut --- this example is preceded by \verb"\ExIndex{Sauerkraut}"
\xe

\printindex
\end{document}


• The write to the external file is deferred, so by the time the line is written, \thepage has switched back to \arabic{page}, which is why it doesn't work. Mar 16, 2014 at 18:10
• I guess it must wait until the end of the page. So one would have to have \thepage give a different answer each time it is called (in sequence). Ugh! Mar 16, 2014 at 21:23
• The delimiter can be changed to a full stop by creating a .ist file (for example mystyle.ist) and adding the line page_compositor "." (and you need to specify the style using the -s switch when you run makeindex`) Mar 17, 2014 at 17:38
• @Nicola Talbot - One thing windows will NOT let you do is create a file with a specific extension. Instead I wind up creating mystyle.ist.tex. If I have an .ist file, I can copy and edit it, so do you know where I can download one or could you email me one? Mar 17, 2014 at 20:34
• Never mind, I found one in MikTeX Mar 17, 2014 at 20:46