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.

Tacet
  • 143

1 Answers1

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

egreg
  • 1,121,712
  • 3
    I have the impression you're especially fond of ... Italy? ;-) –  Mar 04 '17 at 00:17
  • 3
    @ChristianHupfer Do you like the reference to the Black Forest? – egreg Mar 04 '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 –  Mar 04 '17 at 10:42
  • 2
    @Tacet You should first update your TeX system; I've used some recent features of expl3. – egreg Mar 04 '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 04 '17 at 19:48