Używanie \ DTLfetch wewnątrz \ href
Próbuję utworzyć nowe polecenie w LaTeX, które tworzy adres URL mapy Google wskazujący na współrzędne związane z miejscem określonym jako parametr w wywołanym poleceniu (rodzaj funkcji „wyszukiwania tabeli”). Miejsca i współrzędne względne są przechowywane w coords.CSV
pliku i należy je odczytać przy użyciu datatool
pakietu.
Adres URL Map Google powinien mieć taką strukturę:
https://www.google.com/maps/?q=<LAT>,<LNG>
gdzie <LAT>
i <LNG>
są współrzędnymi szerokości i długości geograficznej załadowanymi z coords.CSV
pliku, który jest skonstruowany w ten sposób:
Place,LAT,LNG
Test,42.0000,42.0000
...
Oto jak zostało zdefiniowane polecenie:
\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}
}
Na koniec używam nowego polecenia w ten sposób:
\coords{Test}
Udało mi się poprawnie załadować współrzędne miejsca wywołanego wewnątrz polecenia (w tym przypadku „Test”), ale kiedy próbuję wygenerować adres URL, LaTeX daje mi wiele błędów, z których większość to ! Undefined control sequence
. Jeśli usunę \LAT
iz \LNG
wiersza, w którym generowany jest adres URL (wewnątrz definicji polecenia), nie otrzymam żadnego błędu, ale oczywiście adres URL nie zawiera żadnych współrzędnych, ponieważ są one przechowywane w zmiennych \LAT
i \LNG
.
Czy istnieje sposób na poprawne wygenerowanie adresu URL przy użyciu zmiennych zdefiniowanych w \href
poleceniu?
Oto przykład testowy:
\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}
Odpowiedzi
Możesz użyć tej samej sztuczki, co w mojej odpowiedzi, aby pobrać podciąg z `\ 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}
Kiedyś \jobname
unikałem zbombardowania moich plików. Możesz użyć dowolnej nazwy pliku dla bazy danych.
Załaduj bazę danych raz, a nie za każdym razem, gdy dzwonisz \coords
.
Proponuję następujące podejście:
\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}
Proponuję takie podejście, ponieważ z Twoim kodem jest kilka problemów:
Problem 1:
Twoje \coords
-polecenie produkuje niechciane tokeny \par
spacji i tokeny:
Piszę go ponownie z komentarzami wskazującymi, gdzie powstały te niechciane tokeny:
\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
}
Kwestia 2:
Hyperref-manual mówi, że tokeny w argumencie URL \href
muszą być w pełni rozwijalne.
Twoje polecenia \LAT
i \LNG
nie są w pełni rozszerzalne, ponieważ ich definicja zawiera token słowa kontrolnego, \DTLfetch
podczas gdy podręcznik pakietu narzędzi danych wyraźnie mówi, że
\DTLfetch{students}{regnum}{\RegNum}{forename}
jest równe
co oznacza, że\dtlgetrowforvalue{students}{\dtlcolumnindex{students}{regnum}}{\RegNum}%
\dtlgetentryfromcurrentrow{\dtlcurrentvalue}{\dtlcolumnindex{students}{forename}}% \dtlcurrentvalue
\DTLfetch
(a więc każde makro, którego rozwinięcie na pewnym etapie daje token
\DTLfetch
) nie jest w pełni rozszerzalne, ponieważ makro
\dtlcurrentvalue
jest definiowane przez
\dtlgetentryfromcurrentrow
.
Kwestia 3:
Wątpię, czy konieczne jest ładowanie bazy danych przy każdym wywołaniu \coords
.
Kwestia 4:
Polecenie służy \DTLsetseparator
do ustawiania separatora wpisów w bazie danych na przecinek, chociaż jest to ustawienie domyślne. Więc to prawdopodobnie jest przestarzałe.