\ href内で\ DTLfetchを使用する

Dec 04 2020

呼び出されたコマンドのパラメーターとして指定された場所に関連付けられた座標を指すGoogleマップURLを作成する新しいコマンドをLaTeXで作成しようとしています(一種の「テーブルルックアップ」関数)。場所と相対座標はcoords.CSVファイル内に保存されており、datatoolパッケージを使用して読み取る必要があります。

GoogleマップのURLは次のように構成する必要があります。

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

ここで<LAT>、および<LNG>coords.CSVファイルからロードされた緯度と経度の座標であり、次のように構成されています。

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

コマンドの定義方法は次のとおりです。

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

最後に、新しいコマンドを次のように使用します。

\coords{Test}

コマンド内で呼び出された場所(この場合は「テスト」)の座標を正しくロードできましたが、URLを生成しようとすると、LaTeXで多くのエラーが発生し、そのほとんどが! Undefined control sequenceです。URLが生成された行(コマンド定義内)を削除\LAT\LNGてもエラーは発生しませんが、もちろん、URLには座標が含まれていないため、座標は\LAT\LNG変数内に格納されます。

\hrefコマンド内で定義された変数を使用してURLを適切に生成する方法はありますか?

これはテスト例です:

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

回答

4 egreg Dec 04 2020 at 11:05

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

私が使用\jobname私のファイルをつかう避けるために。データベースには任意のファイル名を使用できます。

を呼び出すたびにではなく、データベースを1回ロードします\coords

3 UlrichDiez Dec 04 2020 at 12:34

次のアプローチをお勧めします。

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

コードにはいくつかの問題があるため、このアプローチをお勧めします。

問題1:

あなたの\coords-commandは、不要なスペーストークンと生産\par-tokensを:

これらの不要なトークンがどこで発生するかを示すコメントで書き直します。

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

問題2:

hyperref-manualは、のURL引数のトークンは\href完全に拡張可能でなければならないと述べています。

コマンド\LAT\LNGは完全に拡張可能ではありません。これは、その定義に制御ワードトークンが含まれているの\DTLfetchに対し、datatool-packageのマニュアルには次のように明記されているためです。

\DTLfetch{students}{regnum}{\RegNum}{forename}
に等しい

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

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

これは、マクロがによって定義される\DTLfetchため、 (したがって、ある段階で展開するとトークンが生成されるすべてのマクロ \DTLfetch)が完全に展開できない \dtlcurrentvalueことを示し \dtlgetentryfromcurrentrowます。

問題3:

を呼び出すたびにデータベースをロードする必要があるとは思えません\coords

問題4:

\DTLsetseparatorこれがデフォルトですが、データベースのエントリの区切り文字をコンマに設定するコマンドを使用します。したがって、これはおそらく廃止されています。