LXP
ПРИМЕЧАНИЕ
LXP — коммерческий продукт, разработанный авторами этой книги. Пакет не распространяется на условиях открытых исходных текстов. На компакт-диске имеется пробная версия LXP.
LXP (или mod_lxp) представляет собой сервер приложений, спроектированный в виде модуля Apache. LXP обеспечивает динамическое форматирование данных HTML в процессе, который называется серверным включением (server-side inclusion) и объединяет данные HTML, полученные из разных источников — исходных файлов HTML, файлов XML, сценарных языков (таких, как РНР и Perl) и даже из баз данных PostgreSQL.
Все операции по включению данных выполняются исключительно на сервере, что гарантирует одинаковый результат, не зависящий от браузера. Предполагалось, что по логичности, по степени интеграции и широте возможностей LXP превзойдет все существующие технологии включения данных, что в значительной степени обусловлено уникальной методикой разметки и непосредственным выполнением запросов PostgreSQL
В LXP используется уникальная форма программных тегов разметки, которые
перед отправкой клиенту интерпретируются сервером и преобразуются в стандартный
вывод HTML. Хотя эти теги называются программными, они принципиально отличаются от сценарных языков типа РНР или Perl, поскольку их реализация построена на тех же базовых концепциях, которые заложены в основу HTML и XML.
Одной из целей, поставленных при разработке LXP, было сохранение синтаксиса и методологии размеченных документов. Документ LXP должен быть в общих чертах понятен любому, кто знает язык HTML, пусть даже смысл дополнительных тегов может быть не очевиден. При этом опытные программисты могут использовать нетривиальные возможности, присущие информационной модели LXP.
Преимущества LXP
LXP позволяет легко строить web-сайты с расширенными возможностями, не прибегая к языку программирования. Если вы умеете пользоваться разметкой, то без особого труда освоите реализацию динамического наполнения сайта в LXP.
Кроме того, интеграция LXP с PostgreSQL упрощает операции с базами данных при наполнении сайта. При выполнении логических операции с итоговыми наборами традиционно приходилось использовать PHP, Perl или компилируемые языки C/C++. В LXP эта задача решается без применения внешних языков.
LXP позволяет применить весь арсенал PostgreSQL (пользовательские функции, триггеры ц процедурные языки — такие, как PL/pgSQL) при реализации логики обработки данных. Большинство простых задач в LXP решается без применения сложных языков программирования. Даже математические операции, вычисления с датой и временем и сложное форматирование строк реализуется в LXP через подключение к PostgreSQL.
Хотя эта простота является сильной стороной LXP, при написании многих функций нужны (или просто предпочтительны) более специализированные решения. Если в каком-либо компоненте сайта вам потребуется мощь современного языка программирования, воспользуйтесь методами LXP Apache и URI, позволяющими включить в выходные данные LXP документ произвольного типа.
Базовые возможности
К числу базовых возможностей LXP относится включение внешних файлов, лексический разбор кода XML и прямой интерфейс между SQL и PostgreSQL. В версии 0.8 команды SQL выполняются через динамическое или устойчивое подключение к СУБД PostgreSQL.
В LXP также поддерживаются современные средства, обычно встречающиеся в языках программирования, — механизмы работы с переменными, вставки и подстановки, массивы, условные команды, циклы и базовый интерфейс форматирования строковых данных с поиском и заменой.
Включение данных
Основная концепция включения данных заключается в том, что в выходные данные запрашиваемого документа HTML могут включаться другие файлы или источники данных. Например, при включении в документ LXP другого файла выходные данные этого файла подставляются в поток данных так, словно они были частью исходного документа. Тем самым повышается эффективность и удобство сопровождения больших динамических web-сайтов.
Непосредственно в LXP предусмотрена поддержка разнообразных внешних файлов, от простого кода HTML до XML и неструктурированных («плоских») файлов, разделяемых при помощи специальных лексем. Тем не менее одна из самых сильных сторон технологии включения заключается в том, что LXP позволяет внедрять любые типы содержимого, указанные в конфигурации web-сервера Apache.
В предыдущих версиях LXP поддержка сценариев РНР была весьма ограниченной. В LXP версии 0.8 поддерживается включение любого информационного наполнения посредством подзапросов Apache. Это позволяет включать на стороне сервера документы, написанные на разных языках, в том числе PHP, Perl и любых исполняемых приложений CGI. Аргументы CGI и переменные LXP передаются включаемому документу так, словно он был вызван напрямую с передачей этих переменных в запросе HTTP.
В LXP также используется библиотека expat, предназначенная для лексического разбора XML без проверки по содержимому DTD. То есть обрабатываемый код проверяется, по крайней мере, на лексическую правильность (то есть па содержание недопустимых символов, непарных тегов и т. д.)
При реализации модуля лексического разбора для LXP особое внимание уделялось простой поддержке форматов RSS/RDF (Rich Site Summary и Resource Description Framework). Эти форматы поддерживаются многими популярными сайтами и обеспечивают краткую сводку по информации, предоставляемой сайтом (например, заголовки и URL-адреса на сайте новостей).
В настоящее время поддержка XML в LXP развивается и приобретает более общий характер, но и сейчас она до определенной степени может использоваться с любым нормально сформированным кодом XML.
Взаимодействие с PostgreSQL
В LXP поддерживаются как динамические, так и устойчивые подключения к PostgreSQL, благодаря чему выполнение команд SQL становится более гибким. Метод включения SQL позволяет выполнять запросы прямо из документов LXP. После выполнения запроса его результаты передаются модулю лексического разбора LXP для внутреннего форматирования. Полученные-значения выводятся в документе или сохраняются в переменных для дальнейшего использования.
Устойчивые соединения, внутреннее форматирование и теги запросов SQL обеспечивают LXP непревзойденную простоту при работе с информацией, полученной из базы данных. Пример использования средств LXP для работы с базой данных встречается в пакете Fingerless — простой и гибкой реализацией журнала ссылок на базе LXP.
Fingerless
Пакет Fingerless, впервые появившийся в LXP версии 0.7, представляет собой систему для ведения журнала ссылок (weblog) на базе LXP. Аналогичные системы применяются на таких сайтах, как Slashdot.org и Kuro5bin.org.
В версии 0.8 реализация Fingerless была переработана во внешний пакет, использующий общие теги LXP и устойчивые подключения. По этой причине в документации не рассматриваются устаревшие встроенные методы Fingerless, которые будут устранены из ядра LXP в следующей версии. Пример web-сайта, использующего Fingerless, можно найти по адресу http://www.thelinuxreview.com.
Установка и настройка LXP
Чтобы установить LXP, необходимо предварительно установить и настроить web-сервер Apache с поддержкой mod_so (модуль общих объектов Apache). Если при конфигурировании Apache этот модуль не использовался, компиляцию придется провести заново с ключом --enable-module=so.
ПРИМЕЧАНИЕ
Если вы предпочитаете компилировать Apache вручную, не забудьте сначала удалить все существующие модули RPM Apache. Обычно их можно найти командой грго -qa | grep apache.
Если сервер Apache установлен, а в нем включена поддержка модуля общих объектов, вставьте в дисковод прилагаемый к книге компакт-диск, смонтируйте его и переходите к установке. Для успешной установки LXP необходимы права root, поскольку в процессе установки потребуется доступ к системным файлам и каталогам.
Установка LXP
В версии 0.8 существует два варианта установки LXP. Во-первых, можно воспользоваться сценарием Ixpinstall.sh, находящимся в каталоге 1хр на компакт-диске; во-вторых, пакет можно установить вручную. Сценарий Ixpinstall.sh устанавливает необходимые файлы LXP и вносит в файл httpd.conf изменения, обеспечивающие загрузку модуля LXP.
Если в процессе выполнения сценария Ixpinstall.sh возникнут какие-либо ошибки, обратитесь к приведенному ниже описанию ручной установки.
Сценарий Ixpinstall.sh
Сценарий Ixpinstall.sh работает весьма прямолинейно. При первом запуске вам придется ответить всего на один вопрос — в конце сценария будет предложено автоматически перезапустить Apache (это необходимо для активизации LXP). Если в процессе установки возникнут ошибки, сценарий можно запустить заново, хотя на этот раз он потребует подтверждения на перезапись некоторых файлов.
В листинге 13.1 команда cd переходит в каталог 1хр компакт-диска (в данном примере смонтированного в каталоге /mnt/cdrom), после чего запускается файл Ixpinstall.sh.
Листинг 13.1. Установка LXP сценарием Ixpinstall.sh
[root@host root]# cd /mnt/cdrom/lxp
[root@host lxp]# .Ixpiinstall.sh
=======================
Thank you for installing Command Prompt LXP. 0.8.0.
Copyright (c) 1999-2001. Command Prompt. Inc.
See the LICENSE file for licensing restrictions.
========================
[cmd] Checking for PostgreSQL libs (this may take a moment) ...
[cmd] Found PostgreSQL libpq library.
[cmd] Using apxs: '/usr/local/apache/bin/apxs'
[cmd] Using '/usr/local/apache/1ibexec/' for shared object file
========================
[cmd] Installing 'liblxp.so'
[activating module 'Ixp' in /usr/local/apache/conf/httpd.conf]
cp lib/liblxp.so /usr/local/apache/libexec/liblxp.so
chmod 755 /usr/local/apache/libexec/liblxp.so
cp /usr/local/apache/conf/httpd.conf /usr/local/apache/conf/httpd.conf.bak
cp /usr/local/apache/conf/httpd.conf.new /usr/local/apache/conf/httpd.conf
rm /usr/local/apache/conf/httpd.conf.new
[cmd] Using '/usr/local/apache/conf/httpd.conf for configuration
[cmd] Backing up original configuration file...
/usr/1 ocal /apache/conf/httpd.conf -> /usr/1ocal/apache/conf/httpd.conf.1xp_backup
[and] Backing up original configuration file...
/usr/local /apache/conf/srm.conf -> /usr/local/apache/conf/srm.conf.lxp_backup
[cmd] Adding LXP directives to httpd.conf...
===========================
[cmd] Installing 'Ixp.conf into /usr/1ocal/end/etc ...
conf/lxp.conf-dist -> /usr/local/cmd/etc/lxp.conf
============================
[cmd] Re-start Apache with '/usr/local/apache/bin/apachectl'? (y/n) у
/usr/local/apache/bin/apachectl stop: httpd stopped
/usr/local/apache/bin/apachectl start: httpd started
[cmd] Command Prompt LXP 0.8.0 successfully installed.
ПРИМЕЧАНИЕ
Если у вас возникнут проблемы с редактированием файла httpd.conf, не забудьте, что LXP перед внесением изменений создает резервную копию исходной конфигурации в файле с именем httpd.conf.lxp_backup, который находится в одном каталоге с исходным файлом httpd.conf.
При запуске сценария Ixpinstall.sh может появиться следующее сообщение об ошибке:
[cmd] ERROR: LXP requires Apache be configured with Shared Object support,
[cmd] but we couldn't find Apache's apxs script.
[cmd] Please make sure it Is in your path. If you know mod_so is enabled,
[cmd] exit error 1
Ошибка означает, что в системе не найден файл apxs (Apache Extension). Обычно этот файл находится в каталоге /usr/local/apache/bin, однако он может отсутствовать, если web-сервер Apache не был построен с поддержкой mod_so или если в системе не был установлен пакет RPM apache-devel. Если вы точно знаете, что файл присутствует в системе, убедитесь в том, что каталог, в котором он находится, входит в переменную среды PATH.
Также возможно сообщение об ошибке следующего вида:
[cmd] ERROR: apxs couldn't find your configuration file
[cmd] (Tried /usr/local/apache/conf/httpd.conf)
[cmd] exit error 3
Если вместо httpd.conf используется конфигурационный файл с нестандартным именем, вам придется произвести настройку вручную. Инструкции приведены в следующем пункте.
Ручная установка
В этом пункте рассказано, как установить LXP вручную, когда установка с использованием сценария Ixpinstall.sh не удалась. Если пакет LXP успешно установлен, этот пункт можно пропустить.
Ручная установка LXP состоит из трех этапов.
Установка общего модуля LXP. Установка конфигурационного файла LXP. Настройка файла Apache httpd.conf.Установка и настройка LXP 371
Файл liblxp.so (находится в каталоге /Ixp/lib на компакт-диске) следует скопировать в каталог, из которого web-сервер Apache загружает внешние модули. Обычно это каталог /usr/local/apache/libexec для ручной установки Apache или каталог /etc/httpd/modules для установки RPM. Учтите, что каталоги меняются, и в вашей поставке они могут быть другими. Тем не менее файл можно установить в нужный каталог при помощи сценария apxs. Команда выглядит следующим образом:
apxs -i -n модуль -а файл
В листинге 13.2 приведен пример использования сценария apxs для установки и настройки файла liblxp.so в каталог модулей Apache.
Листинг 13.2. Ручная установка файла liblxp.so
[root@host lib]# apxs -i -n "Ixp" -a lib/liblxp.so
cp lib/liblxp.so /usr/local/apache/libexec/liblxp.so
chmod 755 /usr/local/apache/libexec/liblxp.so
[activating module 'Ixp' in /usr/local/apache/conf/httpd.conf]
[root@host lib]#
Если пакет PostgreSQL не установлен, файл libpq.so.2.2 (также находящийся в каталоге /Ixp/lib на компакт-диске) копируется в каталог /usr/local/cmd/lib. Кроме того, следует создать символическую ссылку 1 ibpg. so. 2, указывающую на этот файл. Если сценарий Ixpinstall.sh не запускался, возможно, вам придется создать этот каталог. Процесс продемонстрирован в листинге 13.3.
Листинг 13.3. Ручная установка libpq.so.2.2
[root@host lib]# mkdir -p /usr/local/cmd/lib
[root@host lib]# cp -iv libpq.so.2.2 /usr/local/cmd/lib/
libpq.so.2.2 -> /usr/local/cmd/lib/libpq.so.2.2
[root@host lib]# In -s /usr/local/cmd/lib/libpq.so.2.2
/usr/local/cmd/lib/libpq.so.2
[root@host lib]#
На втором этапе файл Ixp.conf устанавливается в каталог /usr/local/cmd/etc. Это конфигурационный файл LXP 0.8, подробно описанный в следующем подразделе. В поставке LXP конфигурационный файл находится в каталоге /Ixp/conf на компакт-диске и хранится под именем Ixp.conf-dist. Скопируйте этот файл из каталога /Ixp/conf на компакт-диске в каталог/usr/local/cmd/etc, как показано в листинге 13.4. Если сценарий Ixpinstall.sh ранее не выполнялся, возможно, вам придется создать этот каталог. Не забудьте переименовать файл Ixp.conf-dist в Ixp.conf!
Листинг 13.4. Ручная установка Ixp.conf
[root@host lxp]# mkdir -p /usr/local/cmd/etc
[root@host lxp]# cp -v conf/lxp.conf-dist /usr/local/cmd/etc/lxp.conf
conf/lxp.conf-dist -> /usr/local/cmd/etc/lxp.conf
[root(?host lxp]#
Остается лишь настроить файл Apache httpd.conf для работы с содержимым типа LXP.
ВНИМАНИЕ
Иногда файл httpd.conf сохраняется под другим именем (например, как в ApacheSSL, httpsd.conf).
Для правильной настройки LXP в файл httpd.conf следует включить две строки, приведенные в листинге 13.5.
Листинг 13.5. Настройка файла http.conf для LXP
DirectoryIndex index.html index.Ixp
AddType application/x-httpd-lxp .Ixp
В файле httpd.conf уже должна присутствовать строка, похожая на первую строку в листинге 13.5. Включите index.Ixp в значение этой директивы, если вы хотите, чтобы при запросе каталога модуль Apache автоматически искал индекс LXP.
Второй строки в первоначальной конфигурации быть не должно. Директива /\ddType должна выглядеть в точности так, как показано в листинге 13.5. Она указывает, что файлы с расширением .Ixp должны обрабатываться модулем LXP.
В общем случае эти директивы могут располагаться в произвольной позиции файла httpd.conf, хотя обычно для логического упорядочения файла их размещают рядом с другими директивами с похожими именами.
Завершив редактирование, перезапустите Apache, чтобы изменения вступили в силу. Обычно это делается при помощи команды apachectl или сценария службы httpd.
Настройка файла Ixp.conf
После установки LXP файл Ixp.conf находится в каталоге /usr/local/cmd/etc. В этом файле хранятся параметры подключения LXP к PostgreSQL. Кроме того, в нем присутствуют параметры, относящиеся к отладке.
Конфигурационный файл Ixp.conf имеет простую структуру и строится по общепринятым правилам. Он состоит из комментариев, директив и значений, связанных с каждой директивой.
Комментарии всегда начинаются со знака #. Комментарий может начинаться в начале строки или следовать за директивой или значением. В процессе загрузки конфигурационного файла LXP полностью игнорирует все комментарии, поэтому они нужны только для того, чтобы напомнить программисту смысл отдельных директив или другие возможные значения параметров. Вы можете добавлять в файлы новые комментарии, это нисколько не помешает работе LXP (только не забывайте о том, что комментарии должны начинаться с символа #).
Директивы непосредственно управляют конфигурацией LXP. Обычно директива начинается в начале строки и состоит из имени (без пробелов), за которым следует ассоциированное значение. Имя директивы определяет общие аспекты функционирования сервера LXP, а значение влияет на особенности его работы. Некоторые директивы получают несколько значений, разделенных символами табуляции или пробелами. Пример:
# Here's an example directive.
MyDirective SomeValue # MyDirective defines some arbitrary value.
Возможно, вам никогда не придется вносить сколько-нибудь заметные изменения в файл Ixp.conf, но при этом желательно знать, как устроен этот файл и что он делает на случай, если такая необходимость все же возникнет. В LPX 0.8 файл Ixp.conf разделен на две секции: секцию общих параметров и секцию параметров базы данных.
Общие параметры
Секция общих параметров содержит две директивы, Debug и MaxIncludeDepth:
###############
# General LXP settings.
###############
Debug No # (Yes|No)
MaxIncludeDepth 15 # (Number)
Если директиве Debug присвоено значение Yes, в начало всех документов LXP включается отладочный заголовок, который может использоваться для диагностики непредвиденного поведения файлов LXP и включаемых сценариев. В отладочный заголовок включаются имя документа LXP, все значения cookie для заданного домена, все полученные переменные GET/POST и значение максимальной глубины включения.
Максимальная глубина включения определяет наибольший уровень включения, после которого LXP прекращает работу и выводит сообщение об ошибке. Этот параметр помогает бороться с циклическими включениями (например, файл a.lxp включает b.lxp, который, в свою очередь, включает a.lxp). Максимальная глубина включения задается директивой MaxIncludeDepth, по умолчанию она равна 15.
ПРИМЕЧАНИЕ
Директива MaxIncludeDepth не ограничивает общего количества файлов, которые могут включаться в одном документе. Она относится лишь к наибольшему уровню вложенных включений (например, в файле a.lxp включается файл b.lxp, в котором включается файл c.lxp, включающий d.lxp и т. д.).
Параметры базы данных
Следующие шесть директив задают параметры подключения к PostgreSQL. Значения по умолчанию подходят для большинства систем, но при желании их можно изменить (если этого требует специфика установки PostgreSQL).
############################
# PostgreSQL persistent connectivity options.
############################
UseDb No # (Yes|No) Присвойте значение Yes. чтобы
# подключиться к базе данных.
DbName templatel # База данных. По умолчанию "template!.".
DbHost localhost # Хост базы данных. По умолчанию "localhost".
DbPort 5432 # Порт, по которому производится подключение к PostgreSQL.
DbUser postgres # Имя пользователя. По умолчанию "postgres".
DbPass # Пароль. По умолчанию - пустая строка.
Чтобы активизировать устойчивые подключения к базе данных, присвойте параметру UseDb значение Yes. Если параметр равен No, вы все равно сможете использовать интерфейс SQL для динамического открытия подключений (см. подраздел «Включение данных SQL» в разделе «Включение данных»), но в этом случае для каждого запроса на установление связи будет создаваться новое подключение к серверу PostgreSQL.
Остальные параметры — DbName, DbHost, DbPort, DbUser и DbPass — хорошо знакомы каждому, кто хоть раз подключался к PostgreSQL. Обычно значений по умол-
чаншо оказывается достаточно, но вы можете изменить их, если этого требует ситуация (например, когда данные хранятся на отдельном сервере, параметру DbHost присваивается имя соответствующего хоста).
ВНИМАНИЕ
При использовании устойчивых соединений между Apache и PostgreSQL необходимо понимать, что каждый процесс httpd обслуживается отдельным процессом postmaster. Проследите за тем, чтобы настройка системы позволяла загрузить столько серверных процессов PostgreSQL postmaster, сколько потребует Apache (то есть количество, указанное в директиве MaxCl ients в файле httpd.conf).
Самоучитель по SQL-сервер в Linux
Использование cookie в LXPВ LXP предусмотрены средства для присваивания и чтения значений cookie. Присваивание осуществляется тегом <setcookie>, а для вывода используется тег <putcook1e>. Присваивание cookie Значение cookie должно присваиваться перед отправкой каких-либо данных с сервера Apache. Дело в том, что значения cookie включаются в заголовки, предшествующие непосредственному содержимому запрашиваемого документа. Для подобных случаев существует специальная конструкция — так называемый инициализатор, определяемый тегом <dock type="1nit">. Этот тег должен находиться сразу же после тега <1хр> в вашем документе, а внутри открываемого им блока могут находиться теги <setcookie>. Синтаксис открытия инициализатора: <1хр> <dock type="init"> В открытом блоке значения cookie задаются командой следующего вида: <setcook1e name="ww" уа1ие="значенле" domain="домен" path="путь" ехрires="срок_дейсвия" /> После закрытия блока инициализатора тегом </dock> значения cookie задаются, а данные, следующие за закрывающим тегом, передаются клиенту. При записи cookie обязательны только атрибуты name и value. Присваивание пустого значения (атрибут value) приводит к удалению cookie. Явное указание домена позволяет задать домен, в котором принимается значения cookie (например, www.thelinuxreview.com или .thelinuxreview.com для всех субдоменов). Атрибут путь задает путь URI, по которому хранится значение cookie (например, path="/app/"). Если атрибут expi res не задан, значение cookie действует на протяжении сеанса и автоматически становится недействительным при закрытии браузера. В противном случае величина атрибута либо определяет интервал в часах, в течение которого значение cookie остается действительным, либо количество секунд с 1970 года до момента истечения срока действия cookie. Если величина атрибута больше миллиона, предполагается вторая интерпретация. В отличие от некоторых web-языков, документы LXP узнают обо всех значениях cookie в том же запросе, в котором они были заданы. Передача информации о cookie реализуется на уровне внутренней логики LXP, а включенные документы других типов (например, РНР) не будут знать о назначении cookie до поступления следующего запроса. Это связано с самой природой файлов cookie, хранимых на стороне клиента. ПРИМЕЧАНИЕ Инициализатор также является удобным для выполнения любой общей инициализации в документе, поскольку ни комментарии, ни символы новой строки в инициализаторе не передаются браузеру. В инициализаторе допускается включение внешних файлов LXP. Чтение cookie В отличие от других web-языков (таких, как PHP), LXP не обеспечивает автоматической интерпретации значений cookie как переменных. Вместо этого LXP наряду со списком переменных ведет отдельный список cookie. Это сделано для предотвращения возможных конфликтов имен переменных и имен cookie. Пример вывода cookie тегом <putcookie> приведен в листинге 13.7. Листинг 13.7. Вывод значения cookie <1хр> Your cookie "user" is set to: <putcookie name="user" /> </lxp> При подстановке значения cookie в атрибут LXP возникает естественное желание воспользоваться тем же обозначением $, как при подстановке значений переменных, но это может привести к потенциальным конфликтам между значениями cookie и значениями переменных. По этой причине к значениям cookie всегда следует обращаться через специальный объект LXP cookies (листинг 13.8). Листинг 13.8. Подстановка значения cookie <lхр> <setvar welcome_msg="Welcome. @cookies.user!" /> <if cookies.user> <putvar name="welcome_msg" /> </if> </lxp> В LXP 0.8 для совместимости с предыдущими версиями действует следующее правило: если переменная с указанным при подстановке именем (например, $my_cookie) не найдена, LXP ищет имя в списке cookie. Тем не менее в будущих версиях LXP это правило будет либо отменено, либо отдельно настраиваться. |
Лексический разбор тегов
В процессе разбора тегов атрибуты либо читаются буквально, либо интерпретируются. По правилам, действующим во многих языках, заключенное в апострофы значение (например, name=' val ue') воспринимается буквально независимо от того, из каких символов оно состоит. С другой стороны, значения, заключенные в кавычки, интерпретируются, то есть некоторые символы в них имеют особый смысл.
В LXP особый смысл имеют символы $, @ и &. Они используются соответственно при подстановке переменных, объектов и сущностей.
Подстановкой называется процесс, в результате которого синтаксическое имя переменной, cookie, объекта или сущности, находящееся в произвольной символьной строке, заменяется связанным с ним значением.
Подстановка переменных
Особенности подстановки переменных со знаком $ в LXP (например, Smyvariable) поначалу сбивают с толку даже опытных программистов. При использовании LXP необходимо хорошо знать, в каких контекстах подставляются значения переменных (а в каких — не подставляются). Это поможет вам понять, когда можно задействовать подстановку, а когда лучше прибегнуть к другим средствам.
Первое правило: переменные никогда не подставляются за пределами тегов LXP. В листинге 13.9 приведен пример неправильного включения значения переменной variable в документ LXP.
Листинг 13.9. Недопустимая подстановка
<1хр>
Неге is my variable: Svariable <!-- Ошибка -->
<1хр>
А теперь предположим, что в браузере открыт адрес http://localhost/ test.lxp?setbar=foo, а файл test.lxp содержит блок LXP, приведенный в листинге 13. 10.
Листинг 13.10. Правильная подстановка переменных
<1хр>
<setvar bar="$setbar" /> <!-- Значение setbar присваивается bar-->
<putvar name="bar" /> <!-- Вывод значения bar -->
<lxp>
В этом блоке LXP тег <setvar> присваивает значение переменной setbar новой переменной с именем bar. Подстановка в данном случае вполне допустима, поскольку она выполняется в теге LXP.
Поскольку в приведенном URL-адресе переменной setbar присваивается значение foo, это новое значение будет присвоено переменной bar.
Тег <putvar> является примером второго правила подстановки в LXP. Некоторые теги (такие, как <putvar>) для выполнения своих функций должны получать имена переменных. Вспомните, что знаки $ и @ не входят в имена переменных; они всего лишь используются для подстановки значений вместо имен.
На первый взгляд кажется, что тег <putvar> из листинга 13.10 должен выглядеть так:
<putvar name="$bar" /> <!-- Вывод значения bar -->
Однако в действительности это приведет к тому, что в значение атрибута name будет подставлено значение переменной bar. А так как переменная bar равна foo, то в конечном счете LXP попытается вывести переменную с именем foo.
Чтобы определить, нужно ли использовать подстановочные символы в каждом конкретном случае, проще всего разобраться в том, что же делает тег. Если атрибут должен заменяться значением переменной, необходимо произвести подстановку с символом $. Если же в атрибуте просто задается имя переменной (как в теге <putvar>), подстановка не нужна.
Если литерал $ требуется использовать в кавычках, его следует экранировать. Для этого в строку включаются два знака $ подряд (например, <setvar pri ce="$$99 . 95" />).
ПРИМЕЧАНИЕ
Если при подстановке переменная не найдена, LXP ищет cookie с указанным именем. Если cookie существует, вместо имени подставляется его значение.
Подстановка объектных переменных
Подстановка переменных, являющихся компонентами объектов, имеет очень много общего с подстановкой обычных переменных, разве что вместо знака $ используется знак @. С точки зрения синтаксиса между префиксами @ и $ существует единственное различие: с префиксом @ имя может содержать точки (.) и квадратные скобки ([ ]).
Чтобы включить литерал @ в строку, экранируйте его удвоением (например, <setvar email="jlx(a(acommandprompt.com" />).
Подстановка сущностей
LXP автоматически преобразует все опознанные сущности в значениях атрибутов тегов LXP в их символьные прототипы. В LXP версии 0.8 распознавались пять стандартных сущностей XML:
амперсанд (Samp;); знак «меньше» (&11:); знак «больше» (>); апостроф (&apos:); кавычка (").Подстановка сущностей иногда бывает очень полезной — если апострофы и кавычки должны входить в значения атрибутов тегов LXP, вставить их без использования сущностей не удастся. Разработчики LXP рассматривали возможность поддержки экранирующих префиксов \ (как обычно делается в других языках программирования), но непосредственная работа с сущностями лучше соответствует стилю разметки и поднимает язык на более высокий уровень.
В листинге 13.11 приведен пример подстановки сущности в теге LXP<include>.
Листинг 13.11. Подстановка сущности
<1хр>
<setvar field="field_two" />
<include sql="SELECT f1eld_one. Ifield FROM ":CAPITALIZED_TABLE""
method="SQL">
<strong>Column One:</strong> <field name="field_one" /><br>
<strong>Column Two:</strong> <field name="field_two" /><br>
</include>
</lxp>
В листинге 13.11 сущности используются в запросе SQL для того, чтобы указать в кавычках символы кавычек ("). Это часто бывает необходимо для того, чтобы в PostgreSQL учитывался регистр символов, поскольку в противном случае идентификаторы автоматически преобразуются к нижнему регистру.
В процессе разбора комбинация Squot: заменяется своим символьным прототипом, в результате чего будет выполнен следующий запрос: SELECT field_one. field_two FROM "CAPITALIZEDJABLE"
Смысл блока LXP, приведенного в этом примере, описан в подразделе «Включение данных SQL» раздела «Включение данных».
Тег <varparser>
В LXP предусмотрен простой механизм поиска и замены значений переменных, для этой цели используется тег <varparser>. Тег получает два атрибута, find и repl асе. Он открывает блок, в котором все подставляемые значения переменных проходят фильтрацию но заданному правилу.
Тег <varparser> чаще всего используется для удаления или экранирования нежелательных символов. Например, при подготовке команды SQL все апострофы (') обычно экранируются символом \, поскольку в PostgrcSQL апостроф задей-ствуется в качестве ограничителя строковых констант. В листинге 13.12 продемонстрировано экранирование апострофов в переменной с именем txt.
Листинг 13.12. Использование тега <varparser> при подготовке команды SQL
<1хр>
<varparser find=..... replace="\'">
<include sql="SELECT * FROM table WHERE txtfield = '$txt'">
<field /><br />
</include>
</varparser>
</lxp>
В листинге 13.12 тег <varparser find=..... replace="\' "> приказывает LXP заменять апострофы экранированной последовательностью \' во всех подставляемых значениях переменных.
Обратите внимание: поиск с заменой производится только в подставляемых значениях. По этой причине литералы-апострофы в атрибуте sql тега <1 ncl ude> остаются без изменений; модификация относится только к значениям, подставляемым в этот атрибут (то есть значению переменной txt в листинге 13.12).
Завершающий тег </varparser> возвращает LXP к обычному режиму подстановки переменных.
ПРИМЕЧАНИЕ
Вложение тегов <varparser> позволяет установить несколько одновременных правил поиска с заменой.
Условная логика
Простейший способ условной генерации данных в LXP основан на встроенной поддержке тегов условной логики. Условные теги позволяют скрывать или активизировать целые блоки посредством проверки условий для переменных и cookie. К числу основных условных тегов LXP относятся теги: <if>, <ifnot>, <ifcookie>, <ifnotcookie>, <else>, <elseif> и <elseifnot>.
Теги <1f> и <1fnot> работают с переменными LXP (или компонентами объектов), тогда как теги <1 fcookie> и <1 f notcooki e> работают с файлами cookie текущего домена. Иначе говоря, теги <if> и <ifcookie> обладают одинаковыми логическими функциями, различаются только проверяемые исходные данные.
Тег <el se> имеет более общий характер и реализует проверку инвертированных условий для тегов, упоминавшихся выше. Теги <elseif> и <elseifnot> в действителыюсти всего лишь обеспечивают сокращенную запись для вложения тегов <i f> и <1fnot> в блоки <else>.
Теги <if> и <ifnot>
Без атрибутов теги <1f> и <1fnot> не выполняют никаких полезных функций. Однако с правильно указанными атрибутами они позволяют легко и быстро помечать блоки разметки и обеспечивать их отображение при определенных условиях.
Тег <if>
Тег <i f> сравнивает свои атрибуты с переменными, имена которых соответствуют именам атрибутов. Если значение заданного атрибута совпадает со значением переменной, блок разметки между <if> и парным тегом </if> обрабатывается LXP. В противном случае весь блок (от <if> до </if>) полностью игнорируется вместе со всей разметкой.
В зависимости от типа логической проверки в тег <1 f> включается имя атрибута, пара «имя/значение» или серия таких пар.
Если указано только имя атрибута (например, <i f test>), LXP проверяет только существование каких-либо символов, присвоенных переменной с указанным именем. Если переменная содержит пустое значение (или вообще не существует), проверка завершается неудачей, а соответствующий блок исключается из обработки. Если значение найдено, блок обрабатывается обычным образом.
При наличии одной или нескольких пар атрибутов каждое значение сравнивается со значением переменной с указанным именем. Если тег содержит более одного атрибута, то для совпадения в целом должны совпадать осе частичные условия. Только в этом случае соответствующий блок будет нормально обработан.
В листинге 13.13 тег <if> проверяет существование значения переменной с именем name, а также проверяет, содержит ли переменная access значение 1.
Листинг 13.13. Использование тега <if>
<1хр>
<if name access="l"> <strong>Success!</strong><br />
A <em>name</em> is set. and <em>access</em> is set to l.<br />
</if> <
/lxp>
Тег <ifnot>
Тег <ifnot> во всех отношениях противоположен тегу <if>. Например, при перечислении нескольких атрибутов блок <ifnot> обрабатывается лишь в том случае, если не выполняется ни одного из проверяемых условий.
В листинге 13.14 тег <ifnot> убеждается в том, что переменная с именем error не содержит значения, а также проверяет, что переменная access не равна 0.
Листинг 13.14. Использование тега <ifnot>
<1хр>
<ifnot error access="0"> <strong>Success!</strong><br />
An <em>error</em> is not set. and <em>access</em> is not set to 0.<br />
</ifnot>
</lxp>
ПРИМЕЧАНИЕ
В одном теге LXP не допускается определение двух атрибутов с одинаковыми именами (то есть тег <ifnot access="0" access="2"> неправилен). Следовательно, проверка двух условий для одной переменной должна производиться двумя отдельными тегами.
Вложение логических тегов
Под термином вложение понимается размещение тегов внутри блоков, размеченных другими тегами. Логические теги можно свободно вкладывать, по при этом необходимо тщательно следить за соответствием открывающих и закрывающих тегов.
В некоторых случаях вложение логических тегов требуется для проверки нескольких условий с одной переменной. Это связано с тем, что имя переменной может встречаться в логическом теге всего один раз.
В листинге 13.15 приведен пример вложения нескольких логических тегов в один тег <if> верхнего уровня.
Листинг 13.15. Вложение логических тегов
<1хр>
<if answer> <strong>You have supplied an answer!</strong><br />
<if answer="12">
Your answer is correct!<br />
</1f>
<ifnot answer="12">
Your answer of <putvar name="answer">. though, is incorrect.<br />
</ifnot>
<if answer="12" cheatcode>
You appear to be cheating, however.
</if>
</if>
</lxp>
В листинге 13.15 первый тег <i f> проверяет, задано ли значение аргумента answer. Если значение отсутствует, весь внутренний блок не обрабатывается.
Второй тег <if> проверяет, содержит ли переданный аргумент answer значение 12. Если условие выполняется, блок тега <i f> обрабатывается, а если нет — не обрабатывается.
Следующий тег <ifnot> проверяет, отличен ли аргумент answer от 12. В этом случае обрабатывается внутренний блок тега <i fnot>.
Наконец, последний Ter<if> в листинге 13.15 проверяет, содержит ли аргумент answer значение 12 и был ли при этом передан аргумент cheatcode. Если аргумент равен 12, а переменная cheatcode существует, обрабатывается блок последнего тега <if> (в данном примере он просто выводит сообщение).
Теги < ifcookie> и <ifnotcookie>
Теги <ifcookie> и <ifnotcookie> аналогичны тегам <if> и <ifnot>, с одним принципиальным различием: при проверке используются не переменные, хранимые в памяти, а файлы cookie, хранимые в некотором домене и доступные через браузер.
В листинге 13.16 блок LXP строит персональное приветствие для пользователя, если в его браузере хранится cookie с именем username.
Листинг 13.16. Теги <ifcookie> и <ifnotcookie>
<1хр> <ifcookie username>
Welcome back. <putcookie name="username">.<br />
</ifcookie>
<ifnotcook1e username>
<include src="login.php" />
</ifnotcookie>
</lxp>
Если cookie с именем username не существует, выводится стандартная страница для ввода пользовательских данных, реализованная в документе РНР. Документ воспроизводится посредством подзапроса Apache (см. подраздел «Включение внешних источников данных» в разделе «Включение данных»).
Теги <else>, <elseif> и <elseifnot>
Теги <else>, <e!seif> и <else1fnot> помогают организовать проверку более сложных логических условий по сравнению с отдельными командами <if> и <ifnot>.
Тег <else> открывает блок, который воспроизводится лишь в том случае, если предыдущее условие (при вложении логических тегов — находящееся на том же уровне) было ложным. Если последнее логическое условие было истинным, блок <else> не обрабатывается.
В листинге 13.17 простое условие <if> проверяет переменную с именем answer. Если переменная не существует, то блок, заключенный между тегами <else> и </ else>, обрабатывается; в противном случае — не обрабатывается.
Листинг 13.17. Использование тега <else>
<1хр>
<ifanswer>
Thank you for supplying an answer.
</if>
<e1se>
You nave not yet supplied an answer.<br/>
<include src="forms/question.lxp" />
</else>
</lxp>
Как упоминалось выше, теги <el sei f> и <el sei fnot> всего лишь сокращают объем записи. Они работают точно так же, как теги <1 f > и <i f not>, вложенные в блок <el se>. Например, следующие два блока функционально идентичны:
<if conditionl="true">
Condition 1 is True. </if> <eise>
<if condition2="true"> Condition 2 is tnue.
</if>
</else>
...
<if conditioni="true">
Condition 1 is True.
</if>
<elseif condition2="true">
Condition 2 is true.
</elseif>
Теги <el se> повышают эффективность и упрощают дальнейшее сопровождение условных конструкции. При использовании тега <else> LXP автоматически следит за выполнением предыдущего условия, и вам не приходится проверять его заново в инвертированном виде.
В листинге 13.18 реализована та же логика, что в приведенном выше листинге 13.15, но объем кода сокращен за счет применения тега <else>.
Листинг 13.18. Последовательная проверка с использованием тега <else>
<1хр>
<1f answer> <strong>You have supplied an answer!</strong><br />
<if answer="12"> Your answer is correct!<br />
<if cheatcode>
You appear to be cheating, however.
</if>
<else>
Congratulations for not cneating!
</eise>
</if>
<else>
Your answer of <putvar name="answer">. though, is incorrect.<br />
</else>
</if>
<else>
You have not yet supplied an answer.<br />
<include src="forms/question.Ixp" />
</else>
</lxp>
Циклы
Тег <for> предназначен для многократного выполнения блоков LXP. При вызове он всегда получает обязательный атрибут start, а также один из атрибутов end и endbefore. Всем атрибутам должны быть присвоены числовые значения.
Атрибут start инициализирует целочисленный счетчик цикла, который увеличивается на 1 при каждой последующей итерации. Если в теге определен атрибут end, цикл прекращается после достижения числа, указанного в этом атрибуте. Если же определен атрибут endbefore, цикл прекращается на одну итерацию раньше. Таким образом, атрибуты end и endbefore в этом отношении функционально эквивалентны операторам <= и < таких языков программирования, как РНР и С.
В процессе перебора специальный объект LXP с именем for содержит переменную count, в которой хранится текущее значение счетчика цикла. В листинге 13.19 приведен пример простого цикла for с изменением счетчика в интервале от 1 до 5.
Листинг 13.19. Простой цикл <for>
<1хр>
<for start="l" end="5">
Iterating loop: <putvar name="for.count" /><br />
</fon>
</lxp>
При обработке этого блока будет выведен следующий результат:
Iterating loop: l<br />
Iterating loop: 2<br />
Iterating loop: 3<br />
Iterating loop: 4<br />
Iterating loop: 5<br />
Цикл for оказывает неоценимую помощь при работе с массивами, элементы которых требуется вернуть средствами LXP. Как упоминалось ранее, если при определении после имени переменной следуют квадратные скобки ([ ]), LXP автоматически создает массив значений, связанных с этим именем, при этом каждый элемент массива определяется целочисленным индексом. LXP также создает объектную переменную с тем же именем, но без квадратных скобок, с двумя переменными size и last. Переменная size (например, my_array.size) содержит количество элементов в массиве, а переменная 1 ast (например, my_array. 1 ast) — индекс последнего элемента.
В листинге 13.20 продемонстрирован вывод элементов массива my_array[].
Листинг 13.20. Вывод элементов массива в цикле <for>
<1хр>
<for start="0" end="@my_array.last">
Here is the value of my_array. at offset <putvar name="for.count" />:
<putvar name="my_array[@for.count]" />
<br />
</for>
</lxp>
Обратите внимание: знак @ используется с объектом my_array только в том случае, когда нужно получить значение переменной, а не ее имя. В теге <putvar> он отсутствует, поскольку атрибут name должен содержать имя переменной, а не ее значение.
ВНИМАНИЕ
Вместо автоматического создания массива (в виде my_array[]) можно присваивать индексы элементов вручную (например, my_array[0], my_array[l]), но в этом случае LXP не устанавливает значения переменных size и last.
Включение данных
В системе управления включением данных LXP центральное место занимает тег <include>. Он работает в разных режимах в зависимости от переданного атрибута method или контекста, определяемого значениями атрибутов.
В простейшем виде тег <i ncl ude> используется для простого включения файлов HTML— стандартных заголовков, панелей ссылок и нижних колонтитулов. Существуют и другие, не столь тривиальные применения — тег <include> может использоваться для разбора файлов, разделенных произвольными лексемами, и базовых документов XML, внедрения выходных данных РНР в документы LXP, непосредственной обработки запросов SQL и, конечно, включения других документов LXP.
В табл. 13.1 перечислены методы включения, поддерживаемые тегом <incl ude>. В первом столбце указаны значения атрибута method тега <i ncl ude>. Во втором столбце приведены псевдонимы — альтернативные имена для вызова метода. В столбце «По умолчанию» указаны значения атрибутов, при которых этот метод используется по умолчанию (при этом необходимость в явном указании атрибута method отпадает). В столбце «Описание» приводится краткое описание самого метода.
Таблица 13.1. Методы включения в LXP
Метод | Псевдонимы | По умолчанию | Описание |
LXP |
Атрибут src завершается расширением .1хр |
Файл обрабатывается средствами modjxp |
|
flat |
Неопознанное расширение в атрибуте src при отсутствии атрибутов sql и query |
Простой вывод содержимого файла |
|
parsed |
Лексический разбор файла с разбиением на значения <field> |
||
XML |
RSS, RDF |
Атрибут src завершается расширением .xml, .rdf или .rss |
Лексический разбор нормально сформированного файла XML с разбиением на значения <field> |
local |
Apache |
Атрибут src завершается расширением .php, .рпрЗ или .phtml |
Воспроизведение выходных данных подзапроса Apache, атрибут src содержит имя файла |
URI |
Воспроизведение выходных данных подзапроса Apache, атрибут src содержит HTTP URI |
||
SQL |
Наличие атрибута sql или query |
Выполнение команды SQL. Доступ к результатам запроса осуществляется при помощи переменных и тегов <field> |
Источник включаемых данных всегда задается атрибутом src тега <include>. В большинстве случаев это имя файла, хотя в зависимости от выбранного метода источником также может быть подключение к базе данных или URI. При включении файла с относительным путем (то есть не прослеживаемым к основанию файловой системы), LXP выбирает в качестве основания рабочий каталог документа LXP, в котором производится включение.
ПРИМЕЧАНИЕ
Для предотвращения непреднамеренной бесконечной рекурсии (например, из-за включения файла, включающего самого себя) в документах LXP включение может производиться только до глубины, заданной директивой MaxIncludeDepth в файле Ixp.conf (см. подраздел «Настройка файла Ixp.conf» в разделе «Установка и настройка LXP»). По умолчанию максимальная глубина включения равна 15.
Включение файлов LXP
В файлы LXP можно включать другие файлы LXP, если сервер Apache имеет доступ по чтению к документу, заданному в атрибуте src. Все переменные, заданные во включающем документе LXP, будут доступны для чтения и модификации во включаемом документе LXP.
Чтобы включить файл LXP, откройте блок LXP н воспользуйтесь следующей командой (файл_1хр — имя включаемого файла LXP): <include 5гс="фзйл_1хр" />
ПРИМЕЧАНИЕ
Включаемый файл LXP обрабатывается по тем же правилам, что и при непосредственном вызове. Следовательно, чтобы вы могли использовать теги LXP во включаемом файле, в нем необходимо предварительно открыть блок LXP тегом <1хр>.>
Поскольку вывод включаемого документа LXP подставляется на место включающего тега <i ncl ude>, закрывающий тег при таком способе включения не нужен. В этом случае тег <include> является тегом с пустым блоком (то есть с завершающим символом /). Если включаемый файл LXP не имеет расширения .1хр, вы можете обеспечить его принудительную обработку как модуля LXP при помощи атрибута method="lxp".
Допустим, у вас имеется приложение LXP, которое предоставляет разную информацию в зависимости от виртуального хоста, от которого поступило обращение. В каталоге DocumentRoot каждого виртуального хоста может храниться всего один файл index.Ixp, настроенный на включение корневого приложения LXP из другого каталога. В листинге 13.21 приведен пример простого файла верхнего уровня, который задает значения двух защищенных переменных LXP и включает корневой файл LXP.
Листинг 13.21. Включение документа LXP
<1хр>
<setvar lxp.virtual_host="0" />
<setvar lxp.access_level="l" />
<1nclude src="../application/index.Ixp" />
</lxp>
Включение неструктурированных файлов
Неструктурированным, или плоским, файлом называется простой текстовый документ. С точки зрения сервера неструктурированный файл не нужно подвергать лексическому разбору.
Как и при включении документа LXP, метод f I at не требует закрывающего тега и поэтому используется только в виде тега с пустым блоком и завершающим символом /. Чтобы включить неструктурированный файл, откройте блок LXP н воспользуйтесь следующей командой (файл — имя включаемого файла LXP):
include srс="файл_lxp" />
Если включаемый файл имеет одно из распознаваемых расширений, вы можете инициировать его включение как неструктурированного файла при помощи атрибута method="f I at". В листинге 13.22 приведен документ LXP, включающий три файла HTML из относительного каталога parts. В этих файлах подгружаются компонепты web-страницы — заголовок, панель ссылок и нижний колонтитул. Расширения этих файлов не подразумевают более сложные методы, поэтому файлы просто включаются без дополнительных уточнений.
Листинг 13.22. Включение неструктурированных файлов
<1хр>
<include src="parts/header.html" />
<include src="parts/leftbar.html" />
Welcome to my home page.<br />
<include src="parts/footer.html />
<1хр>
Подобные включения упрощают сопровождение web-сайтов с модульной структурой — логические компоненты оформляются в виде отдельных модулей по аналогии с тем, как это делается при использовании серверных включений или функции PHP readfileO. Кроме того, включение неструктурированных файлов позволяет добиться того же уровня модульности без потери простоты и элегантности разметочной структуры документа. Впрочем, этим возможности тега <include> далеко не исчерпываются.
Включение файлов с разделителями
Во многих динамических web-сайтах предусмотрена функция публикации содержимого файлов с разделителями (например, файла headlines с сайта Linux Today) в некотором формате, фильтруемом на программном уровне. Реализация таких фильтров обычно меняется от страницы к странице и от сайта к сайту, а для извлечения данных и их последующей сборки в удобном формате используются довольно сложные алгоритмы.
В LXP для отображения таких файлов используется тег <indude> с атрибутом method="parsed". Содержимое файла разбивается на серию последовательных значений, доступ к которым осуществляется при помощи универсального тега LXP <field>.
Информационные блоки разделяются значением, передаваемым в атрибуте del i mi ter. Внутри блока поля отделяются друг от друга символами новой строки (\п). Необязательный атрибут separator позволяет выбрать другой разделитель полей.
Метод parsed тега <include> требует закрывающего тега </include>, поскольку для каждого блока, который LXP читает из файла, происходит возврат к начальному тегу <include> с повторным выполнением перечисленных действий вплоть до обработки последнего блока.
Если вы захотите ограничить количество отображаемых блоков, задайте номер последнего блока при помощи атрибута lastblock. Кроме того, атрибут firstblock позволяет пропустить несколько начальных блоков (скажем, блок комментариев, который может находиться в начале текстового файла до первого разделителя).
Пример файла с разделителями с сайта www.linuxtoday.com:
Welcome to lthead.txt. Fields are delimited by two ampersands.
The first field is the headline. The second field is the URL to the story.
The third field is the date the story was posted.
Have Fun! (webmaster@linuxtoday.com)
&&
LinuxProgramming: python-dev summary 2001-06-21 - 2001-07-05 http://linuxtoday.com/news_story.php3?ltsn=2001-07-05-019-21-OS-SW
Jul 5. 2001. 21:30:38
&&
Chicago Sun-Times: Test drive Linux using friendly tryout software
http://linuxtoday.com/news_story.php3?ltsn=2001-07-05-018-21-PS-CY
Jul 5. 2001, 21:00:48
&&
[...]
Фрагмент, приведенный в листинге 13.23, открывает файл /home/web/headlines/ lthead.txt и разбивает его на блоки. В качестве разделителя блоков используется последовательность символов &&.
Листинг 13.23. Включение файла с разделителями
<1хр>
<include src="/home/web/headlines/lthead.txt" delimiter="&&"
firstblock="2" lastblock="4" method="parsed">
<table border="0" cellspacing="l"><tr>
<td bgcolor="#ffffff" width="100r> <div class="content">
- <field />
</div>
</td>
</tr>
<tr>
<td bgcolor="#eOeOe8" width="100r> <strong>
<field type="url" link="Read More..." target="_blank" />
</strong>
<br/>
</td>
</tr>
</table>
</include>
</lxp>
При обработке этого фрагмента теги <field> заполняются результатами разбора блоков. Поля присваиваются тегам <field> в порядке нахождения.
Как видно из листинга 13.23, в теге <f ield> можно определить дополнительный атрибут type. При включении разделенных файлов этот атрибут может принимать значения hidden (значение поля не выводится в выходных данных) и url.
Тип hidden назначается полям, пропускаемым при разборе файла. Поскольку в файлах с разделителями не предусмотрена идентификация блоков по именам, все поля обрабатываются LXP в порядке их следования в исходном файле. Чтобы исключить некоторое поле из вывода, вы назначаете ему атрибут type="hidden" — это позволяет продолжить вывод со следующего поля.
Тип url обычно используется в тех случаях, если поле заведомо содержит URL-адрес. Вместо простого вывода текста создается гипсрссылка по заданному URL-адресу (при помощи тега HTML <a>). Вместо URL-адреса текст сгенерированной гиперссылки можно заменить любым текстом по своему усмотрению (в листинге 13.23 использовался текст «Read More...»), для этого в теге <field> достаточно задать атрибут link.
Пример выходных данных LXP после разбора фрагмента, приведенного в листинге 13.23:
<table border="0" cellspacing="l"><tr>
<td bgcolor="#ffffff" width="100%>
<div class="content">
- LinuxProgramming: python-dev summary 2001-06-21 - 2001-07-05
</div>
</td>
</tr>
</tr>
<td bgcolor="#e0e0e8" width="100%>
<strong>
<a href="http://linuxtoday.com/news_story.php3?ltsn= 2001-07-05-019-21-OS-SW"
target="_blank">Read More...</a>
</strong><br/>
</td>
</tr></table>
<table border="0" cellspacing="l"><tr>
<td bgcolor="#ffffff" width="100%>
<div class="content">
- Chicago Sun-Times: Test drive Linux using friendly tryout software
</div>
</td>
</tr><tr>
<td bgcolor="#e0e0e8" width="100r>
<strong>
<a href='1http://linuxtoday.com/news_story.php3?ltsn=2001-07-05-018-21-PS-CY"
target="_blank">Read More...</a>
</strong><br />
</td>
</tr></table>
[...]
ПРИМЕЧАНИЕ
В теге LXP <field type="url "> можно передавать внешние (по отношению к LXP) атрибуты, такие как class или target. Эти атрибуты включаются в сгенерированный тег <а>.
Включение файлов XML, RSS и RDF
Процедура включения внешнего правильно оформленного (well-formed) документа XML очень похожа на метод parsed. Режим обработки XML активизируется присваиванием атрибуту method значения XML, RSS или RDF. Кроме того, он автоматически выбирается при передаче атрибута src с расширениями .xml, .rss и .rdf.
Атрибут del imiter в этом контексте задает имя элемента (тега), в котором производится поиск полей. В общем случае значения полей выводятся в порядке их следования в файле XML, если в теге <field> не указано имя выводимого элемента. Например, атрибут name="title" описывает символьные данные, заключенные между тегами <title> и </title> исходного документа XML.
В качестве примера рассмотрим документ XML languages.xml, в котором перечисляются языки взаимодействия с PostgreSQL. Документ имеет следующую структуру:
<?xml version="1.0" encoding="utf-8"?>
<languages>
<language>
<name>C</name>
<notes>Bui11-i n 1anguage.</notes>
</language>
<language>
<name>LXP</name>
<notes>Web-based content language.</notes>
</language>
<language>
<name>PL/pgSQL</name>
<notes>PostgreSQL procedural language.</notes>
</language>
</languages>
Обратите внимание: каждый язык описывается отдельным элементом <1 anguage>. Чтобы произвести лексический разбор этого файла XML по аналогии с рассмотренным выше примером файла с разделителями, присвойте атрибуту del i mi ter тега <include> значение language, а атрибуту src — значение languages.xml. Пример приведен в листинге 13.24.
Листинг 13.24. Включение файла XML
<1хр>
<include src="languages.xml" delimiter="language" method="xml">
Language Name: <field name="name" /><br />
Language Notes: <field name="notes" /><br />
<hr />
</include>
</lxp>
После выполнения этого фрагмента будет получен следующий результат:
Language Name: C<br />
Language Notes: Built-in language.<br />
<hr />
Language Name: LXP<br />
Language Notes: Web-based content language.<br />
<hr /> >
Language Name: PL/pgSQL<br />
Language Notes: PostgreSQL procedural language.<br />
<hr />
В листинге 13.25 приведен пример отображения простого документа RDF XML. Он отличается от примера из листинга 13.24 тем, что относится именно к документу RDF. В результате атрибут del imiter можно не указывать, поскольку значение по умолчанию item подходит для структуры данных RDF.
Листинг 13.25. Включение файла RDF
<1хр>
<include src=»/home/web/ports/headlines/slashdot.rdf» lastblock=»5">
<table Dorder=»0" cellspacing=»l"><tr>
<td bgcolor=»#ffffff» width=»100%>
<div class=»content»>- <field name=»title»></div>
</td>
</tr><tr>
<td bgcolor=»#e0e0e8" width=»100%>
<strong>
<field name=»link» type=»url» link=»Read More...» target=»_blank»>
</strong><br />
</td>
</tr></table>
</include>
</lxp>
Обратите внимание на атрибут lastblock в листинге 13.25. Этот атрибут уже упоминался в подразделе «Включение файлов с разделителями» этого раздела. Атрибуты fi rstblock и lastblock также используются при включении файлов XML, RDF и RSS и определяют размер и смещение выводимых блоков.
ВНИМАНИЕ
Учтите, что все документы XML, включаемые средствами LXP, должны быть правильно оформлены, иначе модуль лексического разбора выдаст ошибку. Ошибки разбора XML сохраняются в журнале ошибок Apache с префиксом [Ixp] XML Parse Error.
Включение внешних источников данных
При включении внешних источников данных, входящих в конфигурацию Apache, тег <include> вызывается с методом URI или local. В обоих случаях выполняется подзапрос к Apache, то есть включение обрабатывается как прямой запрос Apache, результаты которого вставляются в позицию тега <include> документа LXP.
Принципиальное различие между этими двумя способами заключается в том, что метод URI получает атрибут src в том виде, в котором Apache получает его от браузера — с начальным символом / и заданным по отношению к корневому каталогу хоста (например, /example.php). С другой стороны, при использовании метода local серверу Apache передается информация о местонахождении файла в локальной файловой системе (например, /home/web/example.php).
В листинге 13.26 приведен файл LXP с двумя вариантами включения сценария РНР. В обоих случаях включение производится с участием Apache и потому зависит от правильной настройки запрашиваемого типа данных в Apache. Это особенно важно для метода local, требующего наличия соответствующих прав доступа к каталогу, содержащему включаемый сценарий.
Листинг 13.26. Включение внешних данных
<1хр>
An example PHP scnpt:<br />
<include src="/example.php" method="URI" />
<hr />
The same PHP script, using the local method:<br />
<include src="/home/web/default/example.php" method="local" />
</lxp>
Если при включении документа, заданного атрибутом src, атрибут method отсутствует, а имя документа завершается одним из стандартных расширений РНР (.php, .php3 и .phtml), по умолчанию выбирается метод local. В LXP 0.8 метод URI не выбирается по умолчанию. Чтобы использовать метод URI, необходимо передать в теге <1nclude> атрибут method="URI".
Включение данных SQL
Метод SQL обладает исключительно широкими возможностями в области непосредственного взаимодействия с PostgreSQL. В частности, он позволяет внедрять динамические результаты запросов к базе данных в web-страницу, не прибегая к языку программирования, создавать программные объекты подключений или команд и даже производить лексический разбор и форматирование результатов.
Метод SQL выбирается включением BTcr<include> атрибутаmethod="SQL". Кроме того, этот метод выбирается по умолчанию при передаче атрибута sql с выполняемой командой SQL. В следующем примере используется второй вариант, то есть метод SQL подразумевается благодаря атрибуту sql:
<include sql="SELECT * FROM pg_database">
По аналогии с методами лексического разбора данных, блок между открывающим и закрывающим тегами <1 ncl ude> выполняется для всех записей, полученных в результате успешно выполненного запроса SQL.
Выбор базы данных
При использовании метода SQL атрибут src тега <indude> определяет базу данных, с которой выполняется операция. Если атрибут не указан, LXP пытается восстановить устойчивое подключение к базе данных (если оно существует).
ПРИМЕЧАНИЕ
Хотя для каждого процесса Apache httpd существует одно устойчивое подключение к базе данных, на самом деле за его поддержанием следит модуль LXP, а не Apache.
Формат строки подключения хорошо знаком всем, кому доводилось подключаться к PostgreSQL из программ С или РНР. Строка содержит несколько параметров, описывающих источник данных. Параметры подключения перечислены в табл. 13.2.
Таблица 13.2. Параметры подключения к базе данных
Параметр | Описание |
dbname |
Имя базы данных (по умолчанию совпадает с именем подключающегося пользователя) |
host |
Имя хоста |
user |
Имя пользователя (по умолчанию совпадает с именем, под которым работает Apache) |
password |
Пароль (если аутентификация обязательна) |
port |
Порт (по умолчанию 5432) |
В значении атрибута src параметры разделяются пробелами, а имя параметра отделяется от его значения знаком равенства (=). Порядок перечисления параметров не важен.
В листинге 13.27 приведен пример запроса SQL с подключением к базе данных example на сервере db_server под именем пользователя John.
Листинг 13.27. Подключение к базе данных
<1хр>
<include sql-"SELECT * FROM users ORDER BY username ASC"
src="dbname=example host=db_server user=john">
User: <field /><br />
</include>
</lxp>
ВНИМАНИЕ
В LXP 0.8 при вложении подключения SQL в другое подключение SQL во вложенном теге обязательно определяется атрибут src, даже если подключение производится к базе данных по умолчанию. В LXP 0.8.1 этот недостаток исправлен.
Работа с полями
При итеративном выполнении блока включения SQL возможны два варианта обращения к значениям полей: можно воспользоваться общим тегом <f lei d> или объектом this, который заполняется значениями всех полей для текущей итерации.
Как и при включении XML, тег <field> может содержать атрибут name, идентифицирующий выводимое поле. В противном случае поля выводятся последовательными тегами <field> в порядке их перечисления в запросе (слева направо).
Кроме того, к значениям полей можно обращаться при помощи конструкции this. поле, где поле — имя поля. Например, во включенном блоке SQL следующие два тега выводят одинаковый результат:
<field name="id" /> <putvar name="this.id" />
Объект this поддерживается в основном ради применения условных тегов и подстановки переменных с данными, возвращаемыми в итоговых наборах SQL. В листинге 13.28 приведен пример запроса SQL и форматирования выходных данных с применением условных тегов.
Листинг 13.28. Включение результатов запроса SQL
<1хр>
<1nclude sql="SELECT datname. datdba AS userjd FROM pg_database">
<if this.user_id="$userid">
<strong><field /></strong><br />
<setvar owned_databases="$owned_databases @this.datname" /> </if> <else>
<f1eld /><br />
</else>
</include>
</1 xp>
Работа с метаданными SQL
При выполнении запросов SQL объект LXP с именем sql заполняется информацией о полученном итоговом наборе. Он содержит переменные sql .numrows, sql .numcols, sql .numfields (псевдоним для sql .numcols), sql .rown sql .offset.
Переменная sql. numrows содержит количество записей, полученных в результате запроса. Переменная sql .numcols (атакже ее псевдоним sql .numfields) содержит количество полей в каждой записи. При итеративном выполнении блока, заключенного между <1nclude> и </1nclude>, переменная sql. row содержит числовой индекс текущей записи, начиная с 1, а переменная sql .offset — числовой индекс, начиная с 0.
В листинге 13.29 переменная sql .row используется для вывода индекса текущей записи в блоке <include>. После вывода результатов запроса переменная sql .numrows выводит количество выбранных записей.
Листинг 13.29. Использование объектной переменной sql
<1хр>
<include sqVSELECT * FROM pg_user ORDER BY usename LIMIT 5">
User #<putvar name="sql .row" />: <putvar name="this.usename" /><br />
</include>
<br />
Selected <putvar name="sql.numrows" /> rows.
</lxp>
Результат выполнения листинга 13.29 выглядит так:
User #i: al!en<br />
User #2: barbara<br />
User #3: ben<br />
User #4: corwin<br />
User #5: david<br />
<br />
Selected 5 rows.
Присваивание значений объектным переменным SQL
Если запрос SQL должен выполняться только для получения доступа к итоговому набору (в обход автоматического перебора в теге <include>), передайте атрибут setvars с именем объекта LXP, заполняемого информацией о результатах запроса, и немедленно закройте блок парным тегом </include>.
Если итоговый набор состоит из одной записи, для каждого поля этой записи создается переменная объект.поле, где объект — имя объекта, указанное в атрибуте servars, а поле — имя поля, возвращаемого запросом.
Если итоговый набор содержит более одной записи, к имени поля присоединяются квадратные скобки с индексом (например, object, col umn[0], object, col umn[l] и т. д.).
В листинге 13.30 выполняется запрос к таблице pg_user с выборкой трех полей, содержащей информацию о конкретном пользователе.
Листинг 13.30. Заполнение объекта LXP результатами выборки
<1хр>
<include sql="SELECT usenarne. usesuper. usecreatedb
FROM pg_user
WHERE usesysid = Suserid"
setvars="usennfo"></include>
<1f sql,numrows="l">
User name: <putvar name="usennfo.usename"><br />
<if userinfo.usecreatedb-'t'>
<strong>This user can create databases.</strong><br />
</if>
<if userinfo.usesuper='t'>
<strong>Trns user is a superuser.</strong><br />
</1f>
</1f>
<else>
Error: No user was found.
</else>
</lxp>
Внешние теги
В некоторых ситуациях переменные LXP требуется использовать в контексте тегов HTML. Предположим, у вас имеется графическое изображение с динамически изменяемой шириной. Помните, что LXP выполняет подстановку только в теrax LXP, а в тегах HTML это сделать не удастся. Иначе говоря, ссылка на переменную Swidth в следующем фрагменте не работает:
<1хр>
<!-- ОШИБКА: Подстановка переменных LXP во внешних тегах невозможна -->
<img src="/images/spacer.gif" width="$width" />
</lxp>
Напрашивается очевидное решение — подставить тег LXP <putvar> внутрь тега HTML. Тем не менее у такого подхода имеется существенный недостаток. Дело в том, что такие синтаксические конструкции нарушают целостность разметки в документе. В языках разметки правильно оформленный документ означает недопустимость вложения тегов в содержимое других тегов, как в следующем фрагменте:
<1хр>
<!-- Подобное вложение тегов не рекомендуется -->
<img src=:'/irnages/spacer.gif" widtn="<putvar name="width" />">
<lхр>
В некоторых ситуациях вложение тегов LXP во внешние теги может благополучно работать, но делать это не рекомендуется. Возможно, требования к правильно оформленному документу LXP в будущем станут более жесткими, поскольку подобное вложение не только затрудняет чтение LXP, но и нарушает синтаксическую целостность разметки.
Для решения подобных проблем в LXP был введен тег <xtag>. Этот тег выполняет функции «оболочки» для отображения внешних тегов (то есть тегов, не являющихся тегами LXP). У тега <xtag> имеется один обязательный атрибут xname, который определяет тег, заменяющий <xtag> при обработке LXP. Например, тег <xtag xname="a"> отображается в виде тега <а>.
Необязательный атрибут xappend позволяет присоединить произвольную строку к концу сгенерированного тега. Например, атрибут xappend=" checked" в теге флажка HTML создает тег <input type="checkbox" checked>.
Все остальные атрибуты передаются внешнему тегу без изменений. Отчасти именно это обстоятельство объясняет полезность тега <xtag>, поскольку переменные, подставленные в <xtag>, автоматически подставляются в полученный внешний тег. В качестве примера в листинге 13.31 приведен правильный способ оформления тега HTML <1mg> в LXP.
Листинг 13.31. Подстановка во внешнем теге с пустым блоком
<1хр>
<xtag xname-"img" src="images/spacer.gif" width="$width" />
</lxp>
Результат выполнения этого фрагмента в документе LXP (предполагается, что переменной width присвоено значение 10):
<1mg src="images/spacer/gif" width="10" />
Обратите внимание на завершающий символ / в теге <xtag>. Тег <xtag> может быть открывающим, закрывающим пли тегом с пустым блоком в зависимости от того, какой тег в конечном счете требуется вывести. Важнейшая особенность этих тегов заключается в том, что LXP отслеживает все «незакрытые» теги <xtag> и выбирает соответствующее имя тега при достижении закрывающего тега </xtag>.
Если тег <xtag> создается для внешнего тега с пустым блоком (например, для тега HTML <img>), вы обязаны оформить <xtag> в виде тега с пустым блоком
и завершающим символом /. В противном случае LXP примет ближайший закрывающий тег </xtag> за парный тег последнего открывающего тега <xtag> (в нашем случае — <img>), что приведет к неверному сопоставлению тегов. Рассмотрим следующий фрагмент:
<1хр>
<xtag xname="table" width="$table_w1dth">
<tr>
<-- ОШИБКА: тег с пустым блоком должен заканчиваться символом / -->
<td><xtag xname="img" src="images/spacer.gif" w1dth="$width"></td>
</tr>
</xtag>
</lxp>
В этом фрагменте используются три тега <xtag>. Два из них (открывающий и закрывающий) относятся к тегу <table>, а третий (открывающий) инкапсулирует тег <img>. Поскольку в HTML тег <img> не имеет парного завершающего тега, этот тег <tag> должен быть тегом с пустым блоком, но LXP не воспринимает его в этом качестве (обратите внимание на отсутствие завершающего символа /). Проблема заключается в следующем: LXP помнит о существовании открытого элемента <xtag> и при достижении первого закрывающего тега </xtag> считает, что закрывается не Ter<table>, а тег<img>.
Если переменная table_width равна 100, а неременная width равна 10, неправильный результат будет выглядеть так:
<table width="100">
<tr>
<-- ОШИБКА: тег с пустым блоком должен заканчиваться символом / -->
<td><img src="images/spacer.g1f" w1dth="10"></td>
</tr>
</img>
В листинге 13.32 приведена правильная комбинация тегов <xtag>.
Листинг 13.32. Использование вложенных тегов <xtag>
<1хр>
<xtag xname="table" width="$table_width">
<tr>
<-- ПРАВИЛЬНО: тег с пустым блоком заканчивается символом / -->
<td><xtag xname="img" src="1mages/spacer.gif" width="$width" /></td>
</tr>
</xtag>
</lxp>
Поскольку второй тег <xtag> в листинге 13.32 завершается символом /, как это должно быть при инкапсуляции внешних тегов с пустым блоком, LXP не связывает закрывающий тег с тегом <img>, и результат выглядит так:
<table width="100">
<tr>
<-- ПРАВИЛЬНО: тег с пустым блоком заканчивается символом / -->
<td><img src="images/spacer.gif" width="10" /></td>
</tr>
</table>