Utiliser \ DTLfetch dans un \ href

Dec 04 2020

J'essaie de créer une nouvelle commande dans LaTeX qui crée une URL Google Map pointant vers les coordonnées associées à l'endroit spécifié comme paramètre dans la commande appelée (une sorte de fonction de «recherche de table»). Les lieux et les coordonnées relatives sont stockés dans un coords.CSVfichier et doivent être lus à l'aide du datatoolpackage.

L'URL de Google Map doit être structurée comme celle-ci:

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

<LAT>et <LNG>sont les coordonnées de latitude et de longitude chargées à partir du coords.CSVfichier, qui est structuré de cette manière:

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

Voici comment la commande a été définie:

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

Enfin, j'utilise la nouvelle commande de cette manière:

\coords{Test}

J'ai réussi à charger correctement les coordonnées de l'endroit appelé à l'intérieur de la commande (dans ce cas "Test"), mais quand j'essaye de générer l'URL, LaTeX me donne beaucoup d'erreurs, dont la plupart le sont ! Undefined control sequence. Si je supprime \LATet \LNGde la ligne où l'URL est générée (dans la définition de la commande), je n'obtiens aucune erreur, mais bien sûr l'URL ne contient aucune coordonnée, car elles sont stockées dans les variables \LATet \LNG.

Existe-t-il un moyen de générer correctement l'URL en utilisant les variables définies dans la \hrefcommande?

Ceci est un exemple de test:

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

Réponses

4 egreg Dec 04 2020 at 11:05

Vous pouvez utiliser la même astuce que dans ma réponse pour récupérer la sous-chaîne 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}

J'avais l'habitude \jobnamed'éviter de clobber mes fichiers. Vous pouvez utiliser le nom de fichier de votre choix pour la base de données.

Chargez la base de données une fois, pas à chaque appel \coords.

3 UlrichDiez Dec 04 2020 at 12:34

Je suggère l'approche suivante:

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

Je suggère cette approche car avec votre code, il y a quelques problèmes:

Problème 1:

Votre \coords-commande produit des jetons d'espace et des jetons \parindésirables:

Je le réécris avec des commentaires indiquant d'où viennent ces jetons indésirables:

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

Problème 2:

Le manuel hyperref dit que les jetons dans l'argument URL de \hrefdoivent être entièrement extensibles.

Vos commandes \LATet \LNGne sont pas entièrement extensibles car leur définition contient le jeton de mot de contrôle \DTLfetchalors que le manuel du datatool-package dit clairement que

\DTLfetch{students}{regnum}{\RegNum}{forename}
est égal à

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

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

ce qui indique que \DTLfetch(et donc chaque macro dont l'expansion à un certain stade produit le jeton \DTLfetch) n'est pas entièrement extensible car une macro \dtlcurrentvalueest définie par \dtlgetentryfromcurrentrow.

Problème 3:

Je doute qu'il soit nécessaire de charger la base de données à chaque appel à \coords.

Problème 4:

Vous utilisez la commande \DTLsetseparatorpour définir le séparateur des entrées d'une base de données sur une virgule bien qu'il s'agisse de la valeur par défaut. Donc, c'est probablement obsolète.