Usando \ DTLfetch dentro de um \ href

Dec 04 2020

Estou tentando criar um novo comando em LaTeX que cria um URL do Google Map apontando para as coordenadas associadas ao local especificado como um parâmetro no comando chamado (uma espécie de função de "pesquisa de tabela"). Os lugares e as coordenadas relativas são armazenados dentro de um coords.CSVarquivo e devem ser lidos usando o datatoolpacote.

O URL do Google Maps deve ser estruturado como este:

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

onde <LAT>e <LNG>são as coordenadas de latitude e longitude carregadas do coords.CSVarquivo, que é estruturado desta forma:

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

É assim que o comando foi definido:

\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}
}

Por fim, uso o novo comando desta forma:

\coords{Test}

Consegui carregar corretamente as coordenadas do local chamado dentro do comando (no caso "Teste"), mas quando tento gerar a URL, o LaTeX me dá muitos erros, a maioria deles ! Undefined control sequence. Se eu remover \LATe \LNGda linha onde a URL é gerada (dentro da definição do comando), não recebo nenhum erro, mas é claro que a URL não contém nenhuma coordenada, uma vez que elas estão armazenadas dentro das variáveis \LATe \LNG.

Existe uma maneira de gerar corretamente o URL usando as variáveis ​​definidas dentro do \hrefcomando?

Este é um exemplo de teste:

\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}

Respostas

4 egreg Dec 04 2020 at 11:05

Você pode usar o mesmo truque da minha resposta para recuperar substring 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}

Eu costumava \jobnameevitar destruir meus arquivos. Você pode usar qualquer nome de arquivo que desejar para o banco de dados.

Carregue o banco de dados uma vez, não sempre que ligar \coords.

3 UlrichDiez Dec 04 2020 at 12:34

Eu sugiro a seguinte abordagem:

\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}

Eu sugiro essa abordagem porque com seu código existem alguns problemas:

Problema 1:

Seu \coords-command produz tokens e \par-tokens indesejados:

Eu o reescrevo com comentários indicando onde esses tokens indesejados surgem:

\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
}

Edição 2:

O hyperref-manual diz que os tokens no URL-argumento de \hrefdevem ser totalmente expansíveis.

Seus comandos \LATe \LNGnão são totalmente expansível porque a sua definição contém a palavra de controle token de \DTLfetchenquanto o manual do-pacote Datatool diz claramente que

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

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

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

que indica que \DTLfetch(e, portanto, toda macro cuja expansão em algum estágio produz o token \DTLfetch) não é totalmente expansível conforme uma macro \dtlcurrentvalueé definida por \dtlgetentryfromcurrentrow.

Questão 3:

Duvido que seja necessário carregar o banco de dados a cada chamada para \coords.

Questão 4:

Use o comando \DTLsetseparatorpara definir o separador de entradas de um banco de dados como vírgula, embora este seja o padrão. Portanto, isso provavelmente está obsoleto.