4

I'm trying to learn LaTeX and I'm creating something like city encyclopedia. So I made commands like \printcity{country}{city_name} or \createcity{country/city_name}{Long city description.}. It works quite nice. Solution is based on topic What is the recommended way to assign a value to a variable and retrieve it for later use?. But now I have to type

\printcity{Italy}{Florence}
\printcity{Poland}{Warsaw}
\printcity{country_name}{other_city}

So, it's not really comfortable. Especially that I really want to have it in lexicographical order. But I have no idea, how I can print all values. As minimal code example can be helpful, assume that my code is like:

\documentclass{article}
\usepackage{pgfkeys}
\usepackage[utf8]{inputenc}
\usepackage{polski}
\usepackage[polish]{babel}

\newcommand{\setvalue}[1]{\pgfkeys{/variables/#1}}
\def\createcity#1#2{\setvalue{#1 = #2}}

\newcommand{\getvalue}[1]{\pgfkeysvalueof{/variables/#1}}
\def\printcity#1#2{\subsubsection*{#2} \getvalue{#1/#2}}

\newcommand{\declarecountry}[1]{%
 \pgfkeys{
 /variables/#1.is family,
 /variables/#1.unknown/.style = {\pgfkeyscurrentpath/\pgfkeyscurrentname/.initial = ##1}
 }%
}

\declarecountry{Poland/}

\createcity{Poland/Warsaw}{Capital rebuilt after WWII.}
\createcity{Poland/Cracow}{Second largest and one of the oldest cities in Poland.}
\createcity{Poland/Toruń}{The medieval old town of Toruń is the birthplace of Polish astronomer Nicolaus Copernicus.}


\begin{document}
    \printcity{Poland}{Toruń}
    \printcity{Poland}{Cracow}
    \printcity{Poland}{Warsaw}
\end{document}

enter image description here

But how can I print all cities form Poland in lexicographical order? (I don't know how to print all in any order. So, please include that in your answer.)

I'm using PDFLaTeX.

3

Don't tell Joseph.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\declarecountry}{m}
 {
  \prop_new:c { g_tacet_cities_#1_prop }
 }
\NewDocumentCommand{\createcity}{mmm}
 {
  \prop_gput:cnn { g_tacet_cities_#1_prop } { #2 } { #3 }
 }
\NewDocumentCommand{\printcity}{mm}
 {
  #2,~#1:~\prop_item:cn { g_tacet_cities_#1_prop } { #2 }
 }
\NewDocumentCommand{\printcities}{m}
 {
  \tacet_cities_print:n { #1 }
 }

\seq_new:N \l__tacet_cities_country_seq

\cs_new_protected:Nn \tacet_cities_print:n
 {
  \seq_clear:N \l__tacet_cities_country_seq
  \prop_map_inline:cn { g_tacet_cities_#1_prop }
   {
    \seq_put_right:Nx \l__tacet_cities_country_seq { ##1 }
   }
   \seq_sort:Nn \l__tacet_cities_country_seq
    {
     \tacet_city_if_before:nnTF { ##1 } { ##2 }
      { \sort_return_same: }
      { \sort_return_swapped: }
    }
   \section{#1}
   \seq_map_inline:Nn \l__tacet_cities_country_seq
    {
     \noindent
     ##1:~\prop_item:cn { g_tacet_cities_#1_prop } { ##1 }
     \par
    }
 }
\prg_new_conditional:Nnn \tacet_city_if_before:nn { p,T,F,TF }
 {% I hope the LaTeX3 police won't catch me
  \int_compare:nTF { \pdftex_strcmp:D { #1 } { #2 } < 0 }
   {
    \prg_return_true:
   }
   {
    \prg_return_false:
   }
 }
\ExplSyntaxOff

\begin{document}

\declarecountry{Italy}
\createcity{Italy}{Venice}{Some facts about Venice}
\createcity{Italy}{Milan}{Some facts about Milan}
\createcity{Italy}{Florence}{Some facts about Florence}
\createcity{Italy}{Rome}{Some facts about Rome}

\printcity{Italy}{Venice}

\printcities{Italy}

\end{document}

enter image description here

A bit more complicated

Cities in different countries tend to have bizarre accents over them and the above code wouldn't work with them.

Here's an extended version, where for cities with diacritics in their name, you need to supply also a key for sorting and calling (see the Düsseldorf) example.

\documentclass{article}
\usepackage[utf8]{inputenc}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\declarecountry}{m}
 {
  \seq_new:c { g_tacet_cities_#1_seq }
 }
\NewDocumentCommand{\createcity}{mmm}
 {
  \tacet_cities_create:nnn { #1 } { #2 } { #3 }
 }
\NewDocumentCommand{\printcity}{mm}
 {
  \prop_item:cn { g_tacet_cities_city_#1/#2_prop } { name }
  ,~
  #1:~
  \prop_item:cn { g_tacet_cities_city_#1/#2_prop } { text }
 }
\NewDocumentCommand{\printcities}{m}
 {
  \tacet_cities_print:n { #1 }
 }

\prop_new:N \l__tacet_cities_temp_prop
\tl_new:N \l__tacet_cities_temp_tl
\seq_new:N \l__tacet_cities_country_seq

\keys_define:nn { tacet/cities }
 {
  name    .code:n = \prop_put:Nnn \l__tacet_cities_temp_prop { name } { #1 },
  key     .code:n = \prop_put:Nnn \l__tacet_cities_temp_prop { key } { #1 },
  unknown .code:n = \prop_put:NnV \l__tacet_cities_temp_prop { name } \l_keys_key_tl,
 }

\cs_new_protected:Nn \tacet_cities_create:nnn
 {
  \prop_clear:N \l__tacet_cities_temp_prop
  \keys_set:nn { tacet/cities } { #2 }
  \prop_if_in:NnTF \l__tacet_cities_temp_prop { key }
   {
    \prop_get:NnN \l__tacet_cities_temp_prop { key } \l__tacet_cities_temp_tl
   }
   {
    \prop_get:NnN \l__tacet_cities_temp_prop { name } \l__tacet_cities_temp_tl
    \prop_put:NnV \l__tacet_cities_temp_prop { key } \l__tacet_cities_temp_tl
   }
  \seq_gput_right:cV { g_tacet_cities_#1_seq } \l__tacet_cities_temp_tl
  \prop_put:Nnn \l__tacet_cities_temp_prop { text } { #3 }
  \prop_new:c { g_tacet_cities_city_#1/\l__tacet_cities_temp_tl _prop }
  \prop_gset_eq:cN
   { g_tacet_cities_city_#1/\l__tacet_cities_temp_tl _prop }
   \l__tacet_cities_temp_prop
 }

\cs_new_protected:Nn \tacet_cities_print:n
 {
  \seq_set_eq:Nc \l__tacet_cities_country_seq { g_tacet_cities_#1_seq }
  \seq_sort:Nn \l__tacet_cities_country_seq
   {
    \tacet_city_if_before:nnTF { ##1 } { ##2 }
     { \sort_return_same: }
     { \sort_return_swapped: }
   }
  \section{#1}
  \seq_map_inline:Nn \l__tacet_cities_country_seq
    {
     \noindent
     \prop_item:cn { g_tacet_cities_city_#1/##1_prop } { name }
     :~
     \prop_item:cn { g_tacet_cities_city_#1/##1_prop } { text }
     \par
    }
 }
\prg_new_conditional:Nnn \tacet_city_if_before:nn { p,T,F,TF }
 {% I hope the LaTeX3 police won't catch me
  \int_compare:nTF { \pdftex_strcmp:D { #1 } { #2 } < 0 }
   {
    \prg_return_true:
   }
   {
    \prg_return_false:
   }
 }
\ExplSyntaxOff

\begin{document}

\declarecountry{Italy}
\createcity{Italy}{Venice}{Some facts about Venice}
\createcity{Italy}{Milan}{Some facts about Milan}
\createcity{Italy}{Florence}{Some facts about Florence}
\createcity{Italy}{Rome}{Some facts about Rome}

\declarecountry{Germany}
\createcity{Germany}{Furtwangen}{A town in the Black Forest}
\createcity{Germany}{Bielefeld}{Does it exist?}
\createcity{Germany}{Berlin}{A big city}
\createcity{Germany}{Darmstadt}{Hosted the TUG Conference}
\createcity{Germany}{
  name=Düsseldorf,
  key=Dusseldorf,
}{This has the \emph{umlaut}}

\printcity{Italy}{Venice}

\printcity{Germany}{Dusseldorf}% the key!

\printcities{Italy}

\printcities{Germany}

\end{document}

enter image description here

  • 3
    I have the impression you're especially fond of ... Italy? ;-) – user31729 Mar 4 '17 at 0:17
  • 3
    @ChristianHupfer Do you like the reference to the Black Forest? – egreg Mar 4 '17 at 10:28
  • Oh yes, Furtwangen is very near to me, but I can't upvote more than once ;-) But I won't tell Joseph :D – user31729 Mar 4 '17 at 10:42
  • 2
    @Tacet You should first update your TeX system; I've used some recent features of expl3. – egreg Mar 4 '17 at 11:13
  • @egreg it works perfectly, thanks for your effort and for that I learned today few TeX things thanks to you. – Tacet Mar 4 '17 at 19:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.