Импорт параметров из отдельного файла

Импорт параметров из отдельного файла

Долго искал решение своей проблемы, но она, похоже, не поддавалась поиску через «google-eez»!

Вот моя проблема: у меня есть презентация Beamer, которую я представляю разным клиентам. Поскольку мне нравится настраивать эту презентацию под организацию каждого клиента, у меня есть несколько "кусков" кода, примерно по 10 строк каждый, в моем родительском файле Beamer .tex, которые загружают логотипы, устанавливают цвета, отображают названия организаций - все, что служит для "персонализации" презентации для конкретного клиента. Конечно, для каждой отдельной презентации клиента требуется, чтобы в указанный родительский документ .tex был вставлен еще один кусок кода из 10 строк. Как вы можете себе представить, через некоторое время эти "куски персонализации" запутывают указанный родительский документ .tex.

Я хотел бы создать отдельные файлы «данных», по одному для каждого клиента, которые содержали бы сведения, уникальные для каждого клиента (или, если возможно, хранитьвсеуказанные данные клиентов, извсеклиентов, водинокийФайл). Затем я хотел бы иметь возможность, используя одну строку в родительском документе .tex, извлечь данные настройки из соответствующего файла(ов) данных.

Выделенный курсивом текст был добавлен автором 16 февраля 2016 г.: Пожалуйста, имейте в виду, что я хочу иметь возможность по запросу создавать индивидуальную презентацию всего за несколько дней до ее проведения.

Что-то вроде:

\documentclass{beamer}
\usepackage{xcolor}

\newcommand{\nameoforg}{1st line from FileA.data}% Name of organization
\newcommand{\mainRGB}{2nd line from FileA.data}% Title color code
\newcommand{\backRGB}{3rd line from FileA.data}% Background color code
\newcommand{\clientlogowidth}{4th line from FileA.data}% Logo width
\newcommand{\clientlogo}{5th line from FileA.data}% Logo file name

\definecolor{mainslidecolor}{RGB}{\mainRGB}
\definecolor{backslidecolor}{RGB}{\backRGB}


\begin{document}

\title[\nameoforg]{Presentation Title}
\titlegraphic{\includegraphics[width=\clientlogowidth]{\clientlogo}}

\begin{frame}
this is boring
\end{frame}

\end{document}

ФайлA.txt, конечно, один из файлов "данных" (или, возможно,подошватакой файл, если это возможно), о котором я говорил выше.

Некоторые из моих исследований, казалось, указывали на то, что этот catchfileпакет был ответом на мои проблемы, но я не мог понять документацию к этому пакету.

Как это сделать? И возможно ли объединить все мои файлы "данных" в один файл (что мне бы очень хотелось сделать), или лучше хранить их отдельно, по одному на клиента?

решение1

Первоначально я упомянул об этом в комментарии, и меня попросили опубликовать это в качестве ответа.

Другой очень простой способ сделать это без других пакетов — просто иметь декларации \newcommandв своем собственном .texфайле и использовать \inputдля их загрузки. То есть:

% Name of organization
\newcommand{\nameoforg}{Organization A}
% Title color code
\newcommand{\mainRGB}{255,0,0}
% Background color code
\newcommand{\backRGB}{255,255,255}
% Logo width
\newcommand{\clientlogowidth}{6cm}
% Logo file name
\newcommand{\clientlogo}{example-image-a}

в clientA.texи аналогично для других клиентов. Затем это можно загрузить с помощью простого \input{clientA.tex}:

\documentclass{beamer}
\usepackage{mwe}

\input{clientA.tex}

\definecolor{mainslidecolor}{RGB}{\mainRGB}
\definecolor{backslidecolor}{RGB}{\backRGB}

\title[\nameoforg]{Presentation Title}
\titlegraphic{\includegraphics[width=\clientlogowidth]{\clientlogo}}

\begin{document}
\begin{frame}
  \maketitle
\end{frame}

\begin{frame}
  Hello, World!
\end{frame}
\end{document}

Как показали другие, это можно расширить с помощью скрипта для массового производства слайдов, хотя Digger, похоже, требует создания только одного набора слайдов за раз.

решение2

Я бы использовал для этого скрипт оболочки и определил бы имя файла \inputдля каждого клиента в скрипте, а затем передал бы его команде pdflatex(или любому другому движку, который вы используете).

Вот пример. Для каждого клиента создайте .texфайл, содержащий соответствующие определения для этого клиента. Вот три примера файлов:

клиентA.tex

\newcommand\clientname{Client A}
\newcommand\clienttheme{EastLansing}

клиентB.tex

\newcommand\clientname{Client B}
\newcommand\clienttheme{Madrid}

клиентC.tex

\newcommand\clientname{Client C}
\newcommand\clienttheme{Bergen}

