Самоучитель по SQL-сервер в Linux

         

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


Самоучитель по SQL-сервер в Linux

         

Знакомство с разметкой LXP

Хотя LXP решает задачи, традиционно относящиеся к области программирования, при проектировании LXP авторы стремились к тому, чтобы эти задачи решались без изменения общего синтаксиса, используемого при разметке HTML (или XHTML). На сервере документ LXP выглядит как обычный файл HTML с некоторыми незнакомыми тегами.

Рассмотрим пример простого документа LXP:

<lхр>

<dock type="1nit"> <include src="parts/init.lxp" />

</dock>

<1nclude src="parts/head.html" />

<hl>Welcome</hl> <hr width="400">

<if Ixp.authenticated-'t'>

Welcome to my webpage. <putcookie name="user" />

</if> <else>

<strong>Please login.</strong>

<include src="parts/login.lxp" />

</e!se>

include src="Darts/foot.html" />

</lxp>

Теги LXP

Теги (формально называемые элементами) определяются как последовательность символов, начинающаяся с символа < и заканчивающаяся символом >. Теги всегда начинаются с имени, определяющего смысл тега. Кроме того, в них могут присутствовать атрибуты, разделенные пробелами. Атрибуты всегда определяются в формате имя=значение, где имя — имя атрибута, уникальное для данного тега, а значение — некоторое произвольное значение, присвоенное этому атрибуту.

Теги LXP соответствуют общей структуре тегов любого языка разметки. Пара тегов определяет регион (пли блок), который начинается открывающим тегом (например, <tag>) и завершается парным закрывающим тегом с префиксом / (например, </tag>).

Модуль лексического разбора LXP не требует обязательного включения завершающих символов / в теги с пустыми блоками, хотя в некоторых случаях отсутствие этого символа приводит к непредсказуемым последствиям. Например, при вложении тегов <1nclude> с опущенным завершающим символом / могут возникнуть проблемы с принятием решений. Дело в том, что тег <1ncl ude> может быть как тегом с пустым блоком (при включении внешнего документа), так и открывающим тегом, для которого должен существовать закрывающий тег (как при непосредственном включении запросов SQL).

ПРИМЕЧАНИЕ

Привыкните к тому, чтобы включать завершающий символ / в теги с пустым блоком. В HTML некоторые теги формально не требуют завершителя (например, используется тег <Ьг> вместо принятого в XHTML тега <Ьг />). Тем не менее с ростом популярности XHTML и XML требования к размеченным документам становятся более жесткими.

Открывающие теги, как и теги с пустым блоком, обладают именами и содержат атрибуты. Если имя описывает общий смысл тега, то атрибуты обычно определяют детали выполняемой операции, а их смысл зависит от конкретного тега. Закрывающий тег должен состоять из одного имени, указанного после начального символа / (например, </tag>).

В тегах LXP и именах атрибутов регистр символов обычно не учитывается, хотя в некоторых случаях имя атрибута напрямую соответствует имени переменной (как в теге <i f >). В этом случае регистр символов может оказаться существенным в зависимости от написания имен переменных. В приведенных ниже примерах используются символы нижнего регистра, что отчасти связано с влиянием стандарта XHTML (согласно которому имена элементов и атрибуты записываются в нижнем регистре).

В листинге 13.6 приведен простой блок разметки LXP с одним открывающим тегом, одним закрывающим тегом и двумя тегами с пустым блоком.

Листинг 13.6. Простой блок разметки LXP

<1хр>

<setvar example="test" />

<putvar name="example" />

<1хр>

LXP ориентируется на простоту и удобство интеграции при разработке приложений, и этот базовый структурный аспект LXP дает хороший пример такого подхода.

Блоки LXP

Вероятно, самым важным тегом LXP является тег <1 хр>, открывающий блок LXP. Как и тег <script> или короткий тег РНР, он указывает модулю LXP на начало данных LXP.

