[Tex/LaTex] Index that picks up on example numbers, not page numbers

expexindexinglinguistics

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?

enter image description here

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}

Best Answer

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}

mwe, part 1: no traffic


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}
\indexentry{Sauerkraut|myhyperlink{2.2}}{2.2}
\indexentry{Striz|myhyperlink{2.3}}{2.3}
\indexentry{Oldman|myhyperlink{2.4}}{2.4}
\indexentry{Sauerkraut|myhyperlink{2.5}}{2.5} 

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[colorlinks]{hyperref}
\usepackage{filecontents}
\begin{filecontents*}{expex-2.xdy}
;; expex-2.xdy
(define-attributes (("default" "textbf" "textit" "myhyperlink")))
(define-crossref-class "myhyperlink")
(markup-crossref-list :class "myhyperlink" :sep ",\,")
(markup-crossref-layer :open "(\myhyperlink{" :close "})" :class "myhyperlink")
\end{filecontents*}
\def\myhyperlink#1{\hyperref[#1]{#1}}
\makeatletter
\def\@wrindex#1{%
   \protected@write\@indexfile{}%
      {\string\indexentry{#1|myhyperlink{\ep@rawexnoprint}}{\ep@rawexnoprint}}%
 \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}

mwe, part 2: one-way traffic


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[colorlinks=true]{hyperref}

\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-attributes (("malpage" "malexpex" "malchapter" "myhyperlink")))

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

(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)
\def\myhyperlink#1{\hyperlink{#1}{#1}}
\makeatletter
\def\@wrindex#1{%
   \protected@write\@indexfile{}%
      {\string\indexentry{#1|myhyperlink{\ep@rawexnoprint}}{\ep@rawexnoprint}}%
 \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 }
\def\myhypertemp #1-#2-#3 {\hyperlink{#3}{\raisebox{\baselineskip}[0pt][0pt]{\hypertarget{#3-to-index}}#1}}
% Two-way approach...
\newcount\mycounter 
\mycounter=0
\def\myshipping#1#2{%
  \global\advance\mycounter by 1%
  \raisebox{\baselineskip}[0pt][0pt]{\hypertarget{\the\mycounter}{}}%
  \hyperlink{\the\mycounter-to-index}{#1}%
  \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}

mwe, part 3: two-way traffic

Related Question