Первая строка вашего client-presentation.texфайла (до \documentclass) будет содержать строку:

\InputIfFileExists{\clientfile}{}{\typeout{\detokenize{\clientfile}\ not found!}}

Файл презентации

\InputIfFileExists{\clientfile}{}{\typeout{\detokenize{\clientfile}\ not found!}}
\documentclass{beamer}
\usetheme{\clienttheme}
\title{My Presentation}
\author{Prepared for:\\\clientname}
\date{}
\begin{document}
\begin{frame}[plain]
\maketitle
\end{frame}
\begin{frame}
\begin{block}{This is a block}
\begin{itemize}
\item An item
\end{itemize}
\end{block}
\end{frame}
\end{document}

Затем в командной строке мы определяем \clientfileи передаем его в pdflatex. Вот как будет выглядеть один файл:

pdflatex "\def\clientfile{clientA}\input{client-presentation}"

Это создаст client-presentation.pdfкоманды, как определено в clientA.tex.

Одноразовый скрипт оболочки

Теперь мы можем создать простой скрипт оболочки, который берет базовое имя клиентского файла и базовое имя файла презентации, а затем создает документ для этого клиента. Поскольку возможно, что документу может потребоваться более одной компиляции для разрешения ссылок и т. д., я использовал latexmkдля выполнения компиляции. Это гарантирует, что в большинстве случаев документ будет скомпилирован правильно.

#!/bin/sh
#Usage: first argument = client file base name, second = latex document base
latexmk -pdf -silent    \
        -jobname="$1_$2" \
        -pdflatex="pdflatex --file-line-error --shell-escape --synctex=1 %O '\def\clientfile{$1}\input{%S}'" $2.tex

Скрипт оболочки для автоматизации

Теперь при необходимости мы можем автоматизировать создание нескольких клиентских файлов одновременно.

#!/bin/sh
#Usage: pass the basename of the presentation file as an argument
for f in client*.tex; do
basefile=$(basename "$f")
if [ "${basefile%.*}" != "$1" ]
then
latexmk -pdf     \
        -jobname="${basefile%.*}_$1" \
        -pdflatex="pdflatex --file-line-error --shell-escape --synctex=1 %O '\def\clientfile{${basefile%.*}}\input{%S}'" $1.tex
fi
done

Этот скрипт оболочки принимает базовое имя файла презентации в качестве аргумента и генерирует отдельные PDF-файлы для каждого clientX.texфайла в текущем каталоге.

Пример вывода:

введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь

решение3

Вы можете рассмотреть подход интерфейса ключ-значение. Это менее хрупко, поскольку ключи могут быть указаны в любом порядке, а не обязательно должны быть на определенных строках.

Кроме того, пакеты «ключ-значение» позволяют указывать значения по умолчанию, если определенные данные отсутствуют для определенных клиентов, или обеспечивать обратную совместимость, если вы добавите больше ключей в будущем. С некоторыми пакетами «ключ-значение» вы можете пометить определенные ключи какнеобходимыйили всякие другие вещи. По сути, это добавляет большую гибкость.

Вот простой пример подхода. СмотретьБольшой список всех пакетов keyvalдля описания пакетов и статьи TUGboatРеализация ввода ключ-значение: введение кДжозеф РайтиКристиан Фойерзенгердля ознакомления с идеями и возможностями интерфейсов «ключ-значение».

\RequirePackage{filecontents}
\begin{filecontents*}{clientA.data}
\diggersetup{
  orgname = First Organization,
  mainRGB = {1,0,0},
  backRGB = {0,0,1},
  clientlogowidth = 1in,
  clientlogo = example-image-a,
}
\end{filecontents*}
\begin{filecontents*}{clientB.data}
\diggersetup{
  orgname = Second Organization,
  mainRGB = {1,1,0},
  backRGB = {0,1,0},
  clientlogowidth = 1.5in,
  clientlogo = example-image-b,
}
\end{filecontents*}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\documentclass{beamer}
\usetheme{Boadilla}

\usepackage{lmodern} % no font substitution warnings
\usepackage{graphicx}
\usepackage{keyval} % or your favorite key-value package of the month

