You can use my rdfref package for such things. It isn't unfortunately on CTAN, so you will need to install it yourself.
It is inspired by RDF, so you can declare objects for which you can set various properties. In your case, each use of the \applyconcept
should create a new object, for which it should set the concept name and page number as properties.
You can then define another command, named for example as \conceptpages
, which will search for all objects with the given concept name, and print the page numbers where they were used.
I've created a simple package, applyconcept.sty
, which implements these commands with the help of rdfref
:
\ProvidesPackage{applyconcept}
\RequirePackage{rdfref-user}
\RequirePackage{rdfref-query}
\RequirePackage{hyperref}
\newcommand\applyconcept[1]{%
% define a new object, with anonymous name
\BlankNode%
% set basic object properties
% this identifies the current object as the con:concept type
\AddProperty{rdf:type}{con:concept}%
% save the concept name, so it can be later looked up
\AddProperty{con:name}{#1}%
% save the page number for this concept
\AddPropertyEx{doc:pageNo}{\thepage}%
% define target for hyperlink, using the current object
% name as a label.
\hypertarget{\CurrentObject}{}%
}
\newcommand\conceptpages[1]{%
% we will want to separate page numbers with commans, but not the first one
\def\currentseparator{}%
% process all objects with the con:name property equal to the parameter
% it executes the code for each object that matches the condition
\Bind{?obj}{con:name}{#1}{%
% the object name is saved in the ?obj variable, we can get it's value and save it to a macro
% for a simpler access:
\edef\currobject{\GetVal{?obj}}%
% print the page number with link to the page%
\currentseparator\hyperlink{\currobject}{\GetProperty{\currobject}{doc:pageNo}}%%
% the subsequent pages will be separated using comma and space
\gdef\currentseparator{,\space}%
}%
}
\endinput
It defines the commands like this:
\newcommand\applyconcept[1]{%
% define a new object, with anonymous name
\BlankNode%
% set basic object properties
% this identifies the current object as the con:concept type
\AddProperty{rdf:type}{con:concept}%
% save the concept name, so it can be later looked up
\AddProperty{con:name}{#1}%
% save the page number for this concept
\AddPropertyEx{doc:pageNo}{\thepage}%
% define target for hyperlink, using the current object
% name as a label.
\hypertarget{\CurrentObject}{}%
}
First, it defines a new anonymous object using the \BlankNode
command, and then it adds various properties using the \AddProperty
or \AddPropertyEx
(for expanded value).
The rdf:type
property should be used for all objects, to identify the object type. In RDF, properties are named as prefix:name
, so I stick with this, even if it is not really necessary for our use.
The con:name
property is the concept name. It is necessary to save it, in order to be able to use the query language to search for all usages of this concept.
I've also added the \hypertarget
command, so it will be possible to make hyperlink exactly to the place where concept was defined. The \CurrentObject
command holds the current object name, usually something like _:blank1
for anonymous objects. We will get the object name in the query, so we will be able to link to this place.
Now the querying command:
\newcommand\conceptpages[1]{%
% we will want to separate page numbers with commans, but not the first one
\def\currentseparator{}%
% process all objects with the con:name property equal to the parameter
% it executes the code for each object that matches the condition
\Bind{?obj}{con:name}{#1}{%
% the object name is saved in the ?obj variable, we can get it's value and save it to a macro
% for a simpler access:
\edef\currobject{\GetVal{?obj}}%
% print the page number with link to the page%
\currentseparator\hyperlink{\currobject}{\GetProperty{\currobject}{doc:pageNo}}%%
% the subsequent pages will be separated using comma and space
\gdef\currentseparator{,\space}%
}%
}
The \currentseparator
command is used for correct handling of separating commas, so it is not really interesting.
The \Bind
command searches for a query. It takes four parameters:
\Bind{object}{property}{value}{code to be executed}
In our case, we know that we want to search for objects that have property con:name
with value passed as an argument (for instance concept-three
). The ?obj
used in the place of the object indicates that the object is unknown. The \Bind
command will loop over all objects, test if they have the given property and value, and execute the code when they matches. We can then get the object name using the \GetVal{?obj}
command.
We then can use the object name for two tasks: for the hyperlink, and to get the page number. For easier use, I've saved the object name in the \currobject
command. We can then use the following command to print the hyperlink and the page number:
\hyperlink{\currobject}{\GetProperty{\currobject}{doc:pageNo}}
The package can be used like this:
\documentclass{article}
\usepackage{applyconcept}
\begin{document}
\applyconcept{concept-three}As you can see, “concept three” applies to this case ...
\applyconcept{concept-four}As you can see, “concept four” applies to this case ...
\newpage
\applyconcept{concept-three}Apply concept three again.
To see this concept applied, please see pp.~\conceptpages{concept-three}.
\end{document}
This is the result:
