Usando \ DTLfetch dentro de un \ href

Dec 04 2020

Estoy tratando de crear un nuevo comando en LaTeX que crea una URL de Google Map apuntando a las coordenadas asociadas con el lugar especificado como parámetro en el comando llamado (una especie de función de "búsqueda de tabla"). Los lugares y las coordenadas relativas se almacenan dentro de un coords.CSVarchivo y deben leerse usando el datatoolpaquete.

La URL del mapa de Google debe estructurarse así:

https://www.google.com/maps/?q=<LAT>,<LNG>

donde <LAT>y <LNG>son las coordenadas de latitud y longitud cargadas desde el coords.CSVarchivo, que está estructurado de esta manera:

Place,LAT,LNG
Test,42.0000,42.0000
...

Así es como se definió el comando:

\usepackage{datatool}
\newcommand{\coords}[1]{
    % Loads the CSV
    \DTLsetseparator{,}
    \DTLloaddb{coords}{doc/coords.csv}
        
    % Assigns the coordinates to the variables \LAT and \LNG, relative to specific place (the parameter #1)
    \def \LAT {\DTLfetch{coords}{Place}{#1}{LAT}}
    \def \LNG {\DTLfetch{coords}{Place}{#1}{LNG}}
    
    % Generates the URL pointing to Google Maps
    Place: \href{https://www.google.com/maps/?q=\LNG ,\LNG}{#1}
}

Finalmente, uso el nuevo comando de esta manera:

\coords{Test}

He logrado cargar correctamente las coordenadas del lugar llamado dentro del comando (en este caso "Test"), pero cuando intento generar la URL, LaTeX me da muchos errores, la mayoría de los cuales son ! Undefined control sequence. Si elimino \LATy \LNGde la línea donde se genera la URL (dentro de la definición del comando), no obtengo ningún error, pero por supuesto la URL no contiene coordenadas, ya que están almacenadas dentro de las variables \LATy \LNG.

¿Hay alguna forma de generar correctamente la URL utilizando las variables definidas dentro del \hrefcomando?

Este es un ejemplo de prueba:

\documentclass[a4paper,10pt]{article}

\usepackage{hyperref}           
\usepackage{datatool}

\newcommand{\coords}[1]{
     % Loads the CSV
    \DTLsetseparator{,}
    \DTLloaddb{coords}{coords.csv}
        
    % Assigns the coordinates to the variables \LAT and \LNG, relative to specific place (the parameter #1)
    \def \LAT {\DTLfetch{coords}{Place}{#1}{LAT}}
    \def \LNG {\DTLfetch{coords}{Place}{#1}{LNG}}
    
    % Generates the URL pointing to Google Maps
    Place: \href{https://www.google.com/maps/?q=\LAT ,\LNG}{#1}
}

\begin{document}

\coords{Test}

\end{document}

Respuestas

4 egreg Dec 04 2020 at 11:05

Puede usar el mismo truco que en mi respuesta para recuperar la subcadena de `\ DTLfetch`

\begin{filecontents*}{\jobname.csv}
Place,LAT,LNG
Test,42.0000,42.0000
\end{filecontents*}

\documentclass{article}
\usepackage{datatool}
\usepackage{hyperref}

\DTLsetseparator{,}
\DTLloaddb{coords}{\jobname.csv}

\newcommand{\DTLfetchsave}[5]{% see https://tex.stackexchange.com/a/335489/4427
  \edtlgetrowforvalue{#2}{\dtlcolumnindex{#2}{#3}}{#4}%
  \dtlgetentryfromcurrentrow{\dtlcurrentvalue}{\dtlcolumnindex{#2}{#5}}%
  \let#1\dtlcurrentvalue
}

\newcommand{\coords}[1]{%
  \DTLfetchsave{\LAT}{coords}{Place}{#1}{LAT}%
  \DTLfetchsave{\LNG}{coords}{Place}{#1}{LNG}%
  % Generates the URL pointing to Google Maps
  Place: \href{https://www.google.com/maps/?q=\LAT,\LNG}{#1}%
}

\begin{document}

\coords{Test}

\end{document}

Solía \jobnameevitar golpear mis archivos. Puede utilizar el nombre de archivo que desee para la base de datos.

Cargue la base de datos una vez, no cada vez que llame \coords.

3 UlrichDiez Dec 04 2020 at 12:34

Sugiero el siguiente enfoque:

\documentclass[a4paper,10pt]{article}

% Let's create the file coords.csv - the directory ./doc  must exist 
% and writing-permission for that directory must be given!!!
% An already existing file won't be overwritten by the 
% filecontents*-environment (unless you provide the "overwrite"-option)
% and you will be informed about the fact that the file already
% exists via a message in the .log-file only. You won't get a 
% message on the terminal/console.
\begin{filecontents*}{doc/coords.csv}
Place,LAT,LNG
Test,42.0000,42.0000
\end{filecontents*}

\usepackage{hyperref}           
\usepackage{datatool}

\newcommand{\coords}[1]{%%%
    \begingroup
    % Load the CSV only if database "coords" doesn't already exist:
    \DTLifdbexists{coords}{}{%%%
      %\DTLsetseparator{,}% Comma is the default, so this probably is not needed.
      \DTLloaddb{coords}{doc/coords.csv}%%%
    }%%%
    % Assign the coordinates of the place whose name is denoted by the
    % parameter #1 to the macros \LAT and \LNG:
    \edtlgetrowforvalue{coords}{\dtlcolumnindex{coords}{Place}}{#1}%%%
    \dtlgetentryfromcurrentrow{\LAT}{\dtlcolumnindex{coords}{LAT}}%%%
    \dtlgetentryfromcurrentrow{\LNG}{\dtlcolumnindex{coords}{LNG}}%%%
    %%%
    % Use the name (denoted by #1) of the place as a hyperlink leading
    % to the corresponding URL of Google Maps:
    Place: \href{https://www.google.com/maps/?q=\LAT,\LNG}{#1}%%%
    \endgroup
}%%%

\begin{document}

\coords{Test}

\end{document}

Sugiero este enfoque porque con su código hay algunos problemas:

Problema 1:

Su \coords-comando produce tokens de espacio y tokens no \pardeseados:

Lo reescribo con comentarios que indican dónde surgen estos tokens no deseados:

\newcommand{\coords}[1]{ %<- unwanted space-token yields horizontal space in horizontal mode
    % Loads the CSV
    \DTLsetseparator{,} %<- unwanted space-token yields horizontal space in horizontal mode
    \DTLloaddb{coords}{doc/coords.csv} %<- unwanted space-token yields horizontal space in horizontal mode
        %<- unwanted control word token \par
    % Assigns the coordinates to the variables \LAT and \LNG, relative to specific place (the parameter #1)
    \def \LAT {\DTLfetch{coords}{Place}{#1}{LAT}} %<- unwanted space-token yields horizontal space in horizontal mode
    \def \LNG {\DTLfetch{coords}{Place}{#1}{LNG}} %<- unwanted space-token yields horizontal space in horizontal mode
        %<- unwanted control word token \par                
    % Generates the URL pointing to Google Maps
    Place: \href{https://www.google.com/maps/?q=\LAT ,\LNG}{#1} %<- unwanted space-token yields horizontal space in horizontal mode
}

Problema 2:

El hiperref-manual dice que los tokens en el argumento URL de \hrefdeben ser completamente expandibles.

Sus comandos \LATy \LNGno son completamente expandibles porque su definición contiene el token de la palabra de control \DTLfetchmientras que el manual del paquete datatool dice claramente que

\DTLfetch{students}{regnum}{\RegNum}{forename}
es igual a

\dtlgetrowforvalue{students}{\dtlcolumnindex{students}{regnum}}{\RegNum}%

\dtlgetentryfromcurrentrow{\dtlcurrentvalue}{\dtlcolumnindex{students}{forename}}% \dtlcurrentvalue

lo que indica que \DTLfetch(y por lo tanto, cada macro cuya expansión en alguna etapa produce el token \DTLfetch) no es completamente expandible cuando una macro \dtlcurrentvaluese define por \dtlgetentryfromcurrentrow.

Problema 3:

Dudo que sea necesario cargar la base de datos con cada llamada a \coords.

Problema 4:

Utilice el comando \DTLsetseparatorpara establecer el separador de las entradas de una base de datos en coma, aunque este es el valor predeterminado. Entonces esto probablemente esté obsoleto.