Раздел: Учебники / Учебник по HTML
Выполняемые сценарииОсновы объектно-ориентированных технологий Данный раздел посвящен основам объектно-ориентированных технологий (ООТ). Без знания основополагающих понятий ООТ невозможно понимание программирования на языках сценариев, которые реализуют простую объектную модель, непосредственно связанную с документом HTML. He имея никакого представления о событийных приложениях, трудно создать интерактивные, встроенные в документ сценарии. Реальный мир, в котором мы живем, "населен" разнообразными объектами. Нам не надо определять, что это такое: от момента рождения до смерти мы видим и взаимодействуем с объектами. Одни объекты статичны (дом, в котором мы живем), другие объекты могут перемещаться при определенном воздействии на них (машина, в которой мы ездим), третьи могут развиваться сами по себе (мы сами, животные, растения). Все объекты непохожи друг на друга. Не найти двух совершенно одинаковых домов, деревьев даже одного вида, не говоря уже о животных и людях. Однако все объекты похожи друг на друга в том, что каждый объект обладает некоторым внешним видом, поведением (что он умеет делать), а также возможностью взаимодействия с другими объектами. Конечно, такая грубая абстракция не может являться реальной моделью внешнего мира, но она оказывается полезной при моделировании программным способом реально существующих объектов внешнего мира. Программный объект также обладает некоторым внешним видом или свойствами, отражаемыми в значениях его переменных, и поведением или методами, задаваемыми в виде его процедур. Причем свойства и методы не существуют отдельно друг от друга, а объединены вместе, образуя единый объект с новым качеством. Методы "окружают" свойства объекта, не позволяя напрямую обращаться к ним или менять их значения. Говорят, что свойства заключены в некую "капсулу", инкапсулированы в объект. Доступ к ним предоставляют методы объекта, которые решают, можно ли изменять значения свойств, или можно получить только значение некоторого свойства, установленного разработчиком программного объекта. Это и есть фундаментальное свойство программного объекта: свойства инкапсулированы в объект и доступ к ним осуществляется только посредством методов, предоставляемых объектом. Программный объект схематически можно представить так, как на рис. 9.1. Рис. 9.1. Схематическое представление программного объекта Как видим, методы предоставляют программный интерфейс для доступа к значениям свойств, заключенных в ядре объекта, и являются некоторой внешней оболочкой, защищающей их от несанкционированного или случайного воздействия. Инкапсуляцией называется расположение переменных объекта под защитой методов. Она используется для скрытия деталей реализации от других объектов. Не надо знать биологический механизм роста дерева, для практики достаточно знания, что дерево растет и, например, через столько-то лет оно достигнет состояния, при котором его можно использовать в качестве деловой древесины. Водителю автомашины не обязательно представлять детали реализации коробки передач, ему достаточно знать, что, установив ручку переключения скорости в такое-то положение, автомобиль сможет двигаться с заданной скоростью. Главное знать, какие методы может выполнять объект, а как это реализовано — не столь важно. Таким образом, можно всегда изменить внутреннюю реализацию объекта, не меняя части программы, где используется этот объект. Существование программных объектов самих по себе не имеет никакого смысла. Они дадут преимущества при программировании тогда, когда можно организовать их взаимодействие. И это является следующей основной концепцией объектно-ориентированных технологий. Объекты могут взаимодействовать друг с другом, посылая сообщения с просьбой выполнить некоторый подходящий метод или выполняя метод в ответ на запрос системы. Взаимодействуя, объекты образуют единое целое — программу. Любое сообщение состоит из трех компонентов:
Этих трех компонентов достаточно, чтобы объект точно выполнил, что от него хотят. Здесь мы не будем углубляться в понятия класса, перекрытие методов, механизмов наследования и полиморфизма, которые реализуются объектно-ориентированными системами программирования, например, Java, Visual C++, Delphi. Языки программирования сценариев, как отмечалось выше, реализуют простую объектно-ориентированную модель, и для понимания функционирования и создания сценариев вполне достаточно приведенной информации о программных объектах. Обратиться к свойству или методу объекта можно с использованием стандартного для объектно-ориентированных языков синтаксиса — так называемой точечной нотации. Разные объекты могут иметь свойства и методы с одинаковыми названиями. Чтобы указать, метод какого объекта вызывается, перед именем метода указывается имя объекта, отделенного точкой. Например, если необходимо вызвать метод рост объекта липа, это можно сделать с помощью следующего оператора: липа.рост (...) где в скобках задаются необходимые для выполнения метода параметры. До появления операционных систем с графическим интерфейсом (типа Windows) было распространено так называемое "процедурное" программирование, суть которого заключается в том, что программа жестко определяет, когда и в какой последовательности вызываются те или иные процедуры, в совокупности составляющие программу. Программист должен был заранее разработать и реализовать алгоритм выполнения своей программы. При ее запуске она жестко следовала инструкциям вызова соответствующих процедур. По-иному выглядит работа приложения с графическим интерфейсом. Оно должно реагировать на действия пользователя: нажал ли он кнопку, а если нажал — то какую, хочет ли он выполнить команду какого-либо меню и т. п. В этом случае выполняемая программа не должна следовать один раз и навсегда заданному алгоритму выполнения. Она должна иметь возможность запускать на выполнение процедуры, реализующие действие, которое желает выполнить в данный момент пользователь приложения. Такая технология реализуется с помощью концепции события, которое представляет собой действие пользователя (например, нажатие кнопки) или сообщение, генерируемое операционной системой (открылось закрытое окном другого приложения окно нашего приложения). В OOT любое событие представляется объектом, обратившись к свойствам которого можно получить некоторые параметры сгенерированного события. События и сообщения системы тесно связаны: любое событие являете причиной посылки некоторого сообщения операционной системе. И в то же время некоторые сообщения операционной системы, адресованные приложению, представляются в нем в виде некоторых объектов. Таким образом можно организовать перехват событий в приложении и написать собственную процедуру обработки события, выполняющей все необходимые действия которые, например, должны быть ассоциированы с нажатием некоторое кнопки графического интерфейса приложения. Объектные модели языков сценариев Объектные модели языков сценариев тесно связаны с тэгами HTML. При загрузке страницы HTML в браузер интерпретатор языка создает объекты со свойствами, определяемыми значениями параметров тегов страницы. Говорят, что браузер отражает HTML-страницу в свойствах объектов, и иногда этот процесс называют отражением (reflection). Созданные объекты существуют в виде иерархической структуры, отражающей структуру самой HTML-страницы. На верхнем уровне расположен объект window, представляющий собой активное окно браузера. Далее вниз по иерархической лестнице следуют объекты frame, document, location и history, представляющие соответственно фрейм, непосредственно сам документ, адрес загружаемого документа и список ранее загружавшихся документов, и т. д. Значения свойств объектов отражают значения соответствующих параметров тегов страницы или установленных системных параметров. Более подробно модель объектов JavaScript для клиента рассматривается ниже в этой главе в разделе "Объекты клиента и обработка событий". Для правильного использования объектных моделей следует четко понимать, как браузер компонует страницы и, тем самым, создает иерархию объектов. При загрузке страницы просматриваются сверху вниз, тем самым последовательно происходит компоновка страницы и ее отображение в окне браузера. А это означает, что и объектная модель страницы также формируется последовательно, по мере ее обработки. Поэтому невозможно обратиться из сценария, расположенного ранее какой-либо формы на странице к элементам этой формы. Всегда следует помнить о том, что браузер последовательно сверху вниз интерпретирует содержимое HTML-страницы. Еще один аспект работы с объектами языков сценариев заключается в том, что нельзя изменить свойства объектов. Браузер обрабатывает страницу только один раз, компонуя и отображая ее. Поэтому попытка в сценарии изменить свойство отображенного элемента страницы обречена на провал. Только повторная загрузка страницы приведет к желаемому результату. Примечание Можно динамически изменять содержимое полей ввода элементов форм HTML. Это осуществляется установкой свойства value соответствующего элемента в сценарии, встроенном в HTML-страницу. Язык создания сценариев JavaScript Язык программирования JavaScript разработан фирмой Netscape для создания интерактивных HTML-документов. Это объектно-ориентированный язык разработки встраиваемых приложений, выполняющихся как на стороне клиента, так и на стороне сервера. Синтаксис языка очень похож на синтаксис языка Java — поэтому его часто называют Java-подобным. Клиентские приложения выполняются браузером просмотра Web-документов на машине пользователя, серверные приложения выполняются на сервере. Примечание Языки Java и JavaScript являются совершенно разными языками, ориентированными на выполнение разных задач в сети, но дополняющими друг друга при создании сложных сетевых приложений. При разработке обоих типов приложений используется общий компонент языка, называемый ядром и включающий определения стандартных объектов и конструкций (переменные, функции, основные объекты и средство LiveConnect взаимодействия с Java-апплетами), и соответствующие компоненты дополнений языка, содержащие специфические для каждого типа приложений определения объектов. На рис. 9.2 схематически представлено взаимодействие компонентов JavaScript при создании клиентских и серверных приложений. Клиентские приложения непосредственно встраиваются в HTML-страницы и интерпретируются браузером по мере отображения частей документа в его окне. Серверные приложения для увеличения производительности предварительно компилируются в промежуточный байт-код. В данном разделе описывается ядро JavaScript версии 1.3 и дополнительные возможности разработки клиентских приложений. Примечание Фирма Microsoft разработала свой интерпретатор языка JavaScript, который она называет JScript. Рис. 9.2. Компоненты JavaScript Прежде чем переходить к обзору языка JavaScript, перечислим основные области его использования при создании интерактивных HTML-страниц:
В настоящее время трудно найти в Интернете HTML-страницу, не содержащую ни одного оператора языка JavaScript. Любой Web-мастер или создатель собственной страницы в Интернете заботится о том, чтобы как можно большее число потенциальных посетителей разработанного сайта или личной страницы увидели в окне своего браузера именно то, что задумывалось разработчиком страницы. Дело в том, что наиболее популярные на настоящий момент браузеры могут поддерживать не все существующие технологии, реализованные в HTML, или использовать их несколько отлично друг от друга. Поэтому практически любая страница содержит определение и вызов функции языка JavaScript для идентификации используемого пользователем браузера, а также его версии. Приложение JavaScript представляет набор операторов языка, последовательно обрабатываемых встроенным в браузер интерпретатором. Каждый оператор можно располагать в отдельной строке. В этом случае разделитель (;), отделяющий один оператор от другого, не обязателен. Его используют только в случае задания нескольких операторов на одной строке. Любой оператор можно расположить в нескольких строках без всякого символа продолжения. Например, следующие два вызова функции alert эквивалентны: alert("Подсказка"); alert( "Подсказка" ); Строковый литерал обязательно должен располагаться на одной строке. Если необходимо задать его в нескольких строках, то следует разбить его на более мелкие строковые литералы и использовать оператор конкатенации строк для соединения полученных мелких строк в одну длинную. В этом случае каждый литерал можно располагать на отдельной строке. Для удобства чтения кода приложения в нем можно расположить комментарии. Любая последовательность символов, следующая за двумя косыми чертами (//), рассматривается как комментарий. Этот прием позволяет задать комментарий, расположенный на одной строке. Для задания многострочных комментариев используется синтаксис, заимствованный из языков Java и С. Любая последовательность символов, заключенная между символами (/*) и (*/), интерпретируется как комментарий. Язык JavaScript чувствителен к регистру. Это означает, что строчные и прописные буквы алфавита считаются разными символами. Размещение операторов языка на странице Встроить сценарий JavaScript в HTML-страницу можно несколькими способами:
Для внедрения в HTML-страницу сценария JavaScript в спецификацию языка HTML был введен тэг-контейнер <SCRIPT>...</SCRIPT>, внутри которого могут располагаться операторы языка JavaScript. Обычно браузеры, не поддерживающие какие-нибудь теги HTML, просто их игнорируют, анализируя, однако, содержимое пропускаемых тегов с точки зрения синтаксиса языка HTML, что может приводить к ошибкам при отображении страницы. Во избежание подобной ситуации следует помещать операторы языка JavaScript в контейнер комментария <!-- ... -->, как показано ниже <SCRIPT [LANGUAGE="JavaScript"]> <!--
//--> </SCRIPT> Параметр LANGUAGE задает используемый язык сценариев. В случае языка JavaScript его значение задавать не обязательно, так как этот язык используется браузерами по умолчанию. Для языка сценариев VBScript необходимо явно задать значение этого параметра в виде строки "VBScript". Примечание Символы (//) перед закрывающим тэгом комментария --> являются оператором комментария JavaScript. Он необходим для правильной работы интерпретатора. Документ может содержать несколько тегов <SCRIPT>, расположенных в любом месте документа. Все они последовательно обрабатываются интерпретатором JavaScript по мере отображения частей документа в окне браузера. В связи с этим ссылка на переменную, определенную в сценарии, размещенном в конце документа, может привести к генерации ошибки интерпретатора при обращении к такой переменной из сценария в начале документа. Поэтому рекомендуется размещать сценарии с глобальными функциями и переменными в разделе <HEAD> документа. В этом случае все определения обрабатываются интерпретатором в начале загрузки документа и хранятся в памяти с первых моментов отображения документа в окне браузера. Задание файла с кодом JavaScript Тэг <SCRIPT> имеет параметр SRC, позволяющий связать встраиваемый сценарий с внешним файлом, содержащим программный код на языке JavaScript. В качестве значения параметра задается полный или относительный URL-адрес ресурса. Задание закрывающего тега </SCRIPT> обязательно, независимо от того, заданы или нет операторы внутри тэга. Следующий фрагмент кода связывает документ HTML с файлом-источником, содержащим некоторый набор функций: <SCRIPT SRC="http://home.bhv.com/functions/jsfuncs.js">
</SCRIPT> Примечание Связываемый внешний файл не должен содержать тегов HTML и должен иметь расширение JS. Операторы внутри тега <SCRIPT> игнорируются браузером, если только не произошла ошибка при включении файла в страницу, например, файл не найден. Можно разместить внутри тега операторы, выводящие сообщение об ошибке загрузки файла. Следующий сценарий использует метод alert объекта document для вывода диалогового окна с сообщением: <SCRIPT SRC="http://home.bhv.com/functions/jsfuncs.js"> <!--
//--> </SCRIPT> Элементы JavaScript в параметрах тегов HTML Переменные и выражения JavaScript можно использовать в качестве значений параметров тегов HTML. Эта процедура аналогична процедуре встраивания числовых или символьных примитивов HTML. Элементы JavaScript также располагаются между амперсандом (&) и точкой с запятой (,-), но должны заключаться в фигурные скобки {} и использоваться только в качестве значений параметров тегов HTML. Пусть определена переменная barwidth, и ей присвоено значение 75. Следующий тег нарисует горизонтальную линию длиной в 75% от горизонтального размера окна браузера: <HR WIDTH="&{barWidth};%" ALIGN="LEFT"> Предупреждение Нельзя использовать элементы JavaScript в тексте HTML. Они интерпретируются только тогда, когда расположены справа от параметра и задают его значение. Например, попытка использовать значение переменной myVar в следующем фрагменте <H4> &{myVar}; </H4> обречена на провал. Вместо ожидаемого значения переменной myVar браузер отобразит строку myVar. Для совместимости с языками сценариев в некоторые теги HTML были введены специальные параметры обработки возникающих событий. Значениями этих параметров могут быть операторы языка JavaScript. Обычно в качестве значения задается имя функции, которая вызывается, когда происходит соответствующее событие, определяемое параметром обработки события. Имя параметра начинается с приставки on, за которым следует имя самого события. Например, параметр обработки события click (щелчок кнопкой мыши) будет иметь имя onclick. События в основном связаны с действиями, производимыми пользователем с элементами форм HTML. Поэтому чаще всего перехват и обработка событий задается в параметрах элементов форм, что позволяет проверить введенную информацию перед ее отправкой на обработку CGI-сценарием. Здесь кратко остановимся на функциях JavaScript. Функция или процедура — это именованная последовательность операторов, которая выполняет определенную задачу и может возвращать некоторое значение. Функция определяется оператором function, имеющем следующий синтаксис: function имя_функции([параметры]) {
} Параметры, передаваемые функции, разделяются запятыми. Необязательный оператор return в теле функции (блок операторов, заключенный в фигурные скобки), определяет возвращаемое функцией значение. Следует четко понимать различие между объявлением функции и ее вызовом. Объявление функции только задает ее имя и определяет, что она будет делать при ее вызове. Непосредственное выполнение функции осуществляется, когда в сценарии вызывают ее и передают действительные параметры. Определение необходимых функций следует осуществлять в тэге <HEAD>, так как все определенные в нем операторы сценария интерпретируются до отображения страницы, и, таким образом, будут известны в процессе отображения всей страницы. Следующий пример демонстрирует задание функции и ее вызов в процессе формирования страницы документа. Пример 9.1. Задание функции и ее вызов <HEAD> <SCRIPT LANGUAGE="JavaScript"> <!-- //Скрыть сценарий от браузеров: не поддерживающих JavaScript function square(number) { alert("Мне надо вычислить функцию и потом сформировать документ!"); return number * number; } //--> </SCRIPT> </HEAD> <BODY> <P>Начинается отображение страницы, в которую внедрен сценарий вычисления функции</P> <SCRIPT> <!-- document.write("Значение, которое вычислялось, равно ", square(5), "."); //--> </SCRIPT>
Теперь формирование страницы закончено. </BODY> В тэге <HEAD> задано описание функции square (), которая возвращает квадрат значения своего параметра, а также отображает окно сообщения. Вызов функции осуществляется в сценарии, размещенном в теле HTML-документа. В этом сценарии используется метод write объекта document для формирования вывода в HTML-страницу. При загрузке этого документа в браузер Internet Explorer отображается первый абзац, а затем выводится окно сообщения, как на рис. 9.3. Рис. 9.3. Отображение окна сообщения Нажатие на кнопку ОК закрывает окно сообщения, и продолжает отображение страницы. Окончательный вид полученной страницы можно видеть на рис. 9.4. Рис. 9.4. Динамически сформированная страница Следующий пример демонстрирует прием явного вызова функции из сценария. Стилем хорошего программирования, однако, является неявный вызов функций через параметры обработки событий элементов форм. Пример 9.2. Прием явного вызова функции из сценария <HEAD> <SCRIPT LANGUAGE="JavaScript"> //Скрыть сценарий от браузеров: не поддерживающих JavaScript function validate(form) {
} //--> </SCRIPT> </HEAD> <BODY> <FORM name="Form_1"> Ваш возраст: <INPUT type="text" size=5 name="age"><HR> <INPUT type="button" value="Подтвердите"
</FORM> </BODY> В этом примере обработчик события onclick кнопки формы связан с вызовом функции validate, которой передается значение, введенное в текстовое поле age. Имя поля задается параметром name. При нажатии на кнопку вызывается функция validate, отображающая сообщение в зависимости от введенного значения. Параметр name элемента формы задает символическое имя элемента, которое можно использовать в операторах сценария для ссылки на соответствующий элемент. Передаваемый функции параметр this.form.age использует синтаксис объектно-ориентированных языков, обозначающий элемент с именем age (текстовое поле) формы. Ключевое слово this языка JavaScript означает в данном случае ссылку на текущую форму. В функции используется свойство value элемента Текстовое поле формы для анализа введенного пользователем значения. На рис. 9.5 показан результат взаимодействия с загруженной в браузер страницей. Рис. 9.5. Результат взаимодействия с кнопкой формы HTML Этот раздел посвящен элементам языка, общим для клиентской и серверной частей JavaScript. Здесь вводятся основные понятия языка, операторы и стандартные объекты и функции. Как и любой другой язык программирования, JavaScript использует переменные для хранения данных определенного типа. Реализация JavaScript является примером языка свободного использования типов. В нем не обязательно задавать тип переменной. Ее тип зависит от типа хранимых в не£ данных, причем при изменении типа данных меняется и тип переменной. JavaScript поддерживает четыре простых типа данных:
Для присваивания переменным значений основных типов применяются литералы — буквальные значения данных соответствующих типов. Целые литералы являются последовательностью цифр и представляют обычные целые числа со знаком или без знака: 123 // целое положительное число -123 // целое отрицательное число +123 // целое положительное число Для задания вещественных литералов используется синтаксис чисел с десятичной точкой, отделяющей дробную часть числа от целой, или запись вещественных чисел в научной нотации с указанием после символа "е" или "Е" порядка числа. Пример правильных вещественных чисел:
Строковый литерал — последовательность алфавитно-цифровых символов, заключенная в одинарные (') или двойные кавычки ("), например: "Анна", 'АННА'. Примечание При задании строковых переменных нельзя смешивать одинарные и двойные кавычки. Недопустимо задавать строку, например, в виде "Анна'. Предупреждение Двойные кавычки — это один самостоятельный символ, а не последовательность двух символов одинарных кавычек. Если в строке нужно использовать символы кавычек, то строковый литерал необходимо заключать в кавычки противоположного вида: "It's a string" //Значение строки равно It's a string Булевы литералы имеют два значения: true и false, и используются для обработки ситуаций да/нет в операторах сравнения. Каждая переменная имеет имя, которое должно начинаться с буквы латинского алфавита, либо символа подчеркивания "_", за которыми следует любая комбинация алфавитно-цифровых символов или символов подчеркивания. Следующие имена являются допустимыми именами переменных Temp1 MyFunction _my_Method Определить переменную можно двумя способами:
Оператор var используется как для задания, так и для инициализации переменной и имеет синтаксис: var имя_переменной [= начальное_значение]; Необязательный оператор присваивания задает данные, которые содержит переменная. Их тип определяет и тип переменной. Например, следующий оператор var weekDay = "Пятница"; задает переменную weekDay, присваивает ей строковое значение "Пятница", и тем самым определяет ее тип как строковый. Если при определении переменной ей не присвоено никакого значения, то ее тип не определен. Ее тип будет определен только после того, как ей будет присвоено некоторое значение оператором присваивания =. Этот оператор можно использовать в любом месте программы, меняя тем самым тип переменной. Это обстоятельство отличает язык JavaScript от строго типизированных языков программирования (например, Java или C++), в которых тип переменной должен быть определен до ее использования. В следующем фрагменте кода переменная weekDay меняет свой тип:
Выражение — это комбинация переменных, литералов и операторов, в результате вычисления которой получается одно единственное значение, которое может быть числовым (целым или вещественным), строковым или булевым. Переменные в выражениях должны быть инициализированы либо в операторе var, либо оператором присваивания. Если при вычислении выражения встречается неинициализированная или вообще не определенная переменная, то интерпретатор генерирует ошибку "undefined variable" ("переменная не определена"), указывая ее местоположение на странице HTML. Примечание В JavaScript определен специальный литерал null для обозначения неопределенного значения. Если переменной присвоено значение null, то она считается инициализированной, и при вычислении выражения с такой переменной ошибка не генерируется. Оператор присваивания рассматривается как выражение присваивания, которое вычисляется равным выражению правой части, и в то же время он присваивает вычисленное значение выражения переменной, заданной в левой части оператора. Кроме выражения присваивания в JavaScript существует три типа сложных выражений:
Для построения выражений применяются операторы, соответствующие типу выражения. Арифметические выражения создаются арифметическими операторами (табл. 9.1). Таблица 9.1. Арифметические операторы
Ниже представлены арифметические выражения в операторах присваивания: speed = 5.5; time = 4; distance = speed * time; distance = (speed ++)*time; В последнем операторе скорость (переменная speed) увеличивается на единицу и вычисляется пройденное расстояние. Операторы в выражении вычисляются слева направо с учетом общепринятого старшинства арифметических операций. Скобками можно изменить порядок выполнения арифметических операций. Кроме простого оператора присваивания (=) существуют сокращенные формы операторов присваивания, совмещенных с арифметическими операторами, в которых производятся арифметические действия над левым и правым операндами и результат присваивается переменной, заданной левым операндом. Все они перечислены в табл. 9.2. Таблица 9.2. Сокращенные операторы присваивания
Для создания логических выражений используются операторы сравнения и логические операторы, применяемые к переменным любого типа. Операторы сравнения аналогичны таковым в других языках программирования. Их список представлен в табл. 9.3. Таблица 9.3. Операторы сравнения
При использовании этих операторов в выражении оно вычисляется равным true, если соответствующее сравнение верно, в противном случае значение выражения равно false. Логические операторы представлены в табл. 9.4. В примерах предполагается, что переменная var1 = 'Кит',var2 = 'Кот', var3 = false. Таблица 9.4. Логические операторы
Логические операторы и операторы сравнения используются в операторах цикла и условия для проверки завершения цикла или выполнения определенной группы операторов. Строковые операторы используются для создания строковых выражений. В JavaScript, собственно говоря, существует только один строковый оператор — оператор конкатенации (соединения) строк (+), если не считать сокращенной формы оператора присваивания со сложением (+=). Этот оператор присоединяет к строковому значению первого операнда строковое значение второго, получая результат, равный соединению строк: string = "Моя" + "строка"; // Значение переменной string равно "Моястрока" Примечание Оператор + может использоваться со смешанными типами операндов. Все операнды приводятся к строковому типу, если хотя бы один из операндов содержит строковый литерал. Например, выражение "Май" + 1.999еЗ будет вычислено равным строке "Май1999", а "Май" + t будет равно "Mautrue", если переменная t содержит булево значение true. Условный оператор является единственным оператором, использующим три операнда. Его значением является один из двух операндов, определяемый из условия истинности третьего. Синтаксис его таков: (условие) ? знач1 : знач2; Если операнд условие имеет значение true, то результатом вычисления условного оператора будет знач!, в противном случае — знач2. Например, оператор range = (mark <= 2) ? "Пересдача" : "Зачтено"; присваивает переменной range значение "Пересдача", если переменная mark меньше либо равно 2, в противном случае ей присваивается значение "Зачтено". Кроме перечисленных выше операторов в JavaScript существует большая группа операторов для поразрядных действий с данными. В них содержимое каждого оператора рассматривается как последовательность битов, а не как данные строкового, числового или булевого типов. Их описание можно найти в любом учебнике по языку JavaScript или в технических описаниях на сервере фирмы Netscape по адресу: http://developer.netscape.com/. В ядре JavaScript определены объекты и функции, которые можно использовать вне контекста загруженной страницы. Они доступны как для сценариев на стороне клиента, так и для сценариев на стороне сервера. Объект Array В JavaScript нет типа данных массив, но с помощью объекта Array можно создавать массивы в приложениях и манипулировать ими. Методы этого объекта позволяют сортировать, объединять, записывать в обратном порядке содержимое массивов и выполнять многие другие действия. Наиболее часто используется свойство объекта Array, позволяющее определять количество элементов, содержащихся в массиве. Массив — упорядоченный набор однородных данных, к элементам которого можно обращаться по имени и индексу. Массив создается оператором new и конструктором массива — системной функцией Array, инициализирующей элементы массива. Создать массив можно одной из следующих конструкций: имя_массива = new Array([элемент0, элемент1, . . ., элементы]); имя_массива = new Array([длина_массива]); При использовании первого синтаксиса конструктору массива в качестве параметров передаются значения элементов массива, во второй конструкции задается длина массива. Можно использовать конструктор без параметров, но в этом случае только определяется, что переменная с данным именем используется в качестве массива. Элементы самого массива не заданы, и поэтому к ним нельзя обратиться, пока в сценарии им явно не будут присвоены значения. Для получения значения элемента массива необходимо в квадратных скобках рядом с именем массива указать порядковый номер элемента. Элемент массива можно использовать в выражениях и в левой части оператора присваивания: а[0] = "1"; а[1] = 2; с = b[2]*с[3] ; Примечание В JavaScript нумерация элементов массивов начинается с нуля. Поэтому пер вый элемент имеет индекс 0, второй — 1 и т. д. Примечание В JavaScript версии 1.2 и выше вторая форма задания массива с указанием числа элементов в конструкторе создает массив из одного элемента с целых значением. В предыдущих версиях языка создается массив с заданным числом элементов, значения которых не определены. Массив, являясь объектом, обладает методами, которые вызываются с использованием обычной для объектно-ориентированных языков точечной нотации. В табл. 9.5 перечислены методы объекта Массив. Таблица 9.5. Методы объекта Массив
Предположим, что определены два массива array1 = new Array("Первый","Второй","Третий"); array2 = new Array("Один","Два","Три"); Метод arroy1.join о возвратит строку "Первый, второй, третий"; метод arroy1.sort () упорядочит элементы массива arroy1 (переставив их местами) в алфавитном порядке, а оператор arroy1.concat (array2).sort о объединит два массива в один новый и отсортирует его. Примечание Последний оператор является типичным примером точечной нотации в объектно-ориентированных языках. Метод arroy1.concat (array2) возвращает массив, который является объектом. Следовательно, можно выполнить любой метод этого объекта, в данном случае sort (). Присвоить значение элементу массива можно в любом месте программы. Добавление элементов в конец массив можно осуществлять простым присваиванием значения новому элементу, а не только методом push о. Для определения длины массива используется свойство length. Ниже представлен фрагмент кода, определяющий пятый элемент массива arroy1, и тем самым изменяющий значение его свойства length с 3 на 5: arroy1 = new Array("Первый","Второй","Третий"); 11 = arroy1.length; arroy1[4] = "1"; 12 = arroy1.length; document.write(11); // Напечатает 3 document.write(12); // Напечатает 5 Для задания массивов нескольких размерностей следует значениям элементов массивов присваивать массивы. Подобная техника иллюстрируется следующим фрагментом, в котором создается двумерный массив: а = new Array() for (i=0; i < 4; i++) {
} Здесь в первом операторе определяется массив а. Далее в цикле элементы этого одномерного массива сами определяются как массивы, элементам которых присваиваются значения. Таким образом создается двумерный массив. Объект Date Для представления дат в программе JavaScript используется объект Date. Он создается, как и любой объект в JavaScript, оператором new с помощью конструктора Date. Синтаксис оператора создания даты следующий: имя объекта_дата = new Date([параметры]); В JavaScript дата хранится в виде числа миллисекунд, прошедших от 1 января 1970 года. Если в конструкторе даты отсутствуют параметры, то значением объекта будет текущая дата. Параметром конструктора может быть строка вида "месяц день, год часы:минуты:секунды". Если опустить значения часов, минут и секунд, то по умолчанию они будут иметь значения 0. Можно задать список параметров, задающих год, месяц и день или год, месяц, день, часы, минуты и секунды. Ниже представлены все три способа инициализации объекта Date: today = new Date() Xmas = new Date("January 7, 1999 12:00:00") Xmas = new Date(99, 1, 7) Xmas = new Date (99, 1, 7, 12, 0, 0) Методами объекта Date можно получать и устанавливать отдельно значения года, месяца, дня недели, часов, минут и секунд. Например, метод getYear0 возвращает год, метод setYear () устанавливает значение года объекта Date. Метод getTime0 возвращает число миллисекунд, прошедшее с момента времени 1 января 1970 года 00:00:00, метод setTime0 устанавливает соответствующее значение даты в миллисекундах, заданных в качестве параметра. Объект Math В свойствах объекта Math хранятся основные математические константы, а его методы вычисляют основные математические функции. При обращении к свойствам и методам этого объекта создавать его не надо, но следует явно указывать его имя Math. Например, в свойстве PI хранится значение числа л и использовать его в программе можно в виде Math.pl. Методы этого объекта включают процедуры вычисления тригонометрических, экспоненциальных, логарифмических и других математических функций. В табл. 9.6 собраны все методы объекта Math. Таблица 9.6. Методы объекта Math
Объект String Когда переменной присваивается строковый литерал, она становится, как указывалось выше в разделе "Переменные и литералы", строковой переменной. На самом деле JavaScript не поддерживает строковых типов, а создает стандартный объект string. Таким образом, любая строковая переменная или строковый литерал является объектом string, к которому могут быть применены соответствующие методы этого объекта. Можно явно создать строковый объект, используя ключевое слово new и конструктор string, как показано ниже: имя_объекта = new String(строка); Параметром конструктора является любая допустимая строка. Например: myString = new String("Строка"); Объект string имеет единственное свойство length, хранящее длину строки, содержащейся в строковом объекте. Так, и "Строка ".length, и mystring. length возвращают одинаковые значения 6, равные в первом случае длине строкового литерала, а во втором случае длине строки, содержащейся в строковом объекте. Объект string имеет два типа методов: первые непосредственно влияют на саму строку, например метод substring, а вторые возвращают отформатированный HTML вариант строки, например метод bold. Некоторым методам необходимы параметры. Так, метод получения подстроки требует задания двух целых чисел, определяющих позиции начала и конца ПОДСТРОКИ, например substring (2, 7). Методы, возвращающие HTML-отформатированные варианты строк, соответствуют тэгам форматирования HTML. Например, следующий оператор вставляет в страницу HTML связь с ресурсом, расположенным по адресу, задаваемому параметром метода link: document.write(s.link("http://www.bhv.com")); В документе отобразится содержимое строкового объекта s, представленное как связь с соответствующим ресурсом. В табл. 9.7 перечислены методы строковых объектов. Таблица 9.7. Методы объекта string
Примечание Подробную информацию о работе с методами строкового объекта можно найти в любом учебнике по JavaScript или в Интернете по адресу http:// developer.netscape.com. Стандартные функции верхнего уровня В добавление к стандартным объектам существует несколько функций, для вызова которых не надо создавать никакого объекта. Они находятся вне иерархии объектов JavaScript на так называемом "верхнем уровне". Полезными при разработке приложений могут оказаться две функции, производящие "синтаксический" анализ своих аргументов: parseFloat и parselnt. Функция parseFloat (параметр) анализирует значение переданного ей строкового параметра на соответствие представлению вещественного числа в JavaScript. Если в строке при последовательном просмотре обнаруживается символ, отличный от символов, применяемых для формирования вещественных литералов (знаки + и -, десятичные цифры, точка и символы (е) или (Е)), то она игнорирует оставшуюся часть строки и возвращает то числовое значение, которое ею обнаружено до неправильного символа. Если первый символ в строке не является цифрой, она возвращает значение "NaN" (Not a Number — не число). Аналогично функция parseInt(строка, [основание]) пытается возвратить целое число по заданному вторым параметром основанию. Если первый символ в строке не является цифрой, она также возвращает значение "NaN". Эти функции полезны при анализе введенных пользователем данных в полях формы до передачи их на сервер. Функции Number (объект) и String (объект) преобразуют объект, заданный в качестве его параметра в число или строку. Функция isNaN(параметр) тестирует значение своего параметра на соответствие нечисловому значению. Если ее параметр действительно оказывается не числом, она возвращает true, в противном случае — false. Примечание Подробную информацию о функциях верхнего уровня можно найти в любом учебнике по JavaScript или в Интернете по адресу http://developer.netscape.com. Весь набор операторов управления языка можно разбить на три группы:
В этом разделе кратко обсуждается каждая из указанных групп операторов JavaScript, в совокупности позволяющая создавать высоко интерактивные приложения. Операторы выбора К этой группе операторов относятся операторы, которые выполняют определенные блоки операторов в зависимости от истинности некоторого булевского выражения. Это оператор условия if...else и переключатель switch. Оператор условия if применяется, если необходимо вычислить некоторый блок операторов в зависимости от истинности заданного условия, и имеет следующий синтаксис: if(условие) {
} [else {
} ] Первая группа операторов операторы1 выполняется при условии истинности выражения условие. Необязательный блок else задает группу операторов операторы2, которая будет выполнена в случае ложности условия, заданного в блоке if. Примечание Фигурные скобки, отмечающие группу выполняемых операторов в блоках if и else, необязательны, если группа состоит из одного оператора. Совет Лучше всегда задавать группы выполняемых операторов в блоках if и else заключенными в фигурные скобки. Программа в этом случае легче читается, и проще производить ее модификацию. Внутри группы выполняемых операторов могут использоваться любые операторы JavaScript, в том числе и операторы условия. Таким образом, можно создавать группу вложенных операторов условия и реализовывать сложные алгоритмы проверки. В операторе switch вычисляется одно выражение и сравнивается со значениями, заданными в блоках case. В случае совпадения выполняются операторы соответствующего блока case. Синтаксис этого оператора следующий: switch (выражение){
} Если значение выражения в блоке switch равно значение1, то выполняется группа операторов операторы1, если равно значение2, то выполняется группа операторов операторы2 и т. д. Если значение выражения не равняется ни одному из значений, заданных в блоках case, то вычисляется группа операторов блока default, если этот блок задан, иначе происходит выход из оператора switch. Необязательный оператор break, задаваемый в каждом из блоков сазе, выполняет безусловный выход из оператора switch. Если он не задан, то продолжается выполнение операторов в следующих блоках case до первого оператора break или до конца тела оператора switch. Операторы цикла Оператор цикла повторно выполняет последовательность операторов JavaScript, определенных в его теле, пока не выполнится некоторое заданное условие. В языке существует два оператора цикла: for и while. Они отличаются механизмом организации цикла. Оператор цикла for позволяет организовать выполнение блока операторов заданное число раз. Он определяет переменную, называемую переменной цикла, которая изменяет свое значение во время выполнения цикла. Условие завершения цикла зависит от значения этой переменной. Оператор имеет следующий синтаксис: for([инициал_выражение];[условие];[изменяющее_выражение]) {
} Параметром инициал_выражение задается и инициализируется переменная цикла. Это выражение вычисляется один раз в начале выполнения цикла. После этого проверяется истинность выражения условие. Если оно истинно, то выполняется блок операторов тела цикла, ограниченного фигурными скобками; вычисляется изменяющее_выражение, содержащее переменную цикла, и снова проверяется истинность выражения условие. Если оно истинно, то повторяется цикл вычислений, если нет, то оператор цикла завершает свое выполнение. Примечание Инициализирующее выражение, изменяющее выражение и условие окончания цикла не являются обязательными, и любое из них может быть опущено. Однако следует оставлять разделитель (;) для правильной интерпретации оставшихся выражений. Например, в случае отсутствия условия завершения цикла заголовок цикла for будет выглядеть следующим образом: for(var i=0;;i+2). Следующий цикл выводит в документ значения степеней двойки: for(var i=0; i<=5; i++){ document.write("<p>2<sup>", i, "</sup> = ", Math.pow(2,i)) } Результат работы этого оператора цикла представлен ниже: 20= 1 21 =2 22 = 4 23 = 8 24 = 16 25 = 32 Цикл while выполняется пока истинно выражение, задающее условие выполнения цикла. Его синтаксис следующий: while(условие) {
} Сначала проверяется истинность условия, заданного в заголовке цикла, а затем выполняются (или не выполняются) операторы тела цикла. Проверка истинности условия осуществляется на каждом шаге цикла. Использование этого цикла предполагает, что условное выражение окончания цикла меняется в зависимости от вычисленных значений переменных и выражений в теле цикла. Например, следующий фрагмент кода s = "Example"; i = 0; while (i<s.length) { document.write(s.substr(i,1),"<BR>") i++; } выведет в документ слово "Example" по одной букве в строке. Иногда необходимо завершить цикл не по условию, задаваемому в заголовке цикла, а в результате вычисления некоторого условия в теле цикла. Для этой цели в JavaScript существуют операторы break и continue. Оператор break завершает выполнение цикла и передает управление оператору, непосредственно следующим за оператором цикла. Оператор continue прекращает выполнение текущей итерации и начинает выполнение следующей, т. е. в цикле while он передает управление на проверку выражения условие цикла, а в цикле for — на вычисление выражения изменяющее_выражение. Манипулирование объектами Четыре оператора JavaScript предназначены для работы с объектами. Это оператор new, создающий новый объект (см. выше раздел "Стандартные объекты и функции"), операторы for...in и with и ключевое слово this. Оператор for...in позволяет организовать цикл по свойствам объекта JavaScript. Синтаксис его следующий: for( переменная_цикла in объект) { [операторы] } Этот цикл производит перебор свойств объекта. В переменной цикла на каждой итерации сохраняется значение свойства объекта. Количество итераций равно количеству свойств, существующих у заданного в заголовке цикла объекта. В следующем примере функция properties (), в качестве параметров которой передаются объект и его имя, используется для отображения в HTML документе всех свойств объекта Флажок, созданного на странице тэгом <INPUT>. Пример 9.3. Определение свойств объекта Флажок <HEAD> <SCRIPT LANGUAGE="JavaScript"> <!-- //Скрыть сценарий от браузеров, не поддерживающих JavaScript function properties(obj,obj_name) {
} --> </SCRIPT> </HEAD> <BODY> <INPUT TYPE="checkbox" NAME="check1" value="Флажок"> Флажок <p> <SCRIPT> document.write(properties(check1, check1.value)) </SCRIPT> </BODY> Сама функция описывается в разделе <HEAD>, а ее вызов происходит в теле документа. Для связи элементов управления форм со сценарием применяется параметр NAME тега <INPUT>. Его значение равно переменной, которую используют в сценарии для ссылки на соответствующий элемент управления. В качестве имени объекта в функцию передается значение свойства value объекта checkbox. Предупреждение Вызов функции осуществляется после создания в документе элемента управления checkbox. Попытка вызвать функцию properties () до создания в документе флажка приведет к ошибке интерпретатора, так как объект еще не будет существовать (см. выше раздел "Объектные модели языков сценариев"). Оператор with задает объект по умолчанию для блока операторов, определенных в его теле. Это означает, что все встречаемые в операторах этого блока свойства и методы, являются свойствами и методами указанного объекта. Применение данного оператора избавляет от необходимости указывать иерархию принадлежности объекта и сокращает исходный текст программы. Текст приведенного выше сценария с использованием оператора with упростится следующим образом: <SCRIPT> with( check1) { document.write(properties(check1, value)) } </SCRIPT> Здесь свойство value относится к объекту check1, который указан в заголовке оператора with. Полезно использовать этот оператор для объекта Math. Тогда обращение к его свойствам и методам осуществляется без явного указания префикса Math. Например: with( Math) { r = sin(2.0) // Вычисление синуса 1 = 2*РI*r // Вычисление длины окружности } Объекты клиента и обработка событий Как отмечалось выше, при интерпретации страницы HTML браузером создаются объекты JavaScript, свойства которых представляют значения параметров тегов языка HTML. Объекты хранятся в виде иерархической структуры, отражая структуру документа. Некоторые теги HTML являются контейнерами, В которых могут размещаться другие тэги. Например, тег формы <FORM> содержит элементы управления, задаваемые тэгами <INPUT>. Эта подчиненность одних тегов другим и образует структуру документа, отражаясь в иерархической структуре объектов, соответствующих тэгам HTML. Примечание Не все свойства объектов могут соответствовать значениям параметров тегов HTML. Некоторые свойства могут получать значения от установленных свойств самого браузера. Например, свойство fgColor объекта document отражает установку цвета отображения текста на странице в диалоговом окне предпочтений браузера Netscape Navigator. На самом верхнем уровне иерархии находится объект window, представляющий окно браузера .и являющийся "родителем" всех остальных объектов. Расположенные ниже в иерархии объекты могут иметь свои подчиненные объекты. На рис. 9.6 показана структура объектов клиента (браузера). Рис. 9.6. Иерархия объектов JavaScript на стороне клиента Особняком стоит объект navigator с двумя дочерними (подчиненными) объектами. Он относится к самому браузеру, и его свойства позволяют определить характеристики программы просмотра. Свойство appName содержит имя браузера (для Internet Explorer, например, его значение равно "Microsoft internet Explorer"), а свойство appVersion содержит информацию о версии браузера (например, для Internet Explorer версии 4.01 его значение равно "4.0 (compatible; MSIE 4.01; Windows 95)). Каждая страница в добавление к объекту navigator обязательно имеет еще четыре объекта:
Кроме указанных объектов страница может иметь дополнительные объекты, зависящие от ее содержимого, которые являются дочерними объектами объекта document. Если на странице расположена форма, то все ее элементы являются дочерними объектами этой формы. Для задания точного имени объекта используется точечная нотация с полным указанием всей цепочки наследования объекта. Это возможно, так как объект верхнего уровня имеет свойство, значением которого является объект нижнего уровня. Ссылка на объект осуществляется по имени, заданному параметром NAME тега HTML. Например, пусть в документе задана форма с элементами: <FORM NAME="form1"> Фамилия: <INPUT TYPE = "text" name = "studentName" size = 20> Курс: <INPUT TYPE = "text" name = "course" size = 2> </FORM> Для получения фамилии студента, введенного в первом поле ввода, в программе JavaScript следует использовать ссылку document, form1.studentName.value, a чтобы определить курс, на котором обучается студент, необходимо использовать ссылку document. form1. course.value. Примечание При ссылке на формы и их элементы необязательно указывать объект верхнего уровня document. В приведенном примере сослаться на значение первого поля ввода можно и так form1.studentName.value. Совет Для получения свойств объектов можно воспользоваться сценарием примера 9.3. Свойства и методы ключевых объектов Не все объекты иерархии интенсивно используются в сценариях JavaScript В данном разделе перечислены свойства и методы наиболее часто используемых объектов. Объекты window и Frame Объект window создается автоматически при запуске браузера, так как для отображения документа необходимо окно. В меню Файл (File) любого браузера есть команда Создать (New), позволяющая открыть новое окно и отобразить в нем новый документ, и команда Закрыть (Close) закрытия окна. Эти действия можно осуществлять программно из приложения JavaScript, применяя методы open () и close () объекта window. Новое окно создается методом open (), который имеет следующий синтаксис: имя_перемен_окна=window.open( [имя_файла] , [имя_ссылки_окна] , [параметры] ) Здесь: имя_перемен_окна — имя для ссылки на новое окно в операторах JavaScript, имя_файла — полный или относительный URL-адрес открываемого в окне документа, имя_ссылки_окна — имя, указываемое в качестве цели в гипертекстовой ссылке на это окно из другого документа HTML, параметры — задают значения параметров окна (ширина, высота, наличие панелей инструментов, полос прокрутки и т. п.). Примечание Все три параметра задаются в виде текстовых литералов или переменных и не являются обязательными. Если они все отсутствуют, то открывается новое окно браузера с параметрами по умолчанию. Например, следующий оператор: winExample=window.open
открывает новое окно без панелей инструментов, но с полосами прокрутки, на которое можно ссылаться в сценарии по имени winExampie, и загружает в него документ, расположенный по адресу http://www.bhv.ru/library /index.html. На это окно можно ссылаться из другого документа по имени "linkWin". Вывод во вновь открытое окно осуществляется методом write () объекта document этого окна. Например, в примере 9.3 можно отобразить свойства объекта в новом окне с помощью следующего сценария: <SCRIPT> msgWindow=window.open("","displayWindow","toolbar=no,scrollbars=yes") msgWindow.document.write(properties(check1, check1.value)) </SCRIPT> Результат выполнения сценария показан на рис. 9.7. Закрывается окно методом close () без параметров. Окно документа, в котором находится сценарий, закрывается одним из следующих операторов: window.close() self.close() close() Рис. 9.7. Открытие нового окна и отображение в нем свойств объекта Для закрытия окна, открытого методом open (), необходимо явно указывать имя переменной этого окна: msgWindow.close() Метод alert () объекта window отображает диалоговое окно с текстом, передаваемым в качестве параметра этому методу. Например, следующий сценарий выводит диалоговое окно с информацией для пользователя, если некоторая переменная меньше нуля: if( myVar < 0) alert("Переменная 'myVar' стала отрицательной!") Эта функция полезна в сценариях проверки правильности заполнения полей формы перед отправкой формы на сервер. В HTML тэг-контейнер <FRAMESET>. . .</FRAMESET> задает специальный тип окна, называемый набором фреймов. Это окно может отображать несколько независимых, каждый со своими полосами прокрутки фреймов на одном экране. Каждый фрейм, в свою очередь, может отображать определенный документ, расположенный по адресу, указанному в параметре SRC тега <FRAME>. Набор фреймов образует страницу, поэтому не надо задавать тэг <BODY>. Тэг-контейнер <FRAMESET> может содержать, кроме тегов <FRAME>, определяющих фреймы, другие теги <FRAMESET>, образуя, таким образом, вложенные наборы фреймов. Пример HTML-страницы с вложенными наборами фреймов представлен ниже: <FRAMESET COLS="30%,70%">
</FRAMESET> Значение параметра NAME задает имя, по которому можно ссылаться на соответствующий фрейм в иерархии объектов документа. Отображение страницы с фреймами можно увидеть на рис. 9.8. Рис. 9.8. Отображение страницы с фреймами Эта страница содержит три фрейма, которые образуют иерархическую модель объектов Frame. На верхнем уровне расположен объект top, являющийся родителем всех Трех фреймов на странице (clockFrame, menuFrame и content Frame). Для ссылки на фреймы страницы можно использовать либо символические имена, либо свойство-массив frames объекта top, в котором содержатся ссылки на все фреймы страницы. Так, на первый фрейм можно сослаться двумя способами: top.clockFrame или top.frames[0] Свойство location объекта Frame содержит адрес загруженного во фрейм документа. Изменение значения этого свойства приведет к загрузке нового документа в соответствующий фрейм. Следующий фрагмент кода HTML задает на странице menu.html кнопку с именем "Пример 1": <INPUT TYPE="button" VALUE="Пример 1"
</FORM> При щелчке на кнопке пример 1 выполняется код JavaScript, заданный в качестве значения параметра обработки события onclick. Этот код меняет значение свойства location фрейма contentFrame, что приводит к отображению в нем нового документа пример_1.html. Если загружаемый во фрейм документ сам содержит набор фреймов, то объектная модель немного усложняется. В этом случае все фреймы, отображаемого в заданном фрейме документа, являются подчиненными этому фрейму, который, в свою очередь, порождается от объекта верхнего уровня top. Если, например, в предыдущем примере файл menu.html будет содержать следующий код HTML: <FRAMESET ROWS="30%,70%">
</FRAMESET> то фреймы Frame1 и Frame2 будут порождаться фреймом menuFrame, и для ссылки на один из этих фреймов можно воспользоваться любой из следующих конструкций: top.menuFrame. Frame1 top.frames[2].frames[0] В последней конструкции используется свойство-массив frames любого объекта Frame. Объект document Этот объект содержит информацию о текущей загруженной странице. Все элементы страницы HTML представляются свойствами объекта document (см. рис. 9.6). Для каждой страницы создается один объект document, некоторые свойства которого соответствуют параметрам тэга-контейнера <BODY>: bgColor, fgColor, linkColor, alinkColor и vlinkColor. При работе с этим объектом полезно его свойство URL, содержащее адрес загруженного документа. Этот объект используется наиболее часто в связи с его двумя полезными методами write () и writeln(), которые записывают в документ информацию и, тем самым, позволяют динамически его создавать. Объекты location и history Объект location связан с текущим URL-адресом. Его свойства позволяют получить информацию о хост-машине, с которой в данный момент связан браузер. Например, свойство hostname содержит имя хоста, свойство port — номер порта, к которому подсоединен браузер на хост-машине. Два метода объекта location связаны с загрузкой HTML-страниц. Метод reload о перезагружает в браузер текущую страницу, а метод replace о загружает в окно браузера страницу, адрес которой задан в качестве его параметра. Объект history содержит список адресов HTML-документов, ранее загружавшихся в браузер. Получить адреса текущей, следующей и предыдущей страницы можно с помощью соответственно свойств current, next и previous этого объекта. Метод до () этого объекта загружает страницу из списка посещенных. Текущая страница имеет индекс 0, предыдущие по отношению к текущей страницы индексируются отрицательными целыми числами, а последующие — положительными целыми числами. Например, следующий оператор history.go(-3) загрузит страницу, расположенную на три пункта назад по отношению к текущей в списке посещенных страниц. Объекты Form Каждая форма в документе, определенная тэгом <FORM>, создает объект Form, порождаемый объектом document. Ссылка на этот объект осуществляется с помощью переменной, определенной в параметре NAME тега <FORM>. В документе может быть несколько форм, поэтому для удобства ссылок и обработки в объект Form введено свойство-массив forms, в котором содержатся ссылки на все формы документа. Ссылка на первую форму задается как document, forms [0], на вторую — document. forms [ 1 ] и т. д. Вместо индекса в массиве forms можно указывать строку, значение которой равно имени переменной для формы. Например, если создана одна форма <FORM NAME="form1"> Информация пользователя:
</FORM> то любой из следующих операторов JavaScript содержит ссылку на эту форму: document.forms[0] document.forms["form1"] document.form1 Последний оператор возможен в силу того, что объект document порождает объект Form, и ссылку на него можно осуществлять по обычным правилам наследования языка JavaScript. Все элементы формы порождают соответствующие объекты, подчиненные объекту родительской формы (см. рис. 9.6). Таким образом, для ссылки на объект Text формы form1 следует пользоваться любым из нижеприведенных операторов: document.forms[0].text1 document.fоrms["form1"].text1 document.form1.text1 Каждый объект Form имеет также свойство-массив elements, содержащий ссылки на все подчиненные форме элементы в том порядке, как они определены в документе HTML. Элементы формы, точнее их объекты, имеют свойство name, значение которого равно значению параметра NAME тега <INPUT>, а также свойство value, значение которого определяется смыслом параметра VALUE элемента формы. Например, для элементов text и textarea значением этого свойства будет строка содержимого полей ввода этих элементов, для кнопки подтверждения — надпись на кнопке и т. д. Свойства-массивы объектов Некоторые объекты имеют свойства, которые являются массивами. Они используются для хранения информации о подчиненных объектах, когда их количество заранее не известно (например, массив forms объекта document или массив elements объекта Form). В табл. 9.8 перечислены все объекты, обладающие свойствами-массивами. Таблица 9.8. Свойства-массивы объектов JavaScript
Работа с перечисленными массивами аналогична работе с массивом forms, описанным выше в разделе "Объекты Form". Интерактивные страницы должны реагировать на действия пользователя. Например, при нажатии на кнопку появляется диалоговое окно с сообщением, или выполняется проверка правильности введенных пользователем данных в полях формы. В JavaScript подобная интерактивность реализована возможностью перехвата и обработки событий, возникающих в результате действий пользователя. Для этого в теги некоторых элементов (объектов с точки зрения JavaScript) введены параметры обработки событий, задающие действия, выполняемые при возникновении события, связанного с элементом. Имя параметра обработки события начинается с приставки on, за которой следует название события. Если событием является, например, щелчок кнопкой мыши click, то соответствующий параметр обработки этого события называется onclick; если обрабатываемым событием является нажатие кнопки мыши MouseDown, то параметр называется onMouseDown. В табл. 9.9 представлены возможные события, и в каких элементах документа HTML они могут инициализироваться. Таблица 9.9. События JavaScript
Хорошим стилем программирования является оформление действий, выполняемых при обработке событий, в виде процедур. Процедуры JavaScript Процедура, или функция, — это именованная последовательность операторов, которая инициализируется и выполняется простой ссылкой на имя функции. Процедура задается оператором function, имеющим следующий синтаксис: function имя_функции([параметры]) {
} где имя__функции — любое правильное имя языка JavaScript, параметры — список передаваемых в процедуру параметров, элементы которого отделяются запятыми. Оператор function только определяет процедуру, но не выполняет ее. Для вызова процедуры достаточно указать ее имя с заданными в скобках параметрами. Примечание Если в процедуре параметры отсутствуют, наличие скобок без параметров в операторе вызова процедуры обязательно. Процедура может возвращать некоторое вычисляемое в ней значение. В этом случае обычно она называется функцией, и в операторах, определяющих последовательность выполняемых ею действий, обязательно должен присутствовать оператор return, задающий возвращаемое функцией значение. Вызов функции осуществляется аналогично вызову процедуры, но ее можно использовать в выражениях JavaScript. Обычно все определения процедур и функций задаются в разделе <HEAD> документа. Это обеспечивает интерпретацию и сохранение в памяти всех процедур при загрузке документа в браузер. С процедурами и обработчиками событий тесно связано ключевое слово this. Ключевое слово this Ключевое слово this используется для ссылки на текущий объект и обычно применяется для ссылки на объект при вызове процедуры обработки событий в обработчике событий элемента. Предположим, что для проверки правильности ввода в текстовое поле курса, на котором учится студент, написана процедура validate: function validate(obj){
} Вызов этой процедуры в обработчике событий элемента формы осуществляется следующим образом: <FORM NAME="form1"> <В>Курс, на котором учитесь :</В> <INPUT TYPE="text" NAME="text1" SIZE=3
</FORM> Ключевое слово this в данном контексте ссылается на элемент Текстовое поле ввода text1. Свойство form этого объекта содержит ссылку на текущую форму. Таким образом, получается правильная ссылка на поле ввода в контексте объектной модели документа: document, form1. text1. Объект event В JavaScript каждое событие . порождает ассоциированный с ним объект event. Этот объект содержит всю информацию о событии и его можно передать процедуре обработки события. Информация о событии зависит от конкретного произошедшего события. Например, объект event события MouseDown содержит информацию о типе события (свойство type), какая кнопки мыши была нажата (свойство which), какая клавиша (Ait, shift или Ctrl) удерживалась при щелчке кнопкой мыши (свойство modifiers), и значения координат курсора мыши в момент возникновения события (свойства screenX И screenY). Объекты event совместно с обработчиками событий позволяют проводить достаточно тонкую обработку события. Вызов процедуры обработки события Вызов процедуры обработки события можно осуществить двумя способами:
Каждый объект JavaScript, создаваемый для элементов HTML-документа, имеет свойства, ассоциированные с возможными событиями, которые могут быть сгенерированы для этого элемента. Присвоив этому свойству в качестве значения ссылку на процедуру обработки события, мы, тем самым, определим процедуру, которая будет вызываться при возникновении соответствующего события. Например, следующий код определяет процедуру showEventType как процедуру обработки события MouseDown кнопки формы: <FORM NAME="form1"> <INPUT TYPE="button" NAME="button1" VALUE="Узнай событие"> <SCRIPT>
</SCRIPT> </FORM> Сама процедура задается следующим кодом: function showEventType(e) {
} Обратим внимание на то, что, присваивая ссылку на процедуру, мы не задаем в скобках никаких параметров. Это связано с тем, что любая процедура в JavaScript представляется как объект. Поэтому указание имени процедуры (объекта) однозначно определяет ссылку на нее. В объявлении функции showEventType присутствует параметр е, свойство type которого выводится в диалоговом окне. При явном вызове процедуры обработки события объект event передается ей по умолчанию, поэтому в данном случае печатается значение свойства type объекта event, т. е. тип события — MouseDown. Второй, неявный вызов процедуры обработки события требует задания обращения к ней в параметре onMouseDown тега <INPUT>. При этом необходимо явно указывать параметр event, как показано в следующем фрагменте кода: <FORM NAME="form1"> <INPUT TYPE="button" NAME="button1" VALUE="Узнай событие" onMouseDown = "showEventType(event)" > </FORM> Примеры этого раздела демонстрируют технику рекурсивного обращения к функциям JavaScript, создание простого меню, а также работу с фреймами. Как отмечалось выше, нельзя изменить содержимое HTML-страницы после ее загрузки в окно браузера. Однако можно динамически с помощью функций JavaScript менять содержимое полей форм, что и используется при отображении текущего времени на странице. Прежде всего создадим HTML-страницу с текстовым полем, в которое будем выводить текущее время: <HEAD> </HEAD> <BODY bgcolor="#FFCC00" onLoad="JSClock()"> <FORM NAME="clockForm">
</FORM> </BODY> При загрузке документа вызывается функция JSclock (), которая определяет и отображает в поле digits формы clockForm текущее время. Определение самой функции разместим в разделе <HEAD> документа: <SCRIPT LANGUAGE="JavaScript"> //Скрыть сценарий от браузеров, не поддерживающих JavaScript function JSClock() {
} //--> </SCRIPT> При вызове функции переменная time содержит ссылку на объект Date, в котором хранится текущее время. Методы getHours(), getMinutes() и getseconds () объекта Date определяют часы, минуты и секунды, задаваемые системными часами. В переменной temp формируется строка "часы:минуты: секунды" для отображения в поле digits формы clockForm. Наиболее интересный оператор этой процедуры — оператор вызова функции setTimeout (). Эта функция выполняет указанные в первом параметре действия по истечении интервала времени (в миллисекундах), задаваемого вторым параметром. В нашем случае через одну секунду снова вызовется функция JSclock(), отобразит в поле формы текущее время, и процесс повторится снова. На HTML-страницах часто можно встретить меню на фоне привлекательной картинки. При выборе команды такого меню изменяется цветовая гамма ее фона. Подобное меню легко создается с помощью любого языка сценария, в том числе JavaScript. Прежде всего необходимо выбрать рисунок для фона меню и разрезать его на составные части, представляющие обрамление и команды меню, как показано на рис. 9.9, и сохранить их в отдельных графических файлах. Добавить названия команд меню в соответствующие графические файлы. Теперь остается только создать новые картинки, которые будут отображаться вместо исходных картинок при расположении курсора мыши над соответствующей командой. Эти картинки должны отличаться только цветом фона. Заготовки графических файлов для одной из команд меню примера показаны на рис. 9.10. Примечание Фон графического файла для команды соответствует фону исходной картинки для меню (желтая цветовая гамма); фон графического файла для выбранной команды реализован в синих тонах. Рис. 9.9. Разбиение картинки фона на составные части Рис. 9.10. Графические файлы команды и выбранной команды меню Примечание Графические картинки подобного типа достаточно просто можно сделать с помощью, например, программы Adobe Photoshop. В HTML-документе меню создается в виде таблицы, в ячейках которой располагаются графические файлы, причем файлы с командами меню располагаются в тэге <А>, содержащем ссылки на загружаемые документы: <body bgcolor="#FFCC00" leftmargin="0" text="#FFFF00" link="#FFFF00" vlink="#FFFF00" topmargin="0"> <div align="left"> <table border="0" width="152" cellspacing="0" cellpadding="0">
</table> </div> </body> Обработчики событий onMouseOver и onMouseOut вызывают процедуры, которые загружают либо графический образ невыбранной команды, либо графический образ выбранной команды. Эти и другие необходимые процедуры располагаются в разделе <HEAD> документа и представлены ниже: <title>MENU</title> <script LANGUAGE="JavaScript"> <!-- var MAX = 1; var img = new MakeArray(MAX); function MakeArray(n){
} function Images(org, swap) {
} function Add(name, id){
} function enter(id) {
} function out(id) {
} Add("m0","i0"); Add("m1","11") ; // --> </script> Сначала создается массив img (с помощью конструктора MakeArray о), к элементам которого можно ссылаться по индексу с именем объекта, который в нем хранится. В нашем случае в этом массиве будут храниться графические образы невыбранной и выбранной команды меню. Конструктор images о как раз и предназначен для создания объекта, хранящего подобные графические объекты. Функция Add о добавляет в массив img объекты, содержащие по два графических файла для каждой команды меню. Назначение функций enter о и outo — отобразить соответствующий графический файл при расположении курсора мыши над командой и при выходе курсора из области команды. Результаты работы меню можно видеть на рис. 9.11. Рис. 9.11. Меню, созданное в примере Примечание При просмотре созданного меню в браузере рисунок фона обычного меню реализован в желто-коричневых тонах, рисунок фона выбранной команды — в синих тонах, названия команд реализованы в белом цвете. В этом примере мы объединим два предыдущих и создадим полноценную HTML-страницу, в одном из фреймов которой будет отображаться текущее время, в другом располагаться меню, а в третий — загружаться соответствующие документы при выборе команд меню. Текст основной страницы представлен ниже и не требует пояснений: <HEAD> </HEAD> <FRAMESET COLS="152,*" border="0">
</FRAMESET> Каждый фрейм имеет имя, заданное в параметре NAME, по которому можно ссылаться на него в тексте JavaScript. Файл часы.html является файлом первого примера данного раздела, файл menu.html содержит код документа, реализующего меню с небольшим дополнением: в раздел <HEAD> необходимо внести дополнение для указания интерпретатору, что все HTML-страницы, на которые имеются ссылки, должны загружаться во фрейм с именем contentFrame. Для этой цели необходимо добавить следующий тэг: <BASE TARGET="contentFrame"> Естественно, необходимо создать все HTML-документы, на которые имеется ссылка в меню страницы. Результат отображения страницы показан на рис. 9.12. Рис. 9.12. Отображение в браузере страницы примера Язык создания сценариев VBScript разработан фирмой Microsoft и является подмножеством достаточно распространенного в среде программистов языка Visual Basic разработки прикладных Windows-приложений. Как и его родитель, язык VBScript достаточно прост и легок в изучении. Преимуществом его применения для создания сценариев является возможность использования, с небольшими корректировками, ранее написанных процедур на языках Visual Basic и Visual Basic for Application. Функциональные возможности сценариев, написанных на VBScript, ничем не отличаются от возможностей сценариев JavaScript: динамическое создание документа или его частей, перехват и обработка событий и т. д. VBScript используется для написания сценариев клиента (в этом случае браузер должен иметь встроенный интерпретатор этого языка), а также для написания сценариев на сервере (в этом случае сервер должен поддерживать язык VBScript). Для создания сценариев клиента используется набор объектов, аналогичный набору объектов JavaScript (см. выше раздел "Язык создания сценариев JavaScript"). Объекты клиента и сервера отличаются друг от друга, но существует общая часть (ядро) объектов, используемых при разработке как сценариев клиента, так и сценариев сервера. В этом разделе вводятся основные понятия языка VBScript, необходимые для написания кода сценариев. В VBScript определен только один тип данных — variant. Это универсальный тип, в котором можно хранить информацию, представленную другими типами данных, применяемыми в программировании, начиная от простейшего целого и заканчивая объектами. В своем простейшем использовании тип variant содержит либо числовые данные, либо символьные строки — типы данных, наиболее часто встречаемые при написании сценария. Реально содержащиеся в вариантном типе данные могут быть одного из типов, называемых подтипами типа variant, представленных в табл. 9.10. Собственно говоря, эти подтипы охватывают все возможные типы данных, которые используются в языках Visual Basic и Visual Basic for Application. Таблица 9.10. Подтипы данных, хранящихся в типе variant
Первые три подтипа, собственно говоря, не являются подтипами, а представляют значения, которые может принимать вариантный тип. Значение Empty имеет переменная, которая была объявлена в операторе Dim (см. ниже), но ей еще не присваивали никакого значения. Это значение считается равным 0 в математических операциях и равным пустой строке ("") в операциях со строковыми значениями. Значение Null означает, что переменная не содержит данных. Его не следует путать со значением Empty. Вариантная переменная может получить значение Null в результате выполнения некоторых операций над ней. Это значение можно присвоить переменной, тогда как значение Empty — нельзя. Значение Error — это специальное значение, которое используется для указания возникновения ошибки в процедуре. Каждый подтип данных задается с помощью литералов (символьных констант). Числовые литералы представляют собой целые числа, действительные числа с плавающей или фиксированной точкой. Примеры числовых литералов приведены ниже:
Строковые литералы задаются в виде последовательности символов, заключенных в двойные кавычки ("): "Это строковый литерал". Литералы даты и времени заключаются между символами числовых знаков (#). VBScript поддерживает большое число форматов даты и времени. Следующие примеры показывают правильные литералы даты и времени, соответствующие дате 10 июня 1999 года: #10-6-99 22:20# #10/6/99# #10/6/99 10:20pm# Внутренне литералы даты и времени представляются в виде действительных чисел удвоенной точности. Целая часть представляет количество дней, прошедших от даты 30 декабря 1899 года, а дробная часть — время суток. Булевы литералы True и False являются константами целого типа, принимающими соответственно значения 1 и о. Любое числовое значение, не равное нулю, преобразуется функцией CBool в True, а нулевое значение (целое или действительное) — в False. Вариантный тип данных при использовании в выражениях в качестве операндов разнообразных операторов языка обрабатывается в зависимости от подтипа содержащихся в нем данных. Например, при использовании переменных этого типа данных в операторе сложения (+) результат зависит от того, какие подтипы данных в них содержатся. Если хотя бы один из операндов содержит число, то результатом будет сумма значений двух переменных (содержимое второго операнда преобразуется к числовому подтипу), если оба операнда содержат строковые данные, то результатом будет конкатенация строк. Вариантный тип данных предоставляет программисту более эффективный способ обработки и хранения данных, не заботясь о типе хранимых данных. Если, например, при вычислениях первоначально в переменной вариантного типа хранилось значение типа Byte (число в диапазоне от 0 до 255), и в результате выполнения некоторых действий это значение стало отрицательным, то просто изменится представление этого числа в переменной (оно станет типа integer) и не возникнет никакой ошибки. Правда, за это удобство приходится платить используемой памятью: для вариантного типа данных вне зависимости от хранимого подтипа нужно 16 байт памяти. Иногда в некоторых вычислениях необходимо явно преобразовать содержащийся в переменной подтип в другой. Для этого в VBScript имеется ряд функций преобразования в соответствующие типы. В табл. 9.10 последний столбец содержит имена функций преобразования в соответствующий подтип. Эти функции в качестве параметра принимают литералы, переменные и выражения. Переменные, массивы и константы Переменные используются для хранения данных приложения. Прежде чем переменную можно будет использовать, ее необходимо объявить. Это можно осуществить явным способом с помощью оператора Dim, или неявным — просто использовать имя переменной в операторе присваивания. Синтаксис оператора явного объявления переменной следующий: Dim имя_переменной Параметр имя_переменной — имя объявляемой переменной. Оно должно начинаться с буквы, не содержать пробелов, точку (.), восклицательный знак (О, а также символов (@), (&), ($), (#) и не превышать длину в 255 символов. Язык VBScript не чувствителен к регистру. Это означает, что в нем не различаются строчные и прописные буквы. Поэтому, например, и т, и м будут ссылаться на одну и ту же переменную, если используются в качестве идентификатора переменной. В одном операторе Dim можно объявлять несколько переменных, которые в списке параметров задаются через запятую. Так как в VBScript определен только один тип данных variant, то и все, используемые в приложении переменные, также имеют тип variant. Примечание Вместо оператора Dim можно использовать операторы Private и Public для объявления переменной. Эти операторы, наследуемые VBScript от Visual Basic и задающие там локальные и открытые переменные соответственно, в VBScript выполняют функции, аналогичные оператору Dim. Иногда возникает необходимость хранить данные в массивах, обращаясь к ним с помощью индекса. VBScript поддерживает одномерные и многомерные массивы двух типов:
Любой тип массива определяется оператором Dim. Отличие от объявления переменной заключается в том, что после имени массива в круглых скобках указывается его размерность. Синтаксис задания массива следующий: Dim имя_массива([индексы]) Параметром индексы задается число размерностей массива и протяженность каждой размерности. Если этот параметр представляет одно целое число, то он задает одномерный массив, содержащий число элементов на единицу больше значения параметра. Это связано с тем, что первый элемент массива имеет индекс нуль. Например, следующий оператор Dim M(9) задает массив, состоящий из 10 элементов: первый элемент— м(0), второй — М(1) и т. д. Если параметр индексы задан в виде последовательности целых чисел, разделенных запятыми, то оператор Dim задает многомерный массив. Количество чисел в списке определяет число размерностей массива, а значение каждого индекса равно количеству элементов массива, соответствующих этой размерности, минус единица. Следующий оператор задает двумерный массив, или таблицу из 10 строк и 4 столбцов: Dim В (9,3) Для получения значения элемента массива следует указать имя массива и индексы элемента. Например, чтобы получить значение элемента, находящегося на пересечении второй строки и третьего столбца массива в, следует использовать запись B(1,2) Число размерностей можно задавать до 60, хотя следует учитывать, что с увеличением числа размерностей катастрофически увеличивается требуемое количество памяти для размещения массива. Задание параметра индексы определяет так называемые статические массивы, т. е. массивы, количество элементов и размерности которого известны и не могут быть изменены в процессе выполнения приложения. Если при задании массива отсутствует параметр индексы, то такая конструкция определяет динамический массив, размерность и протяженность каждой размерности которого могут меняться в процессе выполнения программы. Для задания числа размерностей и их протяженности применяется оператор ReDim, синтаксис которого аналогичен синтаксису оператора Dim при задании статических массивов: Dim Array() ... ReDim Array(3) ... В этом фрагменте оператор Dim задает динамический массив Array, а в операторе ReDim назначается его размерность. В программе можно неограниченное число раз изменять размерности динамических массивов. Следует только учитывать, что при новом переопределении размерности массива, его предыдущие элементы могут быть потеряны. Во избежание потери старых значений элементов динамического массива при новом его распределении, следует использовать в операторе ReDim ключевое слово Preserve, как показано в следующем примере: Dim Array() ... ReDim Array(3) ... ReDim Preserve Array(Ubound(Array)+1) ... В этом фрагменте используется функция ubound для определения верхней границы изменения индекса массива Array, затем его протяженность увеличивается на единицу с сохранением предыдущих значений элементов. Примечание Для многомерных массивов можно изменять протяженность только последней размерности массива. Любая попытка изменения протяженности не последней размерности приведет к ошибке интерпретатора. Иногда в программе необходимо задавать переменные, значения которых нельзя изменять. Такие переменные называются именованными константами. В VBScript для задания констант существует оператор const, имеющий следующий синтаксис: Const имя_константы = значение Параметр значение представляет собой любой допустимый литерал. Например, следующий фрагмент кода определяет несколько констант разных подтипов:
Совет Чтобы отличать в программе константы от переменных, следует выбрать схему именования констант и придерживаться ее на протяжении разработки всех сценариев. Например, можно использовать для всех констант префикс con. При вычислении выражений необходимо производить разнообразные действия с переменными и литералами. Для этих целей в VBScript предусмотрен ряд встроенных операторов, выполняющих арифметические операции, операции сравнения, конкатенацию (соединение) строк и логические операции над данными, хранящимися в переменных, или представленными литералами. В VBScript каждый оператор размещается на отдельной строке и не завершается никаким разделителем. Однако, если возникает необходимость задания нескольких операторов в одной строке, то они разделяются двоеточием (:). Если оператор достаточно длинный, или из соображений удобства чтения исходного текста необходимо расположить его в нескольких строках, то следует использовать символы продолжения — пробел со знаком подчеркивания (_). Комментарии в языке VBScript вводятся в текст программы одинарной кавычкой ('). Любой текст, расположенный в строке за одинарной кавычкой, трактуется интерпретатором как комментарий, и, естественно, не обрабатывается им. Большую группу представляют арифметические операторы, выполняющие основные арифметические действия над числовыми данными: возведение в степень (л), умножение (*), деление (/), целочисленное деление (\), сложение (+) и вычитание (-). Они подчиняются принятым в математике правилам старшинства операций: сначала выполняется возведение в степень, затем умножение или деление, далее сложение или вычитание. Скобки изменяют последовательность вычисления операций. Примечание Так как в VBScript существует только один тип данных Variant, то интерпретатор языка преобразует хранящиеся в вариантных переменных не числовые подтипы данных в числовые, и производит указанные в выражении арифметические операции. Если подтип данных не может быть конвертирован в правильное число, то генерируется ошибка. Предупреждение Оператор сложения (+), примененный к операндам, содержащим строковые данные, выполняет операцию конкатенации строк, а не сложение преобразованного в числовые данные содержимого обоих операндов. Для выполнения операции конкатенации в VBScript существует специальный оператор (&), которым и следует пользоваться для соединения строковых данных. Для сравнения данных используются операторы сравнения: равенство (=), неравенство (<>), меньше (<), больше (>), меньше или равно (<=), больше или равно (>=). Объекты сравниваются с помощью специального оператора is. Примечание В VBScript нет специального знака для операции присваивания. Один и тот же знак равенства используется как для операции присваивания значения переменной (см. выше), так и для операции сравнения на равенство. Смысл операции, представляемой этим символом, зависит от контекста, в котором она применена. Существует ряд операторов, выполняющих действия над логическими (булевыми) данными: отрицание (Not), конъюнкция (And), дизъюнкция (or), исключающее ИЛИ (хог), эквивалентность (Eqv) и импликация (imp). Эти операции используются в операторах условия для вычисления выражений, истинность (или ложность) которых позволяет изменить поток выполнения операторов языка. Оператор (&) производит конкатенацию (соединение) двух строк. При его выполнении данные, содержащиеся в операндах, преобразуются при необходимости к строковому подтипу, и осуществляется сцепление двух строк. Операторы сценария выполняются последовательно в том порядке, как они записаны. Изменить порядок выполнения операторов в VBScript можно операторами условия и цикла. Операторы принятия решения (условные операторы) выполняют определенные блоки операторов в зависимости от результатов проверки некоторого выражения или выражений. VBScript поддерживает следующие конструкции операторов принятия решения:
Конструкция if...Then применяется, когда необходимо выполнить группу операторов или один оператор в зависимости от значения выражения, задаваемого в качестве параметра условия конструкции. Ее первая форма If условие Then оператор позволяет вычислить указанный оператор, если истинно заданное условие. Вторая форма этой конструкции позволяет вычислить группу операторов, заданных в нескольких строках кода, и имеет следующий синтаксис: If условие Then
End If Примечание Во всех условных операторах проверяемое на истинность условие не обязательно должно быть сравнением. Оно может быть любым вычисляемым выражением, которое интерпретируется как Ложь, в случае нулевого значения, и как Истина — в противном случае. Наиболее общий синтаксис конструкции if...Then...Else следующий: If условие1 Then
[Elself условие2 Then
[Else
End If Сначала проверяется условие1. Если оно ложно, то проверяется условие2. Если и оно ложно, то проверяется следующее условие из группы Elself до тех пор, пока не будет найдено истинное условие, операторы которого и выполняются. После чего управление передается оператору, непосредственно следующему за оператором End if. Если не найдено ни одно истинное условие, то выполняется группа операторов из блока Else, если он присутствует в конструкции. В противном случае управление передается оператору, следующему за оператором End if. Примечание Блоков Elself в конструкции if. . .Then. . .Else может быть сколько угодно, тогда как блок Else всегда один, если он задан. Если в предыдущей конструкции принятия решения проверяется равенство одного выражения разным условиям, она становится не достаточно эффективной как с точки зрения ее выполнения, так и с точки зрения легкости восприятия текста. В этом случае следует использовать конструкцию select Case: Select Case тестируемое_выражение [Case список_значений1
End Select Вычисляется единственное выражение тестируемое_выражение и последовательно сравнивается со значениями из списков значений блоков case. Если значение выражения совпадает со значением, заданным в списке какого-либо блока case, то выполняется группа операторов данного блока, и после этого управление передается оператору, непосредственно следующему за оператором End select. Если не найдено ни одного соответствия значения тестируемого выражения со значениями из списков значений, то выполняется группа операторов блока case Else (в случае его наличия). Список значений блока Case может состоять из одного или нескольких значений. В случае нескольких значений они разделяются запятыми. Примечание Если вычисленное значение тестируемого выражения совпадает со значениями из нескольких блоков Case, то выполняется группа операторов, заданная в первом из блоков Case, в котором найдено соответствие. Для повторного выполнения несколько раз группы операторов VBScript, как и любой другой язык программирования, предоставляет разнообразные типы операторов цикла:
Конструкция Do...Loop применяется для выполнения группы операторов, пока некоторое выражение ложно или истинно. Она имеет несколько разновидностей, отличающихся моментом проверки условия завершения цикла (до начала выполнения группы операторов или после) и тем, истинно или ложно это условие. Цикл Do While выполняется до тех пор, пока истинно условие окончания цикла: Do While условие_окончания
Loop Перед выполнением операторов цикла проверяется, истинно ли выражение условие_окончания. Если оно истинно, то выполняется группа-операторов (в ней изменяются значения переменных, входящих в выражение условие_окончания). После этого снова проверяется условие окончания цикла и, в случае его истинности, выполняется группа операторов тела цикла. Процедура повторяется до тех пор, пока выражение условие_окончания не станет ложным. Примечание Если выражение, определяющее условие завершения цикла и первоначально имеющее значение True, не изменяется в теле цикла, то цикл будет повторяться бесконечное число раз. Для выхода из бесконечного цикла следует использовать оператор Exit Do (см. ниже). Цикл Do While не будет выполнен ни разу, если при первой проверке условие_окончания ложно. Другая разновидность цикла Do while сначала выполняет группу операторов, а потом проверяет условие окончания цикла: Do группа-операторов Loop While условие_ркончания Этот цикл обязательно выполнит один раз группу операторов, определенных в теле цикла. Цикл Do until аналогичен первой разновидности цикла Do While, за исключением того, что он выполняется, пока значение выражения условие_окончания ложно: Do Until условие_окончания
Loop Этот цикл также может не выполниться ни одного раза, если при первой же проверке условия завершения цикла, оно оказывается истинным. Во второй разновидности цикла Do until условие окончания завершения цикла проверяется после выполнения группы операторов, и, таким образом, он обязательно выполнится хотя бы один раз: Do
Loop Until условие окончания Примечание Выражение условие_окончания не обязательно должно быть выражением сравнения, принимающим значение истина или Ложь. Значение любого вычисляемого выражения трактуется как Ложь, если оно равно нулю, и Истина — в противном случае. В циклах Do...Loop заранее не известно количество итераций повторения группы операторов, но иногда требуется выполнить точно заданное число повторений цикла. Такую возможность предоставляет цикл For...Next. В этом цикле задается переменная, называемая счетчиком цикла, которая увеличивается (или уменьшается) на заданную величину после выполнения группы операторов. Цикл завершает свои итерации, когда значение счетчика превысит (или станет меньше) заданной величины. Синтаксис такой конструкции цикла следующий: For счетчик = нач значение То кон_значение [Step приращение]
Next В начале выполнения этого цикла переменной счетчик присваивается значение, заданное параметром нач_значение. Выполняются операторы цикла, и значение переменной цикла увеличивается или уменьшается (в зависимости от знака) на величину приращение. Осуществляется проверка, не превысило ли (или не стало меньше) новое значение счетчика значение параметра кон_значение. Если нет, то итерации повторяются, если да, то цикл завершает свое выполнение. Параметр приращение цикла For...Next является необязательным. Если он не задан, то по умолчанию переменная цикла увеличивается на 1. Примечание Следует аккуратно задавать все три параметра цикла For...Next. Они должны быть согласованы: если приращение положительно, то начальное значение должно быть меньше или равно конечному значению; если приращение отрицательно, то конечное значение должно быть меньше или равно начальному значению. Если это не так, то цикл For...Next не выполняется ни одного раза. Конструкция For Each...Next позволяет организовать цикл по элементам массива или по объектам некоторого набора (семейства) объектов (см. ниже в разделе), не зная заранее число элементов в массиве или число объектов в наборе. Синтаксис этой конструкции следующий: For Each элемент In группа
Next Параметр группа задает имя массива или имя набора объектов. Переменная элемент на каждом шаге цикла будет содержать ссылку на элемент массива или объект набора. Цикл завершает свое выполнение, как только завершится последовательный перебор всех элементов массива или объектов набора. Следующий фрагмент кода подсчитывает количество элементов в массиве: Dim Ar(10)
Number = 0 For Each j In Ar
Next Document.Write "Число элементов массива равно " & Number Результатом работы данного сценария будет строка в документе: Чиcло элементов массива равно 11 В следующем примере используется набор forms для организации цикла по числу форм в документе. Внутренний цикл по элементам набора elements формы печатает в документ значения свойства value всех элементов формы. Пример 9.4. Отображение всех элементов форм документа <BODY> <FORM name="frm1"> <INPUT TYPE="checkbox" NAME="check1" value="Флажок"> Флажок </FORM> <FORM name="frm2"> <INPUT TYPE="checkbox" NAME="check2" value="Флажок1"> Флажок1 </FORM> <P> <SCRIPT language="VBScript"> For Each i In document.forms
Next </SCRIPT> </BODY> На каждом шаге внешнего цикла переменная i содержит ссылку на форму, созданную тэгом <FORM>. Во внутреннем цикле осуществляется перебор элементов формы. Ссылка на набор elements формы указывается в качестве параметра i.elements цикла For Each. Переменная j внутреннего цикла последовательно ссылается на элементы формы, поэтому конструкция j.value дает значение параметра value элемента формы. Результат отображения страницы в окне браузера показан на рис. 9.13. Обычно любой оператор цикла выполняется столько раз, сколько определено его параметрами, но иногда необходимо прервать выполнение цикла, например, в результате выполнения какого-либо условия. Для этих целей в VBScript существует несколько операторов Exit безусловного выхода из конструкций цикла:
Их можно использовать в любом месте в теле цикла, но обычно они используются совместно с операторами условиями. Рис. 9.13. Отображение информации по элементам форм документа Часто приходится выполнять одну и ту же последовательность операторов, реализующих какое-нибудь действие в программе, возможно с разными переменными или разными значениями. Например, отображение подсказки пользователю в диалоговом окне можно рассматривать как одну и ту же последовательность действий (отобразить на экране диалоговое окно) с разными значениями (содержание подсказки). Такая последовательность действий обычно оформляется в виде процедуры (с параметрами или без параметров), инициализация выполнения которой осуществляется простым указанием имени этой процедуры и передаче ей необходимых параметров. VBScript предусматривает создание двух типов процедур:
Процедура sub выполняет последовательность действий, но не возвращает никакого значения, ассоциированного с ее именем. Она имеет следующий синтаксис: Sub имя_процедуры ([список-параметров])
End Sub Через необязательный список параметров можно передать в процедуру внешние данные или, наоборот, получить некоторые вычисленные ею значения. Вызов процедуры sub осуществляется оператором call, после которого указывается имя процедуры и в круглых скобках параметры. Процедуру можно вызвать и простым указанием ее имени, но в этом случае передаваемые ей параметры задаются без скобок. Следующие два способа вызова процедуры эквивалентны: Call MyProc(firstarg, secondarg) MyProc firstarg, secondarg Функция также выполняет определенную последовательность операторов и ей можно передать внешние данные через параметры процедуры, но, в отличие от процедуры Sub, она возвращает значение, присваиваемое ее имени, и может быть использована в выражениях VBScript. Она имеет следующий синтаксис: Function имя__процедуры ( [список-параметров] )
End Function В операторах процедуры обязательно должен присутствовать оператор присвоения имени процедуры некоторого значения. Следующая функция пересчитывает переданное ей в качестве параметра значение в дюймы или сантиметры; второй параметр этой процедуры определяет, в каких единицах измерения задано исходное значение параметра. Function InchMeter( value, index)
End Function
leng = InchMeter(1.5,0)
В этом фрагменте кода функция InchMeter о вызывается в правой части оператора присваивания. Вызов функции в выражениях осуществляется указанием ее имени и списком параметров в круглых скобках. Функции Function можно вызывать, используя синтаксис вызова процедур sub, но в этом случае VBScript игнорирует возвращаемое ею значение. Следующие два оператора вызывают одну и ту же процедуру InchMeter (), но возвращаемые значения не доступны для дальнейшего использования: Call InchMeter(1,0) InchMeter 1,1 VBScript предоставляет два способа передачи параметров в процедуры:
Способ передачи параметра по ссылке, применяемый по умолчанию, передает фактический адрес переменной, используемой в качестве параметра. Это позволяет изменить содержимое соответствующего адреса памяти, а тем самым, и значение переменной. Передача параметров по значению предполагает передачу в процедуру копии переменной, а не адреса самой переменной. Поэтому любые изменения параметра внутри процедуры воздействуют на копию, а не на саму переменную, и, следовательно, значение переменной, переданной в качестве параметра, изменяться не будет. Для указания интерпретатору, что параметр передается в процедуру по значению, используется ключевое слово ByVal, задаваемое перед параметром в описании процедуры. При вызове следующей процедуры значение переменной 1, переданной в качестве параметра, не изменяется, хотя процедура изменяет значение параметра: Sub proc(ByVal m)
End Sub 1 = 4 proc 1 document.write 1 // Напечатает 4, а не 3 Объектная модель и взаимодействие с элементами документа Как уже говорилось (в разделе "Объектные модели языков сценариев" этой главы), при интерпретации HTML-страницы браузер создает объекты, соответствующие элементам отображаемой страницы. Эти объекты доступны для приложения VBScript и любой сценарий может обратиться или установить значения свойств объектов, выполнить их методы. Язык VBScript, как и другой распространенный язык сценариев, может манипулировать стандартными объектами, встроенными в ядро VBScript, и объектами, предоставляемыми браузером. При описании объектов JavaScript мы рассматривали объекты браузера Netscape Navigator фирмы Netscape. Теперь остановимся на объектах браузера Microsoft Internet Explorer фирмы Microsoft. Функции и объекты ядра VBScript Ядро VBScript предоставляет программисту большой набор встроенных функций для работы с датами, строковыми подтипами данных, вычисления математических функций и отображения информационных диалоговых окон и окон ввода информации пользователем. Для вычисления стандартных математических функций используются процедуры-функции, представленные в табл. 9.11. В качестве параметров этих процедур могут выступать числовые литералы, переменные, содержащие числовые значения, или числовые выражения. Таблица 9.11. Математические функции VBScript
Получить текущее время, текущую дату, а также одновременно и дату, и время, установленные на компьютере пользователя, можно с помощью функций Time, Date и Now. Эти три процедуры-функции не требуют параметров, поэтому при их использовании в выражениях следует задавать открывающую и закрывающую скобки, указывающие на отсутствие параметров, как показано в следующем фрагменте кода:
Что хранится в этих переменных, зависит от системных установок времени и даты, определенных на компьютере пользователя. Например, на компьютере с установленным форматом времени Ч:мм:сс и даты дд.ММ.гг печать в документе значений переменных предыдущего фрагмента кода будет выглядеть следующим образом:
Если какая-либо переменная содержит значение подтипа Date, или ее содержимое может быть преобразовано в этот подтип, то функции Day (переменная), Month (переменная) И Year (переменная) возвращают соответственно число, месяц и год даты, не зависимо от формата хранения дат на компьютере пользователя. Функции Hour (переменная), Minute (переменная) и second (переменная) возвращают целые числа, соответствующие часам, минутам и секундам времени, хранящимся в переменной, являющейся параметром этих функций. Для работы со строками предназначен целый ряд функций, которые полезны при проверке правильности ввода информации в поля формы. Функция Lent строка) возвращает число символов в строке с учетом лидирующих и замыкающих пробелов. Если пользователь ввел в поле формы строку " строка " с двумя пробелами в начале и одним пробелом в конце, то эта функция возвратит значение 9. Для удаления незначащих пробелов в Yачале или конце строки можно обратиться к функциям Ltrim, Rtrim и Trim, которые, соответственно, удаляют лидирующие, замыкающие или оба типа пробелов из строки, переданной этим функциям в качестве параметров. Функции Lease и ucase переводят все содержимое строки соответственно в нижний или верхний регистр. Для сравнения Двух строк используется функция StrComp( строка 1, строка2, метод_сравнения). Она возвращает значение 0 (если строки совпадают в соответствии с методом сравнения, заданным третьим параметром функции), значение -1 (если строка1 меньше строки2) и значение 1 в любом не совпадающем с двумя предыдущими случае. Параметр метод_сравнения может принимать два значения: 0 — строки сравниваются с учетом регистра, 1 — строки сравниваются без учета регистра. Функция InStr(нач_позиция, строка1, строка2, метод_сравнения) позволяет определить, содержится ли строка2 в строке1. Параметр нач_позиция задает позицию в строке1, с которой начинается поиск подстроки, заданной параметром строка2. Это достаточно полезно, если известно, что строка1 содержит несколько вхождений строки2. Параметр метод_сравнения определяет, учитывается ли регистр при поиске соответствующей подстроки, и совпадает с аналогичным параметром функции strComp. Функция поиска подстроки intstr возвращает номер позиции в строке1 первого вхождения строки2, если такое найдено, и значение 0 — в противном случае. Две стандартные функции inputBox и MsgBox позволяют отобразить диалоговое окно с полем ввода и диалоговое окно с сообщением пользователю. Функция inputBox отображает диалоговое окно с полем ввода и двумя кнопками: ОК и Cancel (Отмена). Она имеет следующий синтаксис: InputBox(подсказка, заголовок, умалч_знач, х, у) Строковые параметры подсказка и заголовок задают соответственно подсказку для пользователя и заголовок диалогового окна. Параметр умалч_знач определяет значение, выводимое в поле ввода при отображении окна. Необязательные два последних параметра задают в твипах (1 твип = 1/1440 дюйма = = 1/20 пойнта) координаты левого верхнего угла диалогового окна относительно левого верхнего угла окна браузера. Эта функция возвращает значение строки, введенной пользователем, или заданное умалчиваемое значение при нажатии кнопки ОК. При нажатии кнопки Cancel возвращаемое функцией значение равно Empty. На рис. 9.14 показано диалоговое окно, отображаемое оператором: IC = InputBox("Введите Ваш регистрационный номер.", "Регистрация", "") Рис. 9.14. Диалоговое окно, отображаемое функцией InputBox С помощью функции MsgBox можно не только просто информировать пользователя о возникших проблемах, но и предоставить ему возможность разрешить ее некоторыми стандартными способами. Например, если не удается из сценария связаться с каким-нибудь сервером, пользователь может отказаться от этого действия, повторить его или отменить. Подобное взаимодействие осуществляется отображением диалоговых окон разных типов, задаваемых значением соответствующего параметра функции MsgBox. Синтаксис вызова этой функции следующий: IC=MsgBox(строка_сообщения, тип_окна, заголовок_окна) Параметр строка_сообщения задает строку сообщения, отображаемую в диалоговом окне, параметр заголовок_окна определяет надпись в заголовке окна, а параметр тип_окна задает тип отображаемого окна. Он является целым числом и его значение определяется как сумма трех целочисленных подпараметров, задающих элементы диалогового окна. Эти подпараметры определяют количество и типы кнопок, тип значка и умалчиваемую кнопку, отображаемые в диалоговом окне. Значения этих параметров представлены в табл. 9.12. Таблица 9.12. Значения подпараметров вида диалогового окна
Примечание Надписи на кнопках отображаются в зависимости от используемой операционной системы. В таблице в скобках после английского названия кнопок указано их название при работе в русской версии Windows 95. Если необходимо отобразить диалоговое окно с тремя кнопками Yes, No и Cancel (значение подпараметра равно 3), со значком Восклицание (значение подпараметра равно 48) и третьей кнопкой (Cancel) по умолчанию (значение подпараметра равно 512), то необходимо при вызове функции MsgBox в качестве значения параметра тип_окна указать 563 (3+48+512), как показано в следующем примере: MsgBox "Вы действительно хотите завершить процесс?", 563,"Сообщение" Результат выполнения этого оператора можно увидеть на рис. 9.15. Рис. 9.15. Диалоговое окно, отображаемое функцией MsgBox Функция MsgBox возвращает целочисленное значение, по которому можно определить, какая кнопка была нажата, и предпринять необходимые действия. Коды возврата функции показаны в табл. 9.13. Таблица 9.13. Коды возврата функции MsgBox
VBScript предоставляет ряд объектов, не связанных с объектной моделью HTML-страницы и предназначенных для сценариев, выполняющихся на сервере. Это объекты для работы с файловой системой: дисками, папками и файлами. Свойства и методы этих объектов позволяют получать информацию о файлах, расположенных на компьютере, на котором выполняется сценарий. Потенциально их можно включать в сценарии HTML-страниц, но вероятность их выполнения мала, так как при попытке использования подобных объектов браузер отображает предупреждающее сообщение (рис. 9.16), и пользователь может отказаться от дальнейшего выполнения сценария. Рис. 9.16. Сообщение браузера при использовании в сценарии объектов доступа к файлам Здесь дадим краткое описание использования подобных объектов на примере объектов FileSystemObjects (Объекты файловой системы), так как с их помощью можно быстро решить какие-то свои домашние задачи, не обращаясь к "серьезным" системам программирования. Прежде чем использовать методы и свойства любого объекта VBScript, его необходимо создать. Это достигается использованием оператора set совместно С функцией CreateObj ect: Dim fso, MyFile Set fso = CreateObject("Scripting.FileSystemObject") Сначала описывается переменная fso, в которой будет храниться ссылка на объект файловой системы, а затем в операторе set создается сам объект, и в переменную заносится ссылка на него. Теперь можно использовать все методы и свойства созданного объекта, применяя обычную точечную нотацию объектно-ориентированных технологий. Например, в следующем фрагменте кода создается объект Textstream, метод WriteLine которого записывает строку текста в файл: Set MyFile = fso.CreateTextFile("a:\testfile.txt", True) MyFile.WriteLine("Проверка записи в файл из VBScript.") MyFile.Close Если выполнить приведенные два фрагмента кода в одном сценарии, то на дискете будет создан новый файл, содержащий одну текстовую строку. Примечание Создание нового объекта всегда осуществляется с помощью оператора Set. т После знака равенства указывается конструктор объекта— функция, возвращающим значением которой является объект. Конструктор может иметь параметры. Совет Описание всех объектов VBScript можно найти на сервере фирмы Microsoft по адресу http://msdn.microsoft.com. С него же можно установить на свой компьютер документацию по языку сценариев VBScript. Браузер MS Internet Explorer разработан с использованием технологии Automation. Приложение, созданное на основе этой технологии, раскрывает свои объекты другим приложениям, поддерживающим данную технологию. Эти приложения имеют доступ к методам и свойствам объектов другого приложения Automation. Иерархическая структура объектов Internet Explorer достаточна сложна, но для написания сценариев используется часть объектной модели, связанной с элементами HTML-страницы. Во главе иерархии, как и в случае с Netscape Navigator, стоит объект window, представляющий окно браузера и порождающий все остальные объекты модели. При ссылке в программе на любой объект из иерархии можно не указывать "родительский" объект window. Модель охватывает практически все элементы HTML-страницы. На рис. 9.17 показана иерархическая структура объектной модели, которая отражает подчиненность элементов страницы. Рис. 9.17. Объектная модель MS Internet Explorer Для каждого типа элементов в модели предусмотрены соответствующие наборы. Например, для объектов image, определяемых тэгами <IMG>, существует набор images. Ссылку на соответствующий объект можно определить с использованием имени объекта, задаваемого значением параметра NAME, или с помощью набора объектов, в данном случае images. В наборе объекты расположены в последовательности, в которой они задаются на HTML-странице. Примечание Наборы объектов, собственно говоря, являются свойствами порождающих их объектов. Имена наборов объектов задаются в виде множественного числа существительных (в английском языке добавляется буква "s" в конце слова), определяющих типы объектов. Формы HTML, отображаемые в объектах Form, содержат разнообразные элементы управления, которые порождают соответствующие объекты, подчиненные объекту Form. Все, что сказано об этих объектах в разделе "Язык создания сценариев JavaScript", остается в силе и при работе с этими объектами с помощью языка VBScript. Как и в сценарии JavaScript, весь код VBScript должен располагаться в тэге-контейнере <SGRIPT>. . .</SCRIPT>. Для обратной совместимости с браузерами, не поддерживающими язык сценариев VBScript, следует размещать код внутри тега <SCRIPT> в контейнере-комментарии, как показано ниже: <SCRIPT TYPE="text/vbscript" LANGUAGE="VBScript"> <!--
'--> </SCRIPT> Завершающий тег комментария предваряется знаком ('), чтобы интерпретатор браузера не сгенерировал ошибку синтаксиса. Предупреждение
Следует избегать появления в коде сценария последовательности символов (</), так как интерпретатор воспринимает ее как завершающий тег и может не обработать до конца сценарий. Если необходимо напечатать в документе последовательность указанных символов, в коде VBScript следует заменить знак / на его представление через десятичный код
Chr (47)и использовать операцию конкатенации строк. Например, если необходимо при динамическом создании документа напечатать Абзац</р>, то следует использовать метод Write объекта Document следующим образом:
Document.Write " Абзац<" & Chr(47) & "р>"
Параметр LANGUAGE задает язык сценария. Параметр TYPE, определяющий MIME-тип заключенного в тег <SCRIPT> кода, задает также язык сценария. Для VBScript значение этого параметра должно быть строкой "text/vbscript". Этот параметр включен в HTML 4.0, но может не поддерживаться некоторыми браузерами, поэтому рекомендуется задавать оба параметра одновременно. Примечание Все сказанное выше о параметрах TYPE и LANGUAGE относится и к языку JavaScript, для которого MIME-тип следует задавать в виде строки "text/javascript". Указанным выше способом код сценария непосредственно встраивается в страницу. Параметр SRC тега <SCRIPT> позволяет указать полный или относительный адрес внешнего файла, содержащего код VBScript, который будет загружен и обработан интерпретатором браузера. Internet Explorer поддерживает ещё два параметра: FOR и EVENT тега <SCRIPT>, непосредственно связанных с процедурами обработки событий, и речь о которых пойдет немного ниже. В каком месте документа лучше размешать код сценария? В любом месте документа и в неограниченном количестве. Но, как и в случае с JavaScript, определения процедур рекомендуется размещать в разделе <HEAD>, хотя это и не обязательно. Подобная практика улучшает чтение кода сценария, позволяя избегать поиска процедуры по всему документу. Более того, при интерпретации браузером документа раздел <HEAD> интерпретируется до начала обработки тела документа, следовательно, все процедуры будут размещены в памяти до того, как в документе встретится их вызов. Если читатель прочитал раздел "Язык создания сценариев JavaScript", то он помнит, что каждый объект, соответствующий какому-либо элементу HTML-документа, имеет возможность перехватывать и обрабатывать события, возникающие в результате разнообразных действий пользователя с данным объектом (установка курсора мыши над связью, щелчок на кнопке формы, нажатие клавиши клавиатуры при установленном в поле ввода курсоре и т.д.). Для этого в теги HTML, описывающие элементы документа, введены специальные параметры обработки событий: onMouseOver, onclick, onKeyUp и т. д. Значениями этих параметров является код вызова процедур, которые выполняются в ответ на произошедшее событие. Задавать выполняемый код можно несколькими способами. Самый простой — задание кода в качестве значения параметра с указанием в начале строки используемого языка: <BODY>
Пример обработки событий в VBScript<BR> <FORM> <INPUT TYPE="BUTTON" VALOE-"Нажми меня" NAME="Button1"
</FORM> </BODY> Представленный фрагмент кода задает^ в документе кнопку с надписью "нажми меня", щелчок на которой приводит к вызову диалогового окна с надписью "Сообщение в ответ на щелчок1". Префикс vbscript: сообщает интерпретатору, что необходимо использовать язык сценариев VBScript. Далее задается код VBScript, вызывающий метод Alert объекта window. Подобный метод применим, когда необходимо выполнить один-два оператора языка. Примечание Если в качестве префикса указать javascript:, то будет вызван интерпретатор языка JavaScript, а последующий код должен быть, соответственно, написан на языке JavaScript. Второй способ использует параметры FOR и EVENT в тэге <SCRIPT>. Предыдущий фрагмент может быть переписан следующим образом: <BODY>
Пример обработки событий в VBScript<BR> <FORM> <INPUT TYPE="BUTTON" VALUE="Нажми меня" NAME="button1"> <SCRIPT FOR="button1" EVENT="OnClick" LANGUAGE="VBScript"> <!--
'--> </SCRIPT> </FORM> При использовании данного способа задания процедуры обработки события в тэге <INPUT>, определяющем кнопку формы, параметр обработки события click не задается, но в тэге <SCRIPT>, определяющем код сценария, параметр EVENT определяет, в ответ на какое событие будет выполняться код, а параметр FOR — для какого объекта. Значением первого параметра является имя параметра обработки события (onclick) тега элемента, а значением второго параметра — имя элемента (Buttoni), для которого вызывается код, определенное в параметре NAME тега элемента. Примечание Указанный способ обработки события распознается только браузером Internet Explorer, и поэтому его следует избегать. Здесь он упомянут исключительно ради полноты описания. Третий способ задания процедуры обработки события унаследован VBScript от своего "родителя" Visual Basic и заключается в специальном именовании процедуры обработки события при ее объявлении. Любая процедура, имя которой составлено из имени объекта и имени события этого объекта с префиксом (on), соединенных знаком подчеркивания, рассматривается VBScript как процедура обработки указанного события для указанного объекта. Процедуру обработки события для рассмотренного выше примера можно определить следующим образом: <SCRIPT TYPE="text/vbscript" LANGUAGE="VBScript"> <!-- Sub Button1_onClick()
End Sub '--> </SCRIPT> Этот способ удобен тем, что можно в одном тэге <SCRIPT> собрать все процедуры обработки событий всех элементов документа. Для тех, кто программирует на Visual Basic или Visual Basic for Application последний способ инициирования процедуры обработки события, вероятно, окажется самым подходящим. Более того, в специальных приложениях Windows, предоставляющих среду разработки HTML-страниц на языке VBScript, этот способ является основным. В этом разделе приводится несколько примеров программирования сценариев VBScript. Тэг <IFRAME> задает плавающий фрейм на HTML-странице. Его можно использовать для отображения динамически создаваемой страницы. Такая техника полезна, например, при написании учебной страницы по языкам сценариев. В тексте можно привести код изучаемой конструкции, а при щелчке кнопкой мыши внутри плавающего фрейма она отобразится так, как ее увидит конечный пользователь. Прежде всего, необходимо создать страницу с плавающим фреймом, и организовать перехват обработки какого-либо события плавающего фрейма. Ниже представлен текст страницы, на которой при получении плавающим фреймом фокуса (обработчик событий onFocus) вызывается процедура VBScript, динамически создающая содержимое, отображаемое в этом фрейме: <BODY BGCOLOR="FFFF00">
Щелчок кнопкой мыши на плавающем фрейме приводит
к отображению в нем содержимого</Р> <IFRAME WIDTH="400" HEIGHT="100" FRAMEBORDER="1" NAME="fra1" OnFocus="FillIFrame"> </IFRAME> </BODY> При щелчке на плавающем фрейме он получает фокус, и происходит вызов процедуры FillLFrame. На рис. 9.18 показана эта страница, отображенная в окне браузера. Теперь остается только создать процедуру VBScript, создающую содержимое плавающего фрейма. Ее текст представлен ниже и должен быть размещен в разделе <HEAD> предыдущего документа: <SCRIPT LANGUAGE="VBScript"> <!-- Sub FillIFrame()
End Sub '--> </SCRIPT> Рис. 9.18. Страница с плавающим фреймом Оператор with задает объект, методы которого вызываются в теле оператора. В нашем примере — это документ, отображаемый в плавающем фрейме. Методы WriteLn записывают в документ строки, содержащие теги HTML, и тем самым динамически формируют документ, отображаемый во фрейме. Щелчок кнопкой мыши при расположении ее курсора в области фрейма приводит к возникновению события Focus, которое интерпретатор перехватывает и запускает на выполнение процедуру FillLFrame(). Результат отображения динамически созданной страницы показан на рис. 9.19. Рис. 9.19. Содержимое фрейма после получения им фокуса Это полноправная страница. При щелчке на кнопке, расположенной во фрейме, отобразится диалоговое окно подсказки — действие, определенное в процедуре обработки события click кнопки страницы. Можно организовать динамическое отображение разных страниц во фрейме, имитируя, таким образом, работу баннера. Реализация подобного процесса осуществляется вызовом разных процедур, готовящих и отображающих соответствующие страницы во фрейме с использованием функции setTimeOut. В этом примере мы создадим плавающий фрейм, в котором будет постепенно по частям отображаться строка "Издательство В НУ", затем также по частям она будет исчезать, и процесс начнется сначала. Каждая динамически появляющаяся во фрейме строка будет отображаться разным цветом, создавая эффект "неоновой" рекламы. Как и в предыдущем примере, сначала создадим HTML-страницу с плавающим фреймом, а затем напишем сценарий, реализующий необходимый нам процесс отображения. Текст HTML-страницы выглядит следующим образом: <BODY BGCOLOR="FFFF00"> <P ALIGN="center"> <IFRAME NAME="frameBHV" HEIGHT="70" WIDTH="200"></IFRAME></P> Вас приветствует "Издательство BHV", Санкт-Петербург! </BODY> В верхней части страницы отображается плавающий фрейм, ссылаться на который из сценария можно при помощи имени frameBHv. Ниже фрейма располагается текст приветствия. Теперь приступим к созданию сценария. Прежде всего определим, что отображаемая во фрейме строка полностью будет появляться в нем за пять отображений: сначала отобразится "Из", затем "Издат", далее "Издатель", потом "Издательство" и наконец "Издательство BHV". Исчезать она также будет за пять отображений, но в обратном порядке. Для каждого отображения необходимо динамически создать соответствующую страницу, что и реализуется пятью процедурами AnimFrame с соответствующим номером в конце имени процедуры. В них используются переменные Page1, Page2, PageЗ, Page4 и Page5, Содержащие определения цветов фона и текста, и переменная pageEnd, которая хранит завершающие теги страницы. Dim PageEnd Page1 = "<BODY BGCOLOR='#00CCFF' TEXT='#0000FF'><PRE>" Page2 = "<BODY BGCOLOR='#00CCFF' TEXT='#00FFFF'><PRE>" Page3 = "<BODY BGCOLOR='#00CCFF' TEXT='#00FF00'><PRE>" Page4 = "<BODY BGCOLOR='#00CCFF' TEXT='#FFFF00'><PRE>" Page5 = "<BODY BGCOLOR='#00CCFF' TEXT='#FF0000'><PRE>" PageEnd = "</PRE></BODY>" Первая вызываемая процедура — процедура без параметров AnimFrame1, которая отображает во фрейме строку "Из" синим цветом, и по прошествии 1/4 секунды вызывает процедуру AnimFrame2 с параметром True. Это действие реализуется функцией setTimeOut, которая выполняет код, заданный первым параметром, через количество миллисекунд, определяемых вторым параметром этой функции. Sub AnimFrame1
End Sub Процедура AnimFrame2 отображает во фрейме строку "Издат" голубым цветом и вызывает Процедуру AnimFrame3 или AnimFrame1, в зависимости от того, должна ли появиться вся надпись (параметр forw равен True) или вся надпись должна исчезнуть (параметр forw равен False). Sub AnimFrame2(forw)
End Sub Процедуры AnimFrame3 и AnimFrame4 осуществляют аналогичные действия, отображая соответственно строки "Издатель" и "Издательство" и вызывая другие процедуры для выполнения необходимых действий. Sub AnimFrame3(forw)
End Sub Sub AnimFrame4 (forw)
End Sub Последняя, пятая процедура AnimFrame5 отображает строку "Издательство BHV" и запускает процесс отображения в обратном порядке (процедура AnimFrame4 вызывается с параметром False). Sub AnimFrame5
End Sub Теперь, для запуска всего процесса необходимо инициализировать выполнение первой процедуры AnimFrame1 при загрузке документа в окно браузера. Это действие реализуется в процедуре обработки события Load объекта window: Sub Window_OnLoad()
End Sub Результаты отображения информации во фрейме в разные моменты времени показаны на рис. 9.20 и 9.21. Примечание На рис. 9.20 строка во фрейме отображается синим цветом, а на рис. 9.21 — красным. Предупреждение Описанный подход к циклическому вызову функций требует постоянной работы интерпретатора, поэтому следует помнить, что подобная техника программирования значительно загружает процессор компьютера клиента. Рис. 9.20. Отображение строки "Из" во фрейме страницы Рис. 9.21. Отображение строки "Издательство BHV" во фрейме страницы Основу "Всемирной паутины" WWW составляют Web-узлы — компьютеры, на которых выполняется специальная программа — Web-сервер, ожидающая запроса со стороны клиента на выдачу документа. Документы сохраняются на Web-узле, как правило, в формате HTML. Клиентом Web-сервера является программа-браузер, выполняющаяся на удаленном компьютере, которая осуществляет запрос к Web-серверу, принимает запрошенный документ и отображает его на экране. Аббревиатура CGI (Common Gateway Interface) обозначает часть Web-сервера, которая может взаимодействовать с другими программами, выполняющимися на этом же Web-узле, и в этом смысле является шлюзом (gateway — шлюз) для передачи данных, полученных от клиента, программам обработки, таким как СУБД, электронные таблицы, и др. CGI включает общую среду (набор переменных) и протоколы для взаимодействия с этими программами. Общая схема работы CGI состоит из следующих элементов.
Рис. 9.22. Пример отображения HTML-формы браузером HTML-формы предназначены для пересылки данных от удаленного пользователя к Web-серверу. С их помощью можно организовать простейший диалог между пользователем и сервером, например, регистрацию пользователя на сервере или выбор нужного документа из представленного списка. Формы поддерживаются всеми популярными браузерами. Различные аспекты передачи данных Web-серверу будут рассмотрены ниже в разделе "Передача информации СGI-программе". В этом разделе рассмотрены средства языка HTML, используемые для создания форм. В описании тегов приведены только наиболее употребительные параметры и опущены параметры, специфические для отдельных браузеров. В HTML-документе для задания формы используются теги <FORM>. . .</FORM>, отмечающие, соответственно, начало и конец формы. Документ может содержать несколько форм, но они не могут быть вложены одна в другую. Тег <FORM> имеет параметры ACTION, METHOD и ENCTYPE. Отдельные браузеры (Netscape, Internet Explorer) поддерживают дополнительные параметры помимо стандартных, например, CLASS, NAME, STYLE и др. В общем виде форма задается следующим образом: <FORM ACTION="URL" МЕТНОD=метод_передачи ENCTYPE=MIME-тип> содержание_ формы </FORM> Параметр ACTION является единственным обязательным. Его значением является URL-адрес CGI-программы, которая будет обрабатывать информацию, извлеченную из данной формы. Параметр METHOD определяет метод пересылки данных, содержащихся в форме, от браузера к Web-серверу. Он может принимать два значения: GET (по умолчанию) и POST. Примечание Взаимодействие между клиентом-браузером и Web-сервером осуществляется по правилам, заданным протоколом HTTP, и состоит из запросов клиента и ответов сервера. Запрос разбивается на три части. В первой строке запроса содержится HTTP-команда, называемая методом, URL-адрес запрашиваемого файла и номер версии протокола HTTP. Вторая часть — заголовок запроса. Третья часть — тело запроса, собственно данные, посылаемые серверу. Метод сообщает серверу о цели запроса. В протоколе HTTP определены несколько методов. Для передачи данных формы в CGI-программу используются два метода: GET И POST. При использовании метода GET данные формы пересылаются в составе URL-запроса, к которому присоединяются после символа "?" в виде совокупности пар переменноя=значение, разделенных символом "&". В этом случае первая строка запроса может иметь следующий вид:
После выделения данных из URL сервер присваивает их переменной среды QUERY_STRING, которая может быть использована CGI-программой. При использовании метода POST данные формы пересылаются Web-серверу в теле запроса, после чего передаются сервером в CGI-программу через стандартный ввод. Значением параметра ENCTYPE является медиа-тип, определяющий формат кодирования данных при передаче их от браузера к серверу. Браузер кодирует данные, чтобы исключить их искажение в процессе передачи. Возможны два значения этого параметра: application/x-\v\vw-form-urlencoded (по умолчанию) и multipart/form-data. Примечание Одним из первых применений Интернета была электронная почта, ориентированная на пересылку текстовых сообщений. Часто возникает необходимость вместе с текстом переслать данные в нетекстовом формате, например, упакованный zip-файл, рисунок в формате GIF, JPEG и т. д. Для того, чтобы пересылать средствами электронной почты такие файлы без искажения, они кодируются в соответствии с некоторым стандартом. Стандарт MIME (Multipurpose Internet Mail Extensions, многоцелевые расширения электронной почты для Интернета) определяет набор MIME-типов, соответствующих различным типам данных, и правила их пересылки по электронной почте. Для обозначения MIME-типа используется запись вида тип/подтип, где тип определяет общий тип данных, например, text, image, application (тип application обозначает специфический внутренний формат данных, используемый некоторой программой), а подтип— конкретный формат внутри типа данных, например, application/zip, image/gif, text/html. MIME-типы нашли применение в Web, где они называются также медиа-типами, для идентификации формата документов, передаваемых по протоколу HTTP. В HTML-форме параметр ENCTYPE определяет медиа-тип, который используется для кодирования и пересылки специального типа данных — содержимого формы. Как видно из примера на рис. 9.22, форма отображается в окне браузера в виде набора стандартных элементов управления, используемых для заполнения полей формы значениями, которые затем передаются Web-серверу. Значение вводится в поле ввода пользователем или назначается по умолчанию. Для создания полей средствами языка HTML существуют специальные тэги: <INPUT>, <SELECT>, <TEXTAREA>, которые употребляются только внутри тега <FORM>.
Примечание Поле PASSWORD не обеспечивает безопасности введенного текста, так как на сервер он передается в незашифрованном виде.
<SELECT NAME=имя_лоля SIZE=n MULTIPLE> элементы OPTION </SELECT> Тэг <SELECT> предназначен для того, чтобы организовать внутри формы выбор из нескольких вариантов без применения элементов типа CHECKBOX и RADIO. Дело в том, что если элементов выбора много, то представление их в виде флажков или кнопок-переключателей увеличивает размеры формы, делая ее труднообозримой. С помощью тега <SELECT> варианты выбора более компактно представляются в окне браузера в виде элементов ниспадающего меню или списка прокрутки. Тег имеет следующие параметры.
Элементы меню задаются внутри тега <SELECT> при помощи тэга <OPTION>: <OPTION SELECTED VALUE=строка>содержимое_тэга Закрывающий тег </OPTION> не требуется. Параметр VALUE содержит значение, которое пересылается серверу, если данный элемент выбран из меню или списка. Если значение этого параметра не задано, то по умолчанию оно устанавливается равным содержимому тега <OPTION>. Например, элементы <OPTION VALUE=Red>Red <OPTION>Red имеют одно значение Red. В первом случае оно установлено явно при помощи параметра VALUE, во втором — по умолчанию. Параметр SELECTED изначально отображает элемент как выбранный. <TEXTAREA NAME=MM* ROWS=m COLS=n> текст </TEXTAREA> Тэг <TEXTAREA> создает внутри формы поле для ввода многострочного текста, отображаемое в окне браузера в виде прямоугольной области с горизонтальной и вертикальной полосами прокрутки. Для пересылки на сервер каждая введенная строка дополняется символами %OD%OA (ASCII-символы "Возврат каретки" и "Перевод строки" с предшествующим символом %), полученные строки объединяются в одну строку, которая и отправляется на сервер под именем, задаваемым параметром NAME. Параметры:
Между тэгами <TEXTAREA> и </TEXTAREA> можно поместить текст, который будет отображаться по умолчанию. Ниже представлен пример формы, включающей набор характерных полей (рис. 9.23), и HTML-код, использованный для ее создания. Пример 9.5. HTML-код формы, представленной на рис. 9.23 <html><head><title>Пример формы></title></head> <body> <h2>Регистрационная страница Клуба любителей фантастики</h2> Заполнив анкету, вы сможете пользоваться нашей электронной библиотекой. <br> <form method="get" action="/cgi-bin/registrar.cgi"> <pre> Введите регистрационное имя: <input type="text" name="regname"> Введите пароль: <input type="password" name="password1" maxlength=8> Подтвердите пароль: <input type="password" name="password2" maxlength=8> </pre> Ваш возраст: <input type="radio" name="age" value="lt20" checked>До 20 <input type="radio" name="age" value="20_30">20-30 <input type="radio" name="age" value="30_50">30-50 <input type="radio" name="age" value="gt50">старше 50 <br><br> На каких языках читаете: <input type="checkbox" narae="language" value="russian" checked>русский <input type="checkbox" name="language" value="english">английский <input type="checkbox" name="language" value="french">фpaнцyзcкий <input type="checkbox" name="language" value="дегтап">немецкий <br><br> Какой формат данных является для Вас предпочтительным <br> <select name="format" size=2>
</select> <br><br> Ваши любимые авторы: <br> <textarea name="wish" cols=40 rows=3> </textarea> <br><br> <input type="submit" value="OK"> <input type="reset" value="Отменить"> </form> </body> </html> Рис. 9.23. Пример заполнения формы Данная форма содержит:
Итак, пользователь заполнил форму и щелкнул кнопку передачи Submit. Дальнейшее прохождение данных выглядит следующим образом.
Рассмотрим эти шаги более подробно. Передача информации CGI-программе Кодирование и пересылка данных формы Как мы уже знаем, существуют два метода кодирования информации, содержащейся в форме:
Второй метод нужен только в том случае, если к содержимому формы присоединяется локальный файл, выбранный при помощи элемента формы <INPUT TYPE=FILE>. В остальных случаях следует использовать метод кодирования по умолчанию. Схема кодирования application/x-www-form-urlencoded одинакова для обоих методов пересылки (GET и POST) и заключается в следующем. Для каждого элемента формы, имеющего имя, заданное параметром NAME, формируется пара "name=value", где value — значение элемента, введенное пользователем или назначенное по умолчанию. Если значение отсутствует, соответствующая пара имеет вид "пате=". Для радиокнопок и переключателей используются значения только выбранных элементов. Если элемент выбран, а значение параметра VALUE не определено, по умолчанию используется значение "ON". Все пары объединяются в строку, в качестве разделителя служит символ "&". Так как имена и значения представляют собой обычный текст, то они могут содержать символы, недопустимые в составе URL (метод GET пересылает данные как часть URL). Такие символы заменяются последовательностью, состоящей из символа % и их шестнадцатеричного ASCII-кода. Символ пробела может заменяться не только кодом %20, но и знаком + (плюс). Признак конца строки, встречающийся в поле TEXTAREA, заменяется кодом %0D%0A. Такое кодирование называется URL-кодирован нем. Закодированная информация пересылается серверу одним из методов GET или POST. Основное отличие заключается в том, как метод передает информацию CGI-программе. При использовании метода GET данные формы пересылаются серверу в составе URL-запроса, к которому добавляются после символа "?" (вспомним, что запрос это формализованный способ обращения браузера к Web-серверу). Тело запроса в этом случае является пустым. Для формы из примера 9.5 запрос выглядит следующим образом: GET /cgi-bin/registrar.cgi? reg- name=bob&password1=rumata&password2=rumata&age= lt20&language= russian&format=HTML&wish= %F6%C5%CC%Dl%DA%CE%D9 HTTP/1.0 . . (заголовки запроса, сообщающие серверу информацию о клиенте) . <пусто> (тело запроса) Часть URL после символа "?" называется строкой запроса. Web-сервер, получив запрос, присвоит переменной среды QUERY_STRING значение строки запроса и вызовет CGI-программу, обозначенную в первой части URL до символа "?": /cgi-bin/registrar. cgi. CGI-Программа registrar. cgi сможет затем обратиться к переменной QUERY_STRING для обработки закодированных в ней данных. Предупреждение Обратите внимание на то, что данные, введенные в поле типа PASSWORD, передаются открытым текстом без шифрования. При передаче данных методом GET они в составе URL помещаются в файл регистрации доступа access.log, обычно открытый для чтения всем пользователям. Таким образом "секретные" данные, введенные в поле типа PASSWORD, оказываются доступными посторонним. Примечание Метод GET позволяет передавать данные CGI-программе вообще без использования форм. Информацию, содержащуюся в приведенном выше URL, можно передать при помощи следующей гиперссылки, помещенной в HTML-документ: <А HREF="http://www.domain/cgi-bin/registrar.cgi? regname=bob&password1=rumata&password2= r\amata&age=lt20&language= russian&format=HTML&wish=%F6%C5%CC%Dl%DA%CE%D9 ">CCI-программа</А>, заменив в этом фрагменте символ "&" его символьным примитивом & или & для правильной интерпретации браузером. К сожалению, эта информация является статической. Форма же позволяет менять данные. Строка запроса — не единственный способ передачи данных через URL. Другим способом является дополнительная информация о пути (extra path information), представляющая собой часть URL, расположенную после имени CGI-программы. Сервер выделяет эту часть и сохраняет ее в переменной среды PATH_INFO. CGI-программа может затем использовать эту переменную для извлечения данных. Например, URL http://www.domain/cgi-bin/registrar.cgi/regname=bob&password1= r\omata&password2=rumata&age=lt20&language=russian&format=HTML&wish= %F6%C5%CC%D1%DA%CE%D9 содержит уже знакомые нам данные, но не в виде строки запроса, а в виде дополнительной информации о пути. При получении запроса с таким URL сервер сохранит данные в переменной среды. PATH_INFO= "/regname=bob&password1=rumata&password2=rumata&age= lt20&language=russian&format=HTML&wish=%F6%C5%CC%Dl%DA%CE%D9" Название объясняется тем, что обычно этим способом передается информация о местоположении какого-либо файла (extra path information). Например, URL http://www.domain/cgi-bin/registrar.cgi/texts/jdk_doc.txt содержит дополнительную информацию PATH_INFO="/texts/jdk_doc.txt" о местонахождении файла jdk_doc. txt относительно корневого каталога дерева документов. Другая переменная среды PATH_TRANSLATED содержит информацию об абсолютном местоположении файла в файловой системе, например, PATH_TRANSLATED="/home/httpd/docs/texts/jdk_doc.txt" а переменная DOCUMENT_ROOT содержит путь к корневому каталогу дерева документов, В нашем случае DOCUMENT_ROOT="/home/httpd/docs/" . При использовании метода POST данные формы пересылаются серверу в теле запроса. Если в примере 9.5 вместо метода GET использовать метод POST <form method="post" action="/cgi-bin/registrar.cgi">, то запрос клиента будет иметь следующий вид: POST /cgi-bin/registrar.cgi HTTP/1.1 . . (заголовки запроса, сообщающие серверу информацию о клиенте) . Content-length: 126 regname=bob&password1=rumata&password2=rumata&age==lt20&language= russian&forraat=HTML&wish=%F6%C5%CC%Dl%DA%CE%D9 В этом фрагменте среди прочих заголовков выделен заголовок content-length, сообщающий серверу количество байт, переданных в теле запроса. Это значение сервер присваивает переменной среды CONTENT LENGTH, а данные посылает в стандартный ввод CGI-программы. Примечание В операционной системе UNIX для каждого процесса, выполняющего программу, по умолчанию система открывает три специальных файла: стандартный файл ввода (STDIN), стандартный файл вывода (STDOUT) и стандартный файл диагностики (STDERR) соответственно для передачи данных в программу, вывода результатов и сообщений программы. По умолчанию, если для программы не предусмотрено иное, эти специальные файлы ассоциированы с терминалом, т. е. стандартным устройством для ввода данных, которым является клавиатура, а для вывода результатов и сообщений — дисплей. Стандартные ввод, вывод и вывод сообщений могут быть перенаправлены средствами UNIX в произвольный файл или на вход другой программы. Методы GET и POST имеют свои достоинства и недостатки. Метод GET обеспечивает лучшую производительность при пересылке форм, состоящих из небольшого набора коротких полей. При пересылке большого объема данных следует использовать метод POST, так как браузер или сервер могут накладывать ограничения на размер данных, передаваемых в составе URL, и отбрасывать часть данных, выходящую за границу. Метод POST, к тому же, является более надежным при пересылке конфиденциальной информации. Назначение CGI-программы — создать новый HTML-документ, используя данные, содержащиеся в запросе, и передать его обратно клиенту. Если такой документ уже существует, то передать ссылку на него. Какой язык можно использовать для написания CGI-программ? Сам интерфейс CGI не накладывает ограничений на выбор языка программирования. Зная, какую задачу решает CGI-программа и каким образом она получает входную информацию, мы можем назвать свойства, которыми должен обладать язык CGI-программирования.
Выбор языка зависит и от операционной системы Web-сервера. Большая часть имеющихся серверов предназначены для работы под управлением операционной системы UNIX. В этой операционной системе очень распространено использование скриптов — текстовых командных файлов, представляющих собой программы, состоящие из обращений к командам операционной системы и управляющих конструкций языка shell — командной оболочки UNIX. Программа shell является интерпретатором команд операционной системы и, в то же время, имеет встроенные средства, характерные для языков программирования: строковые переменные и управляющие конструкции — операторы цикла, перехода, условные операторы и т. д. Shell выполняет командные файлы как интерпретатор, т. е. считывает из файла и выполняет команды одну за другой с учетом управляющих конструкций, не преобразуя исходный текст в исполняемый двоичный код. При помощи скриптов осуществляется значительная часть работы по конфигурированию ОС. Видимо, с распространенностью командных процедур в UNIX и связано появление в этой операционной системе ряда интерпретирующих языков, предназначенных для создания сценариев: Perl, Python, Tel. Все они могут использоваться для написания CGI-сценариев так же, как и традиционные языки программирования C/C++. Наибольшее распространение в качестве языка CGI-программирования получил язык Perl (Practical Extraction and Report Language). Он удовлетворяет перечисленным выше требованиям и, кроме того, обладает такими полезными свойствами, как:
Perl — достаточно простой язык (по утверждению его создателя). Во-первых, это интерпретируемый язык, а интерпретируемые языки в целом проще языков компилируемых. Во-вторых, его конструкции, в основном заимствованные из других языков, достаточно понятны тем, кто имеет отношение к программированию. Вместе с тем, это мощный язык, обладающий многими возможностями таких языков, как С, UNIX shell, awk (язык обработки текстовых данных в UNIX), sed (утилита UNIX, предназначенная для обработки текста) и, следовательно, требующий времени для усвоения. К счастью, для понимания и создания простых программ не требуется знания всех возможностей Perl, вполне достаточно начального уровня владения языком. Данный раздел не предназначен для того, чтобы служить введением или кратким справочником по языку Perl и технике программирования на нем. Задача другая — дать представление о том, как используется Perl в CGI-программировании. Поэтому мы не стараемся давать формальное определение конструкций языка, предпочитая пояснять их использование на конкретных примерах. Примечание При написании программ следует помнить, что язык Perl, как и ОС UNIX, является чувствительным к регистру символов, поэтому "Perl" и "PERL" обозначают не одно и то же. Первая программа "Hello, world!", с которой начинается изучение любого языка программирования, на языке Perl выглядит так: #!/usr/bin/perl print "Hello, world!\n"; Первая строка сообщает, где находится интерпретатор языка Perl. В UNIX-системах она служит для того, чтобы сопоставить файлу с текстом Perl-программы обрабатывающее его приложение. Другие операционные системы ее игнорируют. Функция print выводит список своих аргументов, преобразованных в строку, в стандартный вывод, по умолчанию ассоциированный с терминалом. Управляющая последовательность \n вызывает переход на новую строку после вывода информации. Отметим также, что большая часть строк Perl-программы завершается символом точка с запятой (;). Исключением являются строки, содержащие операторы цикла и условные операторы. Сохраним текст программы в файле hello.pl. Запустить программу можно по-разному, например, передав имя файла в качестве аргумента командной строки интерпретатору языка: perl hello.pl В ОС UNIX можно сделать файл выполняемым, применив команду chmod 755 hello.pl, и запустить его из командной строки: ./hello.pl CGI-сценарий на языке Perl это программа, имеющая свою специфику, заключающуюся в том, что она, как правило, генерирует HTML-документ, посылаемый клиенту в виде ответа сервера. Ответ сервера, так же как и запрос клиента, имеет определенную структуру. Он состоит из следующих трех частей: 1. Строка состояния, содержащая три поля: номер версии протокола HTTP, код состояния и краткое описание состояния, например: HTTP/1.0 200 ОК # Запрос клиента обработан успешно НТТР/1.0 404 Not Found # Документ по указанному адресу не существует 2. Заголовки ответа, содержащие информацию о сервере и о возвращаемом HTML-документе, например:
3. Содержимое ответа — HTML-документ, являющийся результатом выполнения CGI-программы. CGI-программа передает результат своей работы — HTML-документ — серверу, который возвращает его клиенту. При этом сервер не анализирует и не изменяет полученные данные, он может только дополнять их некоторыми заголовками, содержащими общую информацию (например, текущая дата и время) и информацию о самом себе (например, имя и версия сервера). Информация о содержимом ответа формируется CGI-программой и должна содержать как минимум один заголовок, сообщающий браузеру формат возвращаемых данных: Content-type: text/html Примечание Информацию о заголовках можно найти в спецификации протокола HTTP. Мы же ограничимся еще одним примером. Если в качестве ответа клиенту посылается статический документ, например, подтверждение о получении заполненной формы, то неэффективно каждый раз создавать его заново. Лучше создать один раз и сохранить в файле. В этом случае CGI-сценарий вместо заголовка Content-type: media-type описывающего формат данных, формирует заголовок Location: URL, указывающий серверу местонахождение документа, который следует передать клиенту. Заголовки отделяются от содержимого документа пустой строкой. Преобразуем, учитывая сделанные замечания, программу hello.pl в CGI-сценарий, который сохраним в файле hello.cgi. #!/usr/bin/perl print "Content-type:text/html\n\n"; print "<html><head><title>HELLO</title></head>\n"; print "<body>\n"; print "<h2>Hello, world!</h2>\n"; print "</body></html>\n"; Если поместить файл hello.cgi в каталог CGI-программ Web-сервера, а затем обратиться к нему из браузера, то браузер отобразит HTML-документ, созданный программой hello.cgi (рис. 9.24). Рис. 9.24. Web-страница, сформированная программой hello.cgi Примечание Большинство Web-серверов по умолчанию предполагают, что файлы CGI-сценариев находятся в специальном каталоге, обычно называемом cgi-bin. Можно настроить сервер таким образом, чтобы все файлы, находящиеся в определенном каталоге, он воспринимал не как обычные документы, а как выполняемые сценарии. Можно также указать серверу, что все файлы с определенным расширением (например, CGI) должны рассматриваться как CGI-сценарии. Когда пользователь открывает URL, ассоциированный с CGI-npoграммой, клиент посылает запрос серверу, запрашивая файл. Сервер распознает, что запрошенный адрес является адресом CGI-программы, и пытается выполнить эту программу. Подробности конфигурирования Web-серверов можно найти в соответствующей литературе и документации на конкретный сервер. В языке Perl существует три типа данных и соответственно им три типа переменных: скалярные переменные, массивы скалярных переменных и ассоциативные массивы скалярных переменных (или хеш-массивы). В Perl-программе переменные не нужно явно описывать перед их использованием. Тип переменной определяется начальным символом, предшествующим ее имени. Скалярные переменные Скалярный тип является базовым типом, на основании которого строятся более сложные структуры данных. Скалярная переменная содержит одно значение, которое может быть числом, строкой или ссылкой на другую переменную. Признаком скалярной переменной является начальный символ "$": $name = "mike"; $х = 7; $nameref = \$name; В первой строке примера скалярной переменной $name присваивается строковое значение "mike", во второй строке — скалярной переменной $х присваивается числовое значение 7, в третьей строке — скалярной переменной Snameref присваивается значение ссылки на скалярную переменную $name. Операция \х создает ссылку на объект х, который может быть переменной, подпрограммой или константой. И число, и строка относятся к скалярному типу данных, поэтому в программе скалярная переменная может последовательно принимать числовые и строковые значения, не вызывая сообщения о неправильном использовании типов: #!/usr/bin/perl $pi=3.1416; $pi="Число пи равно $pi"; print "$pi\n"; В результате выполнение этой программы будет выведена строка: Число пи равно 3.1416 Над данными скалярного типа в языке Perl определены арифметические и логические операции, показанные в табл. 9.14. Таблица 9.14. Основные арифметические и логические операции языка Perl
Примечание В языке Perl нет специального типа для представления логических данных, но, в то же время, есть логические операции, выполняемые над скалярными величинами. При выполнении логических операций над данными скалярного типа следует руководствоваться следующими правилами:
Так как логические значения "истина" и "ложь" не имеют однозначной записи, то логические операции && и || в качестве результата возвращают последнее вычисленное в результате применения операции скалярное значение. Операции сравнения скалярных величин определены отдельно для числовых и строковых значений, как показано в табл. 9.15. Таблица 9.15. Операции сравнения
В порядке убывания приоритета операции, перечисленные в табл. 9.14 и 9.15, располагаются следующим образом:
Внесем изменения в нашу первую программу hello.pl, добавив в нее скалярные переменные и некоторые новые конструкции: #!/usr/bin/perl $my_name="Издательство BHV, Санкт-Петербург"; print "Привет, привет. Как Ваше имя?\n"; $your_name=<STDIN>; chomp($your_name) ; print "Здравствуйте, $your_name. Вас приветствует $my_name.\n"; Запуск программы вызовет отображение на экране следующего диалога: perl hello.pl Привет, привет. Как Ваше имя? mike Здравствуйте, mike. Вас приветствует Издательство BHV, Санкт-Петербург. Программа выводит приглашение ввести имя и считывает его в переменную $your_name, используя оператор присваивания $your_name=<STDIN>. Идентификатор STDIN обозначает дескриптор файла стандартного ввода программы. Дескриптор файла — это внутреннее имя файла для интерпретатора Perl. Он создается и связывается с конкретным файлом на диске при помощи специальной функции, о чем будет сказано дальше. Интерпретатор предоставляет Perl-программе несколько предопределенных, автоматически открываемых дескрипторов, которые он сам получает от операционной системы. Это дескриптор стандартного ввода STDIN, дескриптор стандартного вывода STDOUT и дескриптор стандартного вывода диагностики STDERR, обычно связанные с терминалом. Оператор $your_name=<STDIN> читает одну строку из файла, соответствующего дескриптору STDIN, то есть из стандартного ввода программы — терминала. Считанное значение обрабатывается функцией chomp. Функция chomp variable удаляет из строкового аргумента variable признак конца строки. Если его не удалить, то в нашем примере последняя выводимая строка будет разорвана: Здравствуйте, mike . Вас приветствует Издательство BHV, Санкт-Петербург. Массивы Массив это упорядоченный список скалярных значений. Признаком переменной, обозначающей массив, является начальный символ имени "@", например, @names = ("Kate","Bob","Mike"); Здесь определен упорядоченный массив из трех элементов "Kate", "Bob" и "Mike". Значение массива в правой части оператора присваивания представляется конструкцией, состоящей из списка скалярных значений, разделенных запятыми и заключенных в круглые скобки. Префикс @ в имени переменной используется для обозначения массива как совокупности элементов. Для обращения к единичному элементу используется имя массива с префиксом $, сопровождаемое индексом, заключенным в квадратные скобки. Первому элементу массива всегда соответствует индекс 0. $names[0] = "Ann"; @selected_names = @names[1..2]; Обратите внимание на использование префиксов в именах переменных. В первом случае происходит обращение к единичному элементу массива $names[0] для изменения его значения. Во втором случае определяется новый массив @seiected_names, которому присваивается массив значений @names[1. .2], состоящий из элементов "Bob" и "Mike". Использование имени массива в качестве скалярной переменной позволяет легко определить число элементов массива: $number_of_names = @ names; Значение переменной $number_of_names равно числу элементов в массиве @names. В языке Perl можно добавлять новые элементы к массиву при помощи присваивания значений: $names[3] = "John"; Теперь массив @names состоит из четырех элементов: "Ann", "Bob", "Mike" и "John". Функции для работы с массивами Perl располагает набором функций для работы с массивами. Ниже определены наиболее употребительные из них.
Пример: @numbers=("l","2","3") ; $string=join "***", @numbers; Значение переменной $string равно "1***2***3". Ассоциативные массивы Ассоциативный массив или хеш-массив, это неупорядоченное множество пар скалярных величин "ключ-значение". Поскольку хеш-массив представляет собой неупорядоченное, а, значит, ненумерованное множество элементов, то обращение к отдельному элементу осуществляется не через его индекс, которого нет, а через ключ, ассоциированный с этим элементом. Имя переменной, обозначающей ассоциативный массив, содержит в качестве префикса символ "%", например, %phones = ("Ann", "123-45-67",
или более наглядно %phones =("Ann" => "123-45-67",
В этом примере определен хеш-массив %phones, содержащий номера телефонов, ассоциированные с именами их владельцев. Имя служит ключом для выбора отдельного элемента: $ann_phone=$phones{'Ann'}; Переменной $ann_phone присвоено значение "123-45-67". Снова обратите внимание на использование префиксов в именах переменных. Префикс $ в имени хеш-массива, за которым следует значение ключа в фигурных скобках, используется для обращения к единичному элементу, в то время, как префикс % — для ссылки на весь ассоциативный массив. Символы "," и "=>", используемые для создания пары "ключ-значение", являются синонимами. Для получения списка всех ключей или всех значений ассоциативного массива можно использовать функции keys и values, соответственно: @persons= keys %phones; @numbers= values %phones; Массив @persons содержит список ключей хеш-массива %phones, расположенных в случайном порядке. Массив @numbers содержит список значений хеш-массива %phones, расположенных в порядке, соответствующем порядку расположения ключей в массиве @persons:
Можно добавлять элементы к ассоциативному массиву при помощи присваивания: $phones{'John'}="456-78-90" или удалять при помощи функции delete: delete $phones{'john'} Для выполнения операций над множеством элементов массива в языках программирования существуют операторы цикла. Perl имеет несколько таких операторов, из которых мы отметим один, позволяющий работать как с обычными, так и с ассоциированными массивами. foreach $VAR (LIST) {
} В операторе цикла foreach для каждого значения, принимаемого переменной $VAR из списка LIST, выполняется последовательность операторов, заключенная в фигурные скобки {}. Аргумент LIST может быть списком скалярных значений, разделенных запятыми, или переменной, представляющей массив или хеш-массив. Пример: foreach $name (@names) {
} foreach $key ( keys %phones) {
} Результатом выполнения первого оператора foreach будет вывод списка имен, являющихся элементами массива @names: Ann Bob Mike В результате выполнения второго оператора foreach будут выведены следующие строки: Bob 's phone is 234-56-78 Ann 's phone is 123-45-67 Mike 's phone is 345-67-89 Обратите внимание на то, что список телефонов выведен в случайном порядке. Применение функции sort позволяет получить список, отсортированный по значениям ключей: foreach $key ( sort( keys %phones)) {
} Читатель, должно быть, уже догадался, что ассоциативные массивы естественным образом находят применение в CGI-сценариях для обработки данных формы, передаваемых в виде совокупности пар "имя=значение". Все операции в языке Perl выполняются в определенном контексте. Существуют два основных контекста: скалярный и контекст массивов. Результат операции зависит от того, в каком контексте она выполняется. Например, допустимы такие операции присваивания: @a=("one", "two","three"); $a=("one", "two","three"); В первом случае операция выполняется в контексте массива, она присваивает целый список значений переменной-массиву @а. Во втором случае операция выполняется в скалярном контексте, она присваивает единственное значение, равное числу элементов списка (3), скалярной переменной $а. В контексте массива допустима, например, операция присваивания ($опе, $two, $three)= @a, в результате .которой переменным $one, $two, $three будут присвоены последовательные значения из массива @а. В зависимости от метода данные формы передаются в CGI-программу или через стандартный ввод (POST), или через переменную среды QUERY_STRING (GET). Помимо этих данных CGI-программе доступна и другая информация, поступившая от клиента в заголовках запроса или предоставленная Web-сервером. Эта информация сохраняется в переменных среды UNIX. С некоторыми из них мы уже познакомились ранее. В табл. 9.16 перечислены переменные, обычно используемые в CGI. Таблица 9.16. Переменные среды CGI
Предупреждение Имена переменных среды CGI на разных Web-серверах могут различаться. Следует обратиться к документации на соответствующий сервер. CGI-программа на языке Perl имеет доступ к переменным среды через автоматически создаваемый интерпретатором ассоциативный массив %ENV, к элементам которого можно обратиться по ключу, совпадающему с именем переменной среды. Ниже приведен пример CGI-сценария, формирующего HTML-документ с информацией о всех установленных переменных среды, и отображение этого документа в окне браузера. Рис. 9.25. Информация о переменных среды CGI Пример 9.6. Получение информации о переменных среды CGI #!/usr/bin/perl print "Content-type:text/html\n\n"; print "<html>\n"; print "<head><title>Переменные среды</title></head>\n"; print "<body><h2>Переменные среды</h2>\n"; print "<hr><PRE>\n"; foreach $name (sort(keys %ENV)) {
} print "<hr></pre>\n"; print "</body></html>\n"; Поиск и замена текста. Регулярные выражения При обработке текста часто приходится осуществлять поиск фрагментов, удовлетворяющих некоторым условиям, например,
Как видим, условия поиска могут быть достаточно сложными. В языке Perl существуют специальные конструкции, предписывающие интерпретатору организовать поиск, замену или преобразование фрагментов текста, удовлетворяющих некоторому образцу. Рассмотрим следующее выражение: $variable =~ s/pattern/substitution/[e] [g] [i] [m] [о] [s] [x] Левая часть $ variable является скалярной переменной. Правая часть представляет собой конструкцию s/pattern/substitution/[e] [g] [i] [m] [о] [s] [x], которая служит для интерпретатора Perl командой, организующей поиск образца pattern и замену его выражением substitution. Опции egimosx модифицируют процесс поиска и замены, в частности, опция "g" означает выполнение глобальной (а не единичной) замены, а опция "е" означает, что заменяющая строка должна вычисляться как Perl-выражение. Оператор "=~" связывает скалярную переменную с командой подстановки, указывая, что замену следует осуществлять в строке $variable. Значением данного выражения является количество произведенных замен, так что допустима следующая операция присваивания: $count=($variable=~s/pattern/substitution/), в результате которой переменная $count будет равна количеству замен, сделанных в строке $variable. Выражение: $variable=~tr/searchlist/replacementIist/cds предписывает интерпретатору заменить в строке $variable все вхождения символов из списка searchiist на соответствующие символы из списка repiacementlist. Значением выражения является число замененных символов. Опции модифицируют процесс замены следующим образом: с — будет использован не список поиска searchiist, а его дополнение; d — удаление всех символов, для которых нет соответствующего символа в списке замены repiacementlist; s — все последовательности символов, преобразуемые в один и тот же символ, заменяются одним экземпляром этого символа. Образец для поиска pattern представляется в виде регулярного выражения. Регулярное выражение можно рассматривать как шаблон для выделения цепочек символов. Для задания этого шаблона используются специальные символы \ | ( ) [ { ^ $ * + ? . и двухсимвольные конструкции, имеющие в составе регулярного выражения особый смысл. Все остальные символы являются обычными символами, представляющими самих себя. Подробно регулярные выражения рассматриваются в литературе по операционной системе UNIX, где различные их формы используются в командном интерпретаторе shell, утилитах grep, seel, awk, текстовых редакторах ed, vi, emacs. Ограничимся перечислением некоторых конструкций, имеющих в регулярном выражении специальную интерпретацию (табл. 9.17). Таблица 9.17. Конструкции, используемые в регулярных выражениях
Часть регулярного выражения может быть заключена в круглые скобки. В этом случае все заключенные в скобки подвыражения будут пронумерованы слева направо числами 1, 2, и т. д. При нахождении фрагмента, удовлетворяющего образцу, в нем будут выделены части, соответствующие подвыражениям, заключенным в круглые скобки, и сохранены в специальных переменных. К этим переменным в дальнейшем можно обратиться внутри регулярного выражения (при помощи ссылок \1, \2 и т. д.) или за пределами регулярного выражения (при помощи ссылок $1, $2 и т. д.). Примеры:
Поменять местами первые два поля в строке $str.
Присвоить переменной $b значение переменной $а, заменив слово Perl словом Shell. Данные формы поступают в CGI-программу в закодированном виде, поэтому в качестве первого шага обработки CGI-сценарий должен выполнить декодирование полученной информации. При пересылке данных методом GET данные формы присваиваются переменной среды QUERY_STRING, при передаче методом POST — передаются в программу через стандартный ввод и тоже могут быть присвоены некоторой внутренней переменной. Таким образом, декодирование данных сводится к следующей последовательности манипуляций со строкой:
Рассмотренные выше средства языка Perl позволяют написать следующую короткую программу декодирования #!/usr/bin/perl # Декодирование данных формы, переданных методом GET $form_data = $ENV{'QUERY_STRING'}; # преобразование цепочек %hh в соответствующие символы $form_data =~ s/%(..)/pack ("С", hex ($l))/eg; # преобразование плюсов в пробелы $form_data =~ tr/+/ /; # разбиение на пары имя=значение @pairs = split (/&/, $form_data); # выделение из каждой пары имени и значения поля формы и сохранение # их в ассоциативном массиве $form_fields foreach $pair (@pairs) {
} Если данные формы переданы методом POST, то в приведенном тексте следует заменить оператор присваивания $form_data = $ENV{'QUERY_STRING'}; оператором read(STDIN,$form_data,$ENV{'CONTENT_LENGTH'}); считывающим из стандартного ввода программы CONTENT_LENGTH байтов, составляющих содержимое запроса клиента, в переменную $form_data. В приведенном примере используются три новые функции: split, pack и hex. Поясним их назначение прежде, чем перейти к обсуждению текста программы.
В приведенном выше тексте программы все представляется очевидным. Прокомментируем только наиболее насыщенную строку: $form_data =~ s/%(..)/pack ("С", hex ($1))/eg; Образец для поиска задан в виде регулярного выражения %(..). Этому образцу удовлетворяет произвольная последовательность вида %ху, где х, у — любые символы. В результате кодирования данных в качестве х, у могут появиться только шестнадцатеричные цифры, поэтому можно не задавать более точный, но менее компактный шаблон %([0-9A-Fa-f] [0-9A-Fa-f]). Часть выражения заключена в скобки (..). При нахождении подходящего фрагмента %hh его часть, содержащая шестнадцатеричное число hh, сохраняется в переменной, которая затем будет использована в качестве аргумента функции hex($i) для преобразования в десятичное значение. Функция pack упакует это десятичное значение в двоичную структуру, которая в соответствии с шаблоном "с" будет интерпретироваться как символ. Этот символ заменяет в тексте найденную цепочку %hh. После выделения и декодирования данных можно приступить к их обработке. Попробуем написать CGI-сценарий, обрабатывающий данные формы из примера 9.5. Программа должна декодировать полученные данные, проверять заполнение обязательных полей формы и правильность подтверждения пароля, в зависимости от результатов проверки формировать документ для отсылки клиенту. Сохраним сценарий В файле /cgi-bin/registrar.cgi. Полный маршрут к данному файлу определяется параметрами конфигурации Web-сервера. Местоположение каталога cgi-bin обычно указывается не относительно корневого каталога файловой системы, а относительно корня дерева документов Web-сервера. Например, если корнем является каталог /home/httpd/html/, то файл сценария будет иметь маршрутное имя /home/httpd/html/cgi-bin/registrar.cgi, которое в запросе клиента будет указано как /cgi-bin/registrar.cgi. В первом приближении текст сценария может выглядеть следующим образом. Пример 9.7. Первый вариант сценария #!/usr/bin/perl print "Content-type:text/html\n\n"; $method = $ENV{'REQUESTJYETHOD'}; if ($method eq "GET") {
} else {
} $form_data =~ s/%(..)/pack ("C", hex ($1))/eg; $form_data =~ tr/+/ /; @pairs = split (/&/, $form_data); foreach $pair (Spairs) {
} #Проверка заполнения обязательных полей if (!$FORM{'regname'} || !$FORM{'password1'}) { print<<goback
goback ;} #Проверка правильности ввода пароля elsif ($FORM{'password1'} eq $FORM{'password2'}){ print<<confirmation
confirmation ;} else { print<<new_form
new_form ; foreach $key ( keys %FORM) {
} print<<EndOfHTML
value="Отменить">
EndOfHTML ;} После вывода строки заголовка осуществляется считывание переданной серверу информации в переменную $form_data. В зависимости от метода передачи эта информация считывается из переменной среды QUERY_STRING (метод GET) или из стандартного ввода программы (метод POST). Для выбора одного из вариантов здесь использован условный оператор, общая форма которого имеет следующий вид: if (выражение] (...) [ [ elsif (выражение) { ... } ... ] else {...}] Если значение выражения истинно, выполняется соответствующий блок операторов, заключенных в фигурные скобки. Ветви elsif и else являются необязательными. Считанная информация декодируется и помещается в ассоциативный массив %FORM. Отсутствие обязательных данных — регистрационного имени и пароля — проверяется с помощью условия if (!$FORM{'regname'} || !$FORM{'password1'}), смысл которого становится понятен, если вспомнить замечание о том, как интерпретируются значения скалярных величин в условных выражениях. В случае отсутствия необходимых данных формируется виртуальный HTML-документ, предлагающий повторить попытку, который и посылается клиенту (рис. 9.26) При выводе этого документа в операции print использована конструкция, заимствованная из командного интерпретатора UNIX shell и называемая "here document" ("документ здесь"): текст, заключенный между <<word и следующим вхождением идентификатора word, расположенного в отдельной строке, трактуется как заключенный в двойные кавычки. Такая конструкция позволяет внутри себя использовать символы, которые при заключении в обычные двойные кавычки необходимо маскировать символом "\", например, сами двойные кавычки ", символы @, $, %. Важно помнить, что между символом << и идентификатором word не должно быть пробела, а закрывающий конструкцию идентификатор word должен располагаться в отдельной строке. Рис. 9.26. Ответ сервера в случае отсутствия обязательной информации Условие elsif ($FORM{'password1'} eq $FORM{'password2'}) предназначено для проверки совпадения двух копий введенного пользователем пароля. Если значения совпадают, то пользователю посылается сообщение, подтверждающее успешную регистрацию (рис. 9.27). Рис. 9.27. Подтверждение регистрации В противном случае формируется HTML-документ, предлагающий ввести пароль повторно (рис. 9.28). Этот новый документ содержит форму, в состав которой входят два видимых поля типа "password" — для ввода и подтверждения пароля, и скрытые поля типа "hidden" — для сохранения остальных данных, введенных при заполнении исходной формы. Каждое скрытое поле новой формы наследует у соответствующего поля исходной формы параметры name и value. Если эти данные не сохранить, то их придется вводить заново, принуждая пользователя повторно выполнять уже сделанную работу. Информация, сохраненная в скрытых полях, невидима пользователю и недоступна для изменения. Рис. 9.28. Повторное приглашение для ввода пароля Культура Perl допускает различные уровни владения языком. В рассмотренном варианте использован минимальный набор средств. Очевидно, что часть кода, например декодирование, требуется при обработке не только данной, но и любой другой формы. Естественным шагом в развитии исходного варианта сценария является выделение этой части в отдельную подпрограмму и предоставление доступа к ней другим сценариям. Подпрограммы, библиотеки, модули Подпрограммы в языке Perl играют ту же роль, что и функции в языке С, или процедуры и функции в языке Pascal. Они объединяют операторы в одну группу для дальнейшего использования. Подпрограмма может быть объявлена в любом месте основной программы при помощи описания sub subroutine_name {...} Последовательность операторов Perl, заключенная в фигурные скобки, называется блоком. Блоки применяются также в условных операторах и операторах цикла. В языке Perl, как мы знаем, нет обязательного явного описания переменных. Точкой определения переменной является место, где она впервые встречается в программе, а признаком типа — первый символ ее имени. Область действия большинства переменных (исключение составляют некоторые предопределенные глобальные переменные интерпретатора Perl) ограничена пакетом. Пакет это механизм, позволяющий создать свое пространство имен для некоторого отрезка программы (этот отрезок может включать всю программу). Каждый фрагмент кода Perl-программы относится к некоторому пакету. Пакет может быть задан по умолчанию или явно при помощи объявления package package_name Обычно описание пакета встречается в первой строке файлов специального назначения — библиотек и модулей, о чем пойдет речь ниже. Но может встречаться и в любом месте программы. Область пакета распространяется от оператора объявления до конца самого внутреннего вложенного блока или до объявления следующего пакета того же уровня. С каждым пакетом связана своя таблица символов, представляющая собой ассоциированный массив, имя которого совпадает с именем пакета. В ней перечислены все переменные, образующие пространство имен пакета. Каждый пакет имеет имя. Неявно предполагается, что основная программа, не имеющая явного определения пакета, связана с пакетом main. К переменным другого пакета можно обращаться, используя нотацию имя_пакета: : имя_переменной с префиксом, соответствующим типу переменной, например: $main:rmyname, @main::list. Для того чтобы ограничить область действия переменных, внутри блока допускается их явное описание при помощи функций объявления local (Perl 4.0 и Perl 5.0) и my (Perl 5.0). Переменные, объявленные при помощи конструкции local, являются доступными только для операций внутри блока и для подпрограмм, вызываемых внутри блока. Переменные, объявленные при помощи конструкции ту, являются доступными только для операций внутри блока и для подпрограмм, определенных в том же блоке, и недоступны для подпрограмм, определенных за пределами блока. Они не входят в таблицу символов пакета. В версии языка Perl 5.0 в большинстве случаев рекомендуется использовать функцию ту. Если объявляются несколько переменных, то они должны быть заключены в скобки. Переменным при их объявлении могут быть присвоены начальные значения. Примеры объявления локальных переменных:
В языке Perl не различаются понятия "подпрограмма" и "функция". Подпрограмма может быть использована в выражении как функция, возвращающая значение. По умолчанию таким значением подпрограммы является последнее вычисленное в ней выражение. Его можно задать и явно, указав в качестве аргумента функции return о в любой точке подпрограммы. Возвращаемое значение может быть скалярной величиной или массивом. Вызов подпрограммы осуществляется по ее имени, которое может сопровождаться списком параметров в скобках или без скобок. Имя подпрограммы может иметь необязательный префикс "&", являющийся признаком типа: имя_подпрограммы (список_параметров); имя_подпрограммы список_параметров) ; &имя_подпрограммы; Для передачи в подпрограмму аргументы помещаются в специальный массив @_. Внутри подпрограммы они доступны как элементы @_ [ 0 ], @_ [ 1 ], и т. д. Такой механизм позволяет передавать в подпрограмму произвольное количество параметров. В языках программирования различают передачу параметров по ссылке и по значению. При передаче параметров по значению подпрограмма получает копию переменной. Изменение копии внутри подпрограммы не влияет на ее оригинал. При передаче параметров по ссылке подпрограмма получает доступ к самой переменной и может ее изменять. В языке Perl можно реализовать передачу параметров по значению, если внутри подпрограммы объявить локальные переменные и присвоить им значения аргументов из массива @_, как это сделано в следующем примере #!/usr/bin/perl # Передача в подпрограмму параметров по значению $val=&sub1(9,ll) ; print "Значение (9+1) * (11-1) равно $val.\n"; $х = 9; $у = 11; $val = &sub1($x,$y); print "Значение ($х+1) * ($у-1) равно $val.\n"; print "Значение \$х остается равным $х, а \$у равным $у.\n"; sub sub1{ my($x, $y) = @_; return (++$x * --$у); } Результат выполнения: Значение (9+1) * (11-1) равно 100. Значение (9+1) * (11-1) равно 100. Значение $х остается равным 9, а $у равным 11. Примечание В примере использованы заимствованные из языка С префиксные операции увеличения на единицу ++ и уменьшения на единицу --. Передача скалярных параметров по ссылке реализуется обращением внутри подпрограммы непосредственно к элементам массива @_. В этом случае фактический параметр должен быть переменной и не может быть константой, не способной изменять свое значение. #!/usr/bin/perl # Передача в подпрограмму параметров по значению $х = 9; $у = 11; $val = &sub2($x,$y); print "Значение ($х+1) * ($у-1) равно $val.\n"; print "Значение \$х стало равным $х, а \$у равным $у.\n"; sub sub2{ return (++$x * —$у) ; } Результат выполнения: Значение (10+1) * (10-1) равно 100. Значение $х стало равным 10, а $у равным 10. Передача по ссылке этим способом параметров-массивов тоже возможна, но с некоторыми ограничениями: во-первых, несколько параметров-массивов передаются как один массив в составе @_; во-вторых, внутри процедуры нельзя изменять размер массива, следовательно, использовать функции push () и pop (). Для передачи по ссылке массивов можно воспользоваться другим методом, который заключается в том, чтобы внутри подпрограммы объявить локальные переменные, присвоив им значения аргументов из массива @ , а подпрограмме в качестве аргументов передать не массивы, а ссылки на них: #!/usr/bin/perl # Пример подпрограммы, использующей массивы, переданные по ссылке &sub3(\@a1,\@a2) ; print "Измененный массив \@a1: @а1\nИзмененный массив \@а2: @а2\n"; sub sub3{
} Результат работы программы: Эта подпрограмма изменяет массивы @a1 and @a2 Измененный массив @a1: q w e Измененный массив @а2: r t у Примечание Обратите внимание на операцию разыменования, позволяющую обратиться -:* к переменной через ссылку на нее: @$a1ref=("q","w","e"); Обращение к индивидуальному элементу массива в этом случае может иметь одну из следующих эквивалентных форм: $$a1ref [0] = "q"; ${$a1ref}[0] = "q"; $a1ref-> [0] = "q"; В последнем случае в начале выражения опущен символ $, который неявно подразумевается. Эту форму удобно применять в тех в случаях, когда ссылочное выражение является достаточно сложным. Подпрограмма, объявленная внутри основной программы, может быть вызвана в любой ее точке. Чтобы сделать подпрограмму доступной другим программам, в языке Perl существуют два средства: библиотеки (Perl 4.0 и Perl 5.0) и модули (Perl 5.0). Библиотека — это просто коллекция подпрограмм, которая обычно размещается в отдельном файле и образует отдельный пакет со своим пространством имен. Собственное пространство имен позволяет не смешивать одноименные переменные из библиотеки и основной программы. Для создания библиотеки подпрограммы помещаются в один файл с расширением PL, начинающийся строкой объявления пакета package package_name. Имя файла должно совпадать с именем пакета. В конец файла надо добавить строку 1; чтобы она возвращала значение ИСТИНА при включении пакета в основную программу при помощи функции require. Имя файла должно совпадать с именем пакета package_name. Пример библиотеки, состоящей из одной подпрограммы: package cgi_utils; sub print_header { print "Content-type: text/html\n\n"; } 1; Библиотека cgi_utils состоит из одной подпрограммы print_header и сохраняется в файле с именем cgi_utils.pl. Для использования библиотеки в вызывающей программе нужно указать имя библиотеки при помощи функции require: #!/usr/bin/perl require cgi_utils; &cgi_utils::print_header; Более развитым средством, чем библиотеки, являются модули в версии языка Perl 5.0. Модуль представляет собой библиотеку подпрограмм, обладающую дополнительными свойствами по сравнению с библиотеками Perl 4.0. Модуль позволяет управлять экспортом своих переменных и подпрограмм в другие программы, объявляя, какие из них экспортируются по умолчанию, а какие должны быть явно указаны в соответствующем операторе вызывающей программы. Для создания простого модуля следует поместить в начало файла строки следующего вида, за которыми должны следовать собственно подпрограммы: package package_name; require Exporter; @ISA = qw(Exporter); @EXPORT = qw(funcl func2); @EXPORT_OK = qw($var @list %hash func3); Имя файла должно совпадать с именем пакета package_name и иметь расширение РМ. Первая из указанных строк является объявлением пакета. Предложение require Exporter предоставляет возможность наследовать подпрограмму import, реализованную в модуле Exporter. Механизм экспорта имен устроен таким образом, что каждый экспортирующий модуль должен иметь свою подпрограмму import, которая используется программой, импортирующей имена. Подпрограмма import должна быть определена в самом экспортирующем модуле или наследована у модуля Exporter. В третьей строке элементам специального массива @ISA присваиваются имена некоторых пакетов. Применение массива @ISA связано с новыми объектно-ориентированными возможностями Perl 5.0. Мы не будем их обсуждать, так как это выходит за рамки нашей темы. Массив @EXPORT содержит имена, экспортируемые по умолчанию. В четвертой строке указывается, что из данного модуля по умолчанию будут экспортированы имена fund и func2. Конструкция qw(string) возвращает список слов в строке string. Ограничителями, служащими для выделения слов, являются символы пробела, табуляции, новой строки, возврата каретки, подачи бланка. Массив @EXPORT_OK в пятой строке содержит имена, которые будут экспортироваться только в том случае, если они явно указаны в списке импорта вызывающей программы. В вызывающей программе для обращения к модулю используется функция use Module [list] Здесь Module — имя модуля, a list — необязательный список аргументов, позволяющий управлять импортом имен. Если аргументы отсутствуют, то будут импортироваться все имена, определенные в модуле в массиве @EXPORT. Для того чтобы импортировались имена, содержащиеся в массиве @EXPORT_OK, они должны быть явно указаны в списке аргументов list. Если представлен пустой список аргументов (), символы вообще не импортируются. Преобразуем рассмотренную выше в качестве примера библиотеку в модуль. Для этого создадим файл cgi_utils.pm, в который запишем следующие строки: package cgi_utils; require Exporter; @ISA = qw(Exporter); @EXPORT = qw(print_header); sub print_header {
} 1; Соответствующим образом преобразуем вызывающую программу: #!/usr/bin/perl use cgi_utils; &print_header; Используем методы, изложенные в этом разделе, для исправления замечаний, сделанных относительно CGI-сценария из примера 9.7. Пример 9.8. Структурированный вариант сценария а) Часть исходного кода может быть использована другими CGI-программами. Преобразуем ее в отдельный модуль, сохраняемый в файле cgi_utils.pm. package cgi_utils; require Exporter; @ISA = qw(Exporter); 0EXPORT = qw(print_header process_input); # Подпрограмма вывода заголовка ответа sub print_header { print "Content-type: text/html\n\n"; } # Подпрограмма декодирования данных формы sub process_input {
} 1; б) Текст основного сценария обработки формы registrar.cgi преобразуем следующим образом: #!/usr/bin/perl use cgi_utils; my %FORM, $file_rec; $file_rec=&process_input(\%FORM); #Проверка заполнения обязательных полей #if ($FORM{'regname'} eq "" || $FORM{'password1'} eq "") { if (!$FORM{'regname'} || !$FORM{'password1'}) {
#Проверка правильности ввода пароля elsif ($FORM{'password1'} eq $FORM{'password2'}){
} else { iprint header; print<<new_form
new_form ; foreach $key ( keys %FORM) {
} print<<EndOfHTML
EndOfHTML ; } exit в) В исходном варианте сценария в качестве ответов сервера при получении неполных данных и для подтверждения регистрации пользователя формируются виртуальные HTML-документы. В этом нет необходимости, так как они содержат только статическую информацию. Соответствующие фрагменты сценария преобразуем в HTML-код готовых документов, которые сохраним в отдельных файлах. В основном сценарии в качестве ответа сервера возвращаются ссылки на эти документы. Файл confirmation.html содержит документ, посылаемый клиенту в качестве сообщения об успешной регистрации: <html> <head><title>Пoздpaвляeм!</title></head> <body><h2>Пoздpaвляeм! </h2><br> Ваша регистрация прошла успешно. Вы можете пользоваться нашей библиотекой. <br> Спасибо за внимание. </body> </html> Файл goback.html содержит документ, посылаемый клиенту при получении неполных данных: <html> <head><title>Неполные данные</title></head> <body><h2>Извините, Вы пропустили обязательные данные</h2> <br> <а href="http://www.klf.ru/welcome.html">Попробуйте ещё раз, пожалуйста</а> </body> </html> В приведенном тексте появились некоторые новые элементы, которые необходимо пояснить. Подпрограмма process_input модуля cgi_utils.pm передает декодированные данные через вызываемый по ссылке параметр — ассоциативный массив. Кроме того, она возвращает при помощи функции return о те же данные, но в виде строки, состоящей из пар имя=значение, разделенных символом &. Обратите внимание на то, как подпрограмма вызывается в основной программе: $file_rec=&process_input(\%FORM); В качестве аргумента ей передается ссылка на ассоциативный массив. В тексте подпрограммы появилась проверка наличия полей формы с совпадающими именами и разными значениями if (!defined($form_ref->{$name})) {
} else { }} Этот фрагмент необходим для того, чтобы правильно обработать следующую ситуацию из нашего примера. Выбраны несколько переключателей, определяющих языки, которыми владеет пользователь: русский, английский, французский. Так как соответствующие элементы формы имеют одинаковые имена name=language, TO без проверки В ассоциативный массив %form ref, куда помещаются обработанные данные, попадет только информация от последнего обработанного элемента name=language value=french. В подобном случае обычное присваивание заменяется операцией присваивания с конкатенацией $form_ref->{$name} .= "\0$value", которая к переменной $form_ref->{$name} добавляет нулевой символ и значение $value. В основной программе registrar.cgi обратим внимание на то, как передается ссылка на готовый HTML-документ. Для этого вместо заголовка Content-type: text /html выводится заголовок Location: URL, сообщающий серверу адрес документа. Еще один новый элемент в основной программе — работа с файлами. В примере данные сохраняются в файле с именем users. Для записи информации в файл он открывается функцией open с дескриптором OUTF. Напомним, что дескриптор — это внутреннее, используемое системой имя, которое может быть ассоциировано с файлом на диске, устройством (в UNIX устройства также представлены специальными файлами) и другим объектом, к которому применимы файловые операции записи/считывания. Вызов функции open (OUTF, ">>users"); создает дескриптор OUTF, открывает его для добавления данных и связывает с конкретным файлом users. Для указания операций допустимых над открытым файлом используются следующие обозначения:
Запись в файл осуществляется функцией print с указанием дескриптора файла в качестве первого аргумента: print OUTF $file_rec, "\n"; После завершения работы с файлом его необходимо закрыть при помощи функции close. ← к предыдущей главе к следующей главе → Раздел: Учебники / Учебник по HTML |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Copyright © WebNav.ru Обратная@связь |