Utilizzando \ DTLfetch all'interno di un \ href

Dec 04 2020

Sto provando a creare un nuovo comando in LaTeX che crei un URL di Google Map che punta alle coordinate associate al luogo specificato come parametro nel comando chiamato (una sorta di funzione "table lookup"). I luoghi e le relative coordinate sono memorizzati all'interno di un coords.CSVfile e devono essere letti utilizzando il datatoolpacchetto.

L'URL di Google Map dovrebbe essere strutturato come questo:

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

dove <LAT>e <LNG>sono le coordinate di latitudine e longitudine caricate dal coords.CSVfile, che è strutturato in questo modo:

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

Ecco come è stato definito il 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}
}

Infine, utilizzo il nuovo comando in questo modo:

\coords{Test}

Sono riuscito a caricare correttamente le coordinate del luogo chiamato all'interno del comando (in questo caso "Test"), ma quando provo a generare l'URL, LaTeX mi dà molti errori, la maggior parte dei quali sono ! Undefined control sequence. Se rimuovo \LATe \LNGdalla riga in cui è generato l'URL (all'interno della definizione del comando), non ottengo alcun errore, ma ovviamente l'URL non contiene coordinate, poiché sono memorizzate all'interno delle variabili \LATe \LNG.

C'è un modo per generare correttamente l'URL utilizzando le variabili definite all'interno del \hrefcomando?

Questo è un esempio di prova:

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

Risposte

4 egreg Dec 04 2020 at 11:05

Puoi usare lo stesso trucco della mia risposta per recuperare la sottostringa di `\ 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}

Ero solito \jobnameevitare di distruggere i miei file. Puoi usare qualsiasi nome di file desideri per il database.

Carica il database una volta, non ogni volta che chiami \coords.

3 UlrichDiez Dec 04 2020 at 12:34

Suggerisco il seguente approccio:

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

Suggerisco questo approccio perché con il tuo codice ci sono alcuni problemi:

Problema 1:

Il tuo \coordscomando produce gettoni e gettoni spazio indesiderati \par:

Lo riscrivo con commenti che indicano dove vengono in essere questi token indesiderati:

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

Numero 2:

Il manuale hyperref dice che i token nell'argomento URL di \hrefdevono essere completamente espandibili.

I tuoi comandi \LATe \LNGnon sono completamente espandibili perché la loro definizione contiene la parola di controllo token \DTLfetchmentre il manuale del pacchetto datatool lo dice chiaramente

\DTLfetch{students}{regnum}{\RegNum}{forename}
è uguale a

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

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

che indica che \DTLfetch(e quindi ogni macro la cui espansione a un certo punto produce il token \DTLfetch) non è completamente espandibile quando una macro \dtlcurrentvalueviene definita da \dtlgetentryfromcurrentrow.

Problema 3:

Dubito che sia necessario caricare il database ad ogni chiamata a \coords.

Numero 4:

Si utilizza il comando \DTLsetseparatorper impostare il separatore per le voci di un database su virgola, sebbene questa sia l'impostazione predefinita. Quindi questo probabilmente è obsoleto.