\makeatletter
\newlength\clientlogowidth
\define@key{digger}{orgname}{\def\nameoforg{#1}}
\define@key{digger}{mainRGB}{\definecolor{mainslidecolor}{RGB}{#1}}
\define@key{digger}{backRGB}{\definecolor{backslidecolor}{RGB}{#1}}
\define@key{digger}{clientlogo}{\def\clientlogo{#1}}
\define@key{digger}{clientlogowidth}{\setlength\clientlogowidth{#1}}
\setkeys{digger}{ % default key settings
  orgname = No Name!, 
  mainRGB = {1,1,1}, 
  backRGB = {1,0,1}, 
  clientlogo = example-image, 
  clientlogowidth = 1in,
}
\newcommand{\diggersetup}[1]{\setkeys{digger}{#1}}
\makeatother

%-------------------------------------
\input{clientA.data}
%\input{clientB.data}
%-------------------------------------

\begin{document}

\title[\nameoforg]{Presentation Title}
\titlegraphic{\includegraphics[width=\clientlogowidth]{\clientlogo}}

\begin{frame}
\titlepage
\end{frame}

\begin{frame}
this is boring
\end{frame}
\end{document}

введите описание изображения здесь

решение4

Вот простой пример того, как можно использовать textmerg. Предполагая, что вы знаете, какие переменные вам нужны в каждом случае, вы можете создать отдельный файл для каждой компании, а затем «объединить» его с вашим документом. Итак, учитывая этот файл (называемый, скажем, textmerg-example.dat)

FooCo Inc.
rose
whale
serif
4cm
example-image

Затем вы настраиваете файл проектора следующим образом:

\documentclass{beamer}%
\usepackage{mwe}% to get "example-image" named in .dat file
\usepackage{textmerg}
% the "Fields" are read and assigned in the order of the .dat file
\Fields{
\nameoforg
\myinnertheme
\myoutertheme
\myfonttheme
\clientlogowidth
\clientlogo
}
% Load the specific options
\Merge{textmerg-example.dat}{}% <-- note the second argument is empty because we are looping anything.

\usecolortheme{\myinnertheme}
\usecolortheme{\myoutertheme}
\usefonttheme{\myfonttheme}
\title[\nameoforg]{Presentation Title}
\titlegraphic{\includegraphics[width=\clientlogowidth]{\clientlogo}}


\begin{document}
\maketitle

\begin{frame}
\frametitle{Some Frame Title}

\nameoforg: This is boring\ldots
\end{frame}

\end{document}

Очевидно, вам придется каждый раз тщательно обдумывать, что именно вы захотите изменить.

РедактироватьЕсли вы хотите создать много файлов одновременно, используя другой набор переменных, то вы можете изменить приведенный выше пример. Возьмем два .datфайла: 1-textmerg.datи 2-textmerg.dat:

FooCo Inc.
rose
whale
serif
4cm
example-image

и

SOME COMPANY
orchid
seahorse
default
7cm
example-image

Затем мы изменяем указанный выше файл проектора следующим образом:

% main.tex
\documentclass{beamer}%
\usepackage{mwe}% to get "example-image" named in .dat file
\usepackage{textmerg}
% the "Fields" are read and assigned in the order of the .dat file
\Fields{
\nameoforg
\myinnertheme
\myoutertheme
\myfonttheme
\clientlogowidth
\clientlogo
}
% Hack: we don't want to loop the file, so we leave the second argument empty
\providecommand{\tmdatanum}{1}% set a default input file
\Merge{\tmdatanum-textmerg.dat}{}
\usecolortheme{\myinnertheme}
\usecolortheme{\myoutertheme}
\usefonttheme{\myfonttheme}
\title[\nameoforg]{Presentation Title}
\titlegraphic{\includegraphics[width=\clientlogowidth]{\clientlogo}}


\begin{document}

\maketitle

\begin{frame}
\frametitle{Some Frame Title}

\nameoforg: This is boring\ldots

I have used \textbf{\myinnertheme\ \& \myoutertheme} as the inner and outer themes, with this as the client logo: \texttt{\clientlogo}.

\end{frame}

\end{document}

Теперь, чтобы создать все различные PDF-файлы за один раз, мы могли бы использовать что-то вроде:

for num in {1..2} ; do pdflatex -jobname=$num-beamer "\def\tmdatanum{$num}\input{main.tex}" ; done

Это выбирает (включительно) файлы, которые начинаются в диапазоне «между» 1 и 2, назначает им соответствующее имя 1-или 2-beamerдля вывода, определяет команду \tmdatanum, которая используется в нашей нециклической \Mergeкоманде, а затем вводит основной файл проекта, main.tex. Результатом должны быть два отдельных файла с настройками, названными в двух разных .datфайлах.

В качестве альтернативы можно создать скрипт оболочки (называемый, скажем, mergit) следующим образом:

#!/bin/bash
#
# Usage: mergit [FILE] [Highest input file num]
#
MASTERFILE=$1
ENDNUMBER=$2
#
for ((num=1;num<=ENDNUMBER;num++))
do
  pdflatex -jobname=$num-beamer "\def\tmdatanum{$num}\input{$MASTERFILE.tex}"
done

Таким образом, mergit main 2будут созданы два PDF-файла, как в однострочном примере выше.

Связанный контент