Однако в отличие от РНР в процессе обработки блока LXP модуль просто игнорирует любые теги, которые он не опознает как теги LXP. Тег <1 хр> просто активизирует возможность использования тегов LXP в заданном блоке, но при этом вы по-прежнему можете работать с обычными тегами HTML (хотя теги LXP могут управлять включением кода HTML в выходной ноток).

Как нетрудно догадаться, тег </1 хр> закрывает блок LXP и запрещает использование тегов LXP до следующего открывающего тега <1хр>.

ПРИМЕЧАНИЕ

Обработка тегов LXP не включается в документах LXP автоматически. Документ выводится быстрее, если блоки LXP будут ограничены теми областями, в которых используются возможности LXP, поскольку обработка блока LXP с динамическим содержимым занимает больше времени, чем обработка простого кода HTML.


Переменные и объекты LXP

Переменной называется изменяемое значение в памяти, доступ к которому осуществляется по имени. Имя требуется для идентификации и последующего использования того значения, которое оно представляет. Конкретные возможности переменной зависят от тега LXP.

В LXP также реализована особая разновидность структуры данных, называемая объектом. Объект LXP обычно используется для логического объединения нескольких взаимосвязанных переменных под общим именем. Конкретная переменная, к которой вы обращаетесь в объекте LXP, определяется либо уточняющим числовым или текстовым индексом в квадратных скобках (например, ехапр1е[0]), либо именем переменной через точку (например, for.count).

Концепция объектов LXP напоминает программные концепции массивов и объектов в традиционных языках программирования, хотя объекты LXP устроены гораздо проще. В сущности, различия между переменными и объектами сводятся к простому синтаксису ссылок на значения. Ссылка на переменную представляет собой простое имя (например, my_value), а ссылка на объект состоит из имени и уточнения (например, my_va1ue[0], my_value[l] или my_value.s1ze).

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

Правила формирования имен

Имена переменных LXP состоят из следующих символов:

буквы латинского алфавита (a-z, A-Z); цифры (0-9); символ подчеркивания (_).

Полные имена объектов LXP состоят из следующих символов:

буквы латинского алфавита (a-z, A-Z); цифры (0-9); символ подчеркивания (_); точка (.); квадратные скобки ([ ]).

Хотя для индексации больше характерны числа — поскольку они используются и массивах CGI (см. подраздел «Массивы CGI» в этом разделе), в квадратных скобках за именем объекта могут следовать любые допустимые символы (например, pseudo_array [example]).

В процессе лексического разбора атрибутов тега LXP некоторые специальные символы интерпретируются как признак подстановки значения переменной прямо в имя или значение атрибута (дополнительная информация приведена в разделе «Лексический разбор тегов»). К числу этих символов относится знак $ для переменных и знак @ для объектов.

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

Использование переменных и объектов

Значение переменной можно вывести в любой точке блока LXP при помощи тега <putvar>. Синтаксис тега <putvar> (переменная — имя переменной, значение которой требуется вывести):

<putvar name="переменная" />

Теги <setvar> и <setvars> присваивают значения переменным. Синтаксис:

<setvar переменндя="значение" />

<setvars переменная1="значение!"

переменная2="значение2"

[...]

/>

Теги <putvar> и <setvar> позволяют выводить и присваивать значения не только переменным, но и объектам.

ПРИМЕЧАНИЕ

Помните, что точка (.) и квадратные скобки ([ ]) в теге <setvar> означают, что значение присваивается не простой переменной, а объекту. Таким образом, при последующей подстановке этого значения вместо знака $ должен использоваться знак @.

Аргументы CGI

LXP, как и многие языки web-программирования, ведет внутренний список переданных аргументов CGI. В LXP эти аргументы косвенно интерпретируются как переменные.

ПРИМЕЧАНИЕ

В контексте этой главы термины «аргумент» и «переменная» практически эквивалентны. Ниже термин «аргумент» обычно употребляется по отношению к переменным, переданным формой, а термин «переменная» — по отношению к переменным в памяти (либо переданным формой, либо заданным разработчиком).

Аргументы передаются формами с именем и значением. Для каждого аргумента, переданного документу LXP (например, через форму HTML), создается переменная, имя которой совпадает с именем аргумента.

При передаче двух одноименных аргументов используется последнее значение, переданное форме (кроме массивов — см. подраздел «Массивы CGI»).

Массивы CGI

Объекты часто используются при работе с массивами CGI. Обычно при передаче документу LXP нескольких аргументов с одинаковыми именами используется последний аргумент, а предыдущие значения игнорируются. Но если имя передаваемого аргумента CGI завершается парой квадратных скобок (например, <select name="test[] ">), то в объект LXP автоматически включается массив значений, присвоенных имени перед квадратными скобками.

Иначе говоря, любой переданный формой CGI аргумент, имя которого заканчивается квадратными скобками (например, test[]), автоматически интерпретируется LXP как массив. Когда такой аргумент передается LXP формой, все присвоенные ему значения автоматически накапливаются в отдельной переменной и различаются по значениям числовых индексов, указываемых в квадратных скобках за именем объекта.

Например, если форма HTML передает аргумент с именем test[], которому присваиваются три значения, в объекте test создается массив из трех элементов. Они обозначаются соответственно test[0], test[l] и test[2].

Объекты непосредственных запросов SQL

При непосредственном выполнении запросов SQL на поля итогового набора можно ссылаться при помощи специального объекта thi s. Ссылки имеют вид thi s. поле, где поле — имя поля.

Также создается объект sql с метаданными, описывающими итоговый набор, — номером текущей записи в наборе (sql. row), смещением текущей записи (sql. offset), количеством записей, выбранных при последнем запросе SQL (sql .numrows), и количеством полей в последнем запросе SQL (sql . numcols или sql .numfields).

Глобальные объекты LXP

Два специальных объекта, 1хр и env, являются системными объектами и содержат информацию о LXP и переменных среды.

К любой переменной среды, заданной в конфигурации CGI Apache (например, REMOTE_ADDR), можно обратиться в формате env .переменная. Например, значение переменной env.REMOTE_ADDR определяет адрес удаленного клиента, обращающегося к текущему документу (если эта возможность была включена в Apache).

Объект 1 хр зарезервирован для системных целей. В версии 0.8 он содержит только три переменные, из которых самой полезной является Ixp.value — путь URI, полученный сервером для текущего запроса LXP (например, /app/index.lxp).

Кроме того, в переменной 1 хр. versi on хранится версия используемого программного пакета LXP, а в переменной Ixp. copy right — информация об авторских правах.

Пользователи, передающие данные документу LXP, не могут передавать переменные с префиксом 1хр. в операциях GET и POST. Таким образом, любая переменная, начинающаяся с префикса 1хр., является защищенной и может использовать-

ся только в документах LXP и только с тегом <setvar>. Данное свойство помогает защитить конфиденциальную информацию, например результаты парольной аутентификации.




Использование 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:); знак «больше» (&gt;); апостроф (&apos:); кавычка (&quot;).

Подстановка сущностей иногда бывает очень полезной — если апострофы и кавычки должны входить в значения атрибутов тегов LXP, вставить их без использования сущностей не удастся. Разработчики LXP рассматривали возможность поддержки экранирующих префиксов \ (как обычно делается в других языках программирования), но непосредственная работа с сущностями лучше соответствует стилю разметки и поднимает язык на более высокий уровень.

В листинге 13.11 приведен пример подстановки сущности в теге LXP<include>.

Листинг 13.11. Подстановка сущности

<1хр>

<setvar field="field_two" />

<include sql="SELECT f1eld_one. Ifield FROM &quot:CAPITALIZED_TABLE&quot;"

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>