Язык скриптования сайтов Parser 3

         

Filestat


stat. Получение информации о файле


^file::stat[имя файла]   

Объект, созданный этим конструктором, имеет дополнительные поля (объекты класса date):

$файл.size - размер файла в байтах;

$файл.cdate - дата создания;

$файл.mdate - дата изменения;

$файл.adate - дата последнего обращения к файлу.

имя файла - имя файла с путем.

Пример

$f[^file::stat[some.zip]]

Размер в байтах: $f.size<br>

Год создания: $f.cdate.year<br>

$new_after[^date::now(-3)]



Статус: ^if($f.mdate >= $new_after){новый;старый}



Formclass


Класс form


Класс form предназначен для работы с полями форм. Класс имеет статические поля, доступные только для чтения.

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

^if($edit){

# запись из базы

    $record[^table::sql{… where id=…}]

}{

# новая запись, ошибка при заполнении, необходимо вывести 

# поля формы

    $record[$form:fields]

}

<input name="age" value="$record.age">


Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 13.01.2004



Formfield


Получение значения поля формы


$form:поле_формы   

Такая конструкция возвращает значение поля формы. Возвращаемый объект может принадлежать либо классу file, если поле формы имеет тип file, либо классу string. Дальнейшая работа с объектом возможна только методами, определенными для соответствующих классов.

Поле без имени считается имеющим имя nameless.

Координаты нажатия пользователем на картинку с атрибутом ISMAP доступны через $form:imap.

Пример: обычное поле

<form method="post" enctype="multipart/form-data">

<input type="file" name="photo">

<input type="text" name="user">

<input type="submit">

</form>

^if(def $form:photo){

    ^form:photo.save[binary;/upload/photos/beauty.gif]

}

^if(def $form:user){

    Пользователь: $form:user<br>

}


Сохранит картинку, выбранную пользователем в поле формы и присланную на сервер, в заданном файле.

Пример: безымянное поле

<img src="/show.html?123&a=b">


Внутри show.html строка 123 доступна как $form:nameless.



Formfields


fields. Все поля формы


$form:fields   

Такая конструкция возвращает хеш со всеми полями формы или параметрами, переданными через URL. Имена ключей хеша те же, что и у полей формы, значениями ключей являются значения полей формы.

Пример

^form:fields.foreach[field;value]{

   $field - $value

}[<br>]


Пример выведет на экран все поля формы и соответствующие значения.

Предположим, что URI страницы www.mysite.ru/testing/index.html?name=dvoechnik&mark=2. Тогда пример выдаст следующее:

name - dvoechnik

mark - 2



Formimap


imap. Получение координат нажатия в ISMAP


$form:imap

Если пользователь нажал на картинку с атрибутом ISMAP, такая конструкция возвращает хеш с полями x и y, в которых доступны координаты нажатия.


Пример

В файле /go.html напишите:

$clicked[$form:imap]

^if(def $clicked){

    Пользователь нажал на ISMAP ссылке:<br>

    x=$clicked.x<br>

    y=$clicked.y<br>

}

В файле /test.html напишите:

<a href="/go.html?a=b"><img src="map.png" ismap></a>


Откройте в браузере /test.html и нажмите мышкой на картинке, это приведет к переходу по адресу…

/go.html?a=b?10,30

…и вы увидите…

    Пользователь нажал на ISMAP ссылке:

    x=10

    y=30



Formqtail


qtail. Получение остатка строки запроса


$form:qtail

Возвращает часть $request:query после второго ?.


Пример

Предположим, пользователь запросил такую страницу: http://www.mysite.ru/news/article.html?year=2000&month=05&day=27?thisText

Тогда:

$form:qtail


вернет:

thisText



Formtables


tables. Получение множества значений поля


$form:tables

Такая конструкция возвращает хеш со всеми полями формы или параметрами, переданными через URL. Имена ключей хеша те же, что и у полей формы, значениями же являются таблицы, см. ниже.

$form:tables.поле_формы   

Если поле формы имеет хотя бы одно значение, такая конструкция возвращает таблицу (объект класса table) с одним столбцом field, содержащим все значения поля. Используется для получения множества значений поля.

Внимание: не забудьте проверить наличие таблицы перед тем, как начать ею оперировать.

Пример

Выберите, чем вы увлекаетесь в свободное время:

<form method="POST">

   <p><input type=checkbox name=hobby value="Театр">Театром</p>

   <p><input type=checkbox name=hobby value="Кино">Кино</p>

   <p><input type=checkbox name=hobby value="Книги">Книгами</p>

   <p><input type=submit value="OK"></p>

</form>

$hobby[$form:tables.hobby]

^if($hobby){

    Ваши хобби:<br>

    ^hobby.menu{

        $hobby.field

    }[<br>]

}{

    Ничего не выбрано

}


Пример выведет на экран выбранные варианты или напишет, что ничего не выбрано.



Hash


Хеш (ассоциативный массив)


Хеш, или ассоциативный массив - позволяет хранить ассоциации между строковыми ключами и произвольными значениями. Создание хеша происходит автоматически при таком присваивании переменной значения или вызове метода:

$имя[

    $.ключ1[значение]

    $.ключ2[значение]

    . . . 

    $.ключN[значение]

]


или

^метод[

    $.ключ1[значение]

    $.ключ2[значение]

    . . . 

    $.ключN[значение]

]


Также можно создать пустой копию другого хеша, см. «Класс hash, create. Создание пустого и копирование хеша».

Получение значений ключей хеша:

$имя.ключ


Хеш позволяет создавать многомерные структуры, например, hash of hash, где значениями ключей хеша выступают другие хеши.


$имя[

    $.ключ1_уровня1[$.ключ1_уровня2[значение]]

    . . .     

    $.ключN_уровня1[$.ключN_уровня2[значение]]

]


Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 11.07.2002



Hash_count


_count. Количество ключей хеша


^хеш._count[]   

Возвращает количество ключей хеша.

Пример

$man[

   $.name[Вася]

   $.age[22]

   $.sex[m]

]

^man._count[]


Вернет: 3.

В выражениях числовое значение хеша равно количеству ключей:

^if($man > 2){больше}



Hash_keys


_keys. Список ключей хеша


^хеш._keys[]   

^хеш._keys[имя столбца]   [3.1.2]


Метод возвращает таблицу (объект класса table), содержащую единственный столбец, где перечислены все ключи хеша (порядок перечисления не определен).

Имя столбца - «key» или переданное имя.

Пример

$man[

   $.name[Вася]

   $.age[22]

   $.sex[m]

]

$tab_keys[^man._keys[]]

^tab_keys.save[keys.txt]


Будет создан файл keys.txt с такой таблицей:

key

sex

age

name

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 31.03.2004



Hashadd


add. Сложение хешей


^хеш.add[хеш-слагаемое]   

Добавляет к хешу другой хеш-слагаемое, при этом одноименные ключи хеша перезаписываются.

Пример

$man[

   $.name[Вася]

   $.age[22]

   $.sex[m]

]

$woman[

   $.name[Маша]

   $.age[20]

   $.weight[50]

]

^man.add[$woman]


Новое содержание хеша $man:

$man[

   $.name[Маша]

   $.age[20]

   $.sex[m]

]



Hashclass


Класс hash


Класс предназначен для работы с хешами - ассоциативными массивами. Хеш считается определенным (def), если он не пустой. Числовым значением хеша является число ключей (значение, возвращаемое методом ^хеш._count[]).

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 23.03.2004



Hashcreate


create. Создание пустого и копирование хеша


^hash::create[]  

^hash::create[существующий хеш или хешфайл]


Если параметр не задан, будет создан пустой хеш.

Если указан существующий хеш или хешфайл, конструктор создает его копию.

Пустой хеш, создаваемый конструктором без параметров, нужен в ситуации, когда необходимо динамически наполнить хеш данными, например:

$dyn[^hash::create[]]

^for[i](1;10){

   $dyn.$i[$value]

}

Перед выполнением for мы определили, что именно наполняем.

Если предполагается интенсивная работа по изменению содержимого хеша, но необходимо сохранить, скажем, значения по умолчанию, например:

$pets[

   $.pet[Собака]

   $.food[Косточка]

   $.good[Ошейник]

]

$pets_copy[^hash::create[$pets]]

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 31.03.2004



Hashctors


Конструкторы


Обычно хеши создаются не конструкторами, а так, как описано в разделе "Конструкции языка Parser".

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 11.04.2002



Hashdelete


delete. Удаление пары ключ/значение


^хеш.delete[ключ]   

Метод удаляет из хеша пару ключ/значение.

Пример

^man.delete[name]


Удалит ключ name и связанное с ним значение из хеша man.



Hashfields


Поля


В качестве поля хеша выступает ключ, по имени которого можно получить значение:

$my_hash.key


Такая запись возвратит значение, поставленное в соответствие ключу. Если происходит обращение к несуществующему ключу, будет возвращено значение ключа _default, если он задан в хеше.

Для большей взаимозаменяемости таблиц и хешей поле fields хранит ссылку на сам хеш, см. «Использование хеша вместо таблицы».



Hashfieldsfield


Использование хеша вместо таблицы


$хеш.fields - сам хеш.

Для большей взаимозаменяемости таблиц и хешей поле fields хранит ссылку на сам хеш. См. table.fields.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 15.09.2003



Hashfileclass


Класс hashfile [3.1.2]


Класс предназначен для работы с хешами, хранящимися на диске. В отличие от класса hash объекты данного класса считаются всегда определенным (def) и не имеют числового значения.

Если класс hash хранит свои данные в оперативной памяти, hashfile хранит их на диске, причем можно отдельно задавать время хранения каждой пары ключ-значение.

Замечание: в настоящий момент для хранения одного hashfile используются два файла: .dir и .pag.

Чтение и запись данных происходит очень быстро - идет работа только с необходимыми фрагментами файлов данных.

На простых задачах hashfile работает значительно быстрее баз данных.

Замечание: в один момент времени с файл может изменяться только одним скриптом, остальные ждут окончания его работы.

Пример

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

Можно поместить информацию в hashfile, ассоциировав ее со случайной строкой - идентификатором «сеанса общения с посетителем». Идентификатор сеанса общения можно поместить в cookie, данные теперь хранятся на сервере, не видны посетителю и не могут быть им подделаны.

# создаем/открываем файл с информацией

$sessions[^hashfile::open[/sessions]]

^if(!def $cookie:sid){

    $cookie:sid[^math:uuid[]]

}

# после этого…

$information_string[произвольное значение]

# …так запоминаем произвольную $information_string под ключом sid на 2 дня

$sid[$cookie:sid]

$sessions.$sid[$.value[$information_string] $.expires(2)]

# …а так можем считать сохраненное ранее значение

# если с момента сохранения прошло меньше 2х дней

$sid[$cookie:sid]

$information_string[$sessions.$sid]


Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 31.03.2004



Hashfileclear


clear. Удаление всего содержимого


^hashfile.clear[]


Удаляет все ассоциации.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 23.03.2004



Hashfiledelete


delete. Удаление пары ключ/значение


^hashfile.delete[ключ]   

Метод удаляет из файла пару ключ/значение.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 31.03.2004



Hashfiledeletefiles


delete. Удаление файлов данных с диска


^hashfile.delete[]


Удаляет с диска файлы, в которых хранятся данные хеш файла.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 31.03.2004



Hashfileforeach


foreach. Перебор ключей хеша


^hashfile.foreach[ключ;значение]{тело}

^hashfile.foreach[ключ;значение]{тело}[разделитель]

^hashfile.foreach[ключ;значение]{тело}{разделитель}

Перебирает все ключи хеша и соответствующие им значения (порядок перебора не определен). Метод аналогичен foreach класса hash.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 31.03.2004



Hashfilehash


hash. Преобразование к обычному hash


^hashfile.hash[]


Преобразует hashfile в обычный хеш.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 23.03.2004



Hashfileopen


open. Открытие или создание


^hashfile::open[имя файла]  


Открывает имеющийся на диске файл или создает новый.

Для хранения данных в настоящий момент используются два файла, с суффиксами .dir и .pag.


Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 31.03.2004



Hashfileread


Чтение


$hashfile.ключ


Возвращает строку, ассоциированную с ключом, если эта ассоциация не устарела.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 31.03.2004



Hashfilewrite


Запись


$hashfile.ключ[строка]


Сохраняет на диск ассоциацию между ключом и строкой.

$hashfile.ключ[

   $.value[строка]

   $.expires(число дней)

]

$hashfile:ключ[

   $.value[строка]

   $.expires[дата]

]


Такая запись позволяет указать дату устаревания ассоциации. Можно указать число дней или конкретную дату.

Необязательные модификаторы:

$.expires(число дней) - задает число дней (может быть дробным, 1.5=полтора дня), на которое сохраняется пара ключ/строка, 0 дней=навсегда;

$.expires[$date] - задает дату и время, до которой будет храниться ассоциация, здесь $date - переменная типа date.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 05.04.2004



Hashforeach


foreach. Перебор ключей хеша


^хеш.foreach[ключ;значение]{тело}

^хеш.foreach[ключ;значение]{тело}[разделитель]

^хеш.foreach[ключ;значение]{тело}{разделитель}

Метод аналогичен методу menu класса table. Перебирает все ключи хеша и соответствующие им значения (порядок перебора не определен).

ключ - имя переменной, которая возвращает имена ключей   

значение - имя переменной, которая возвращает соответствующие значения ключей   

тело - код, исполняемый для каждой пары ключ-значение хеша   

разделитель - код, который выполняется перед каждым непустым не первым телом   

Пример

$man[

   $.name[Вася]

   $.age[22]

   $.sex[m]

]

^man.foreach[key;value]{

        $key=$value

}[<br>]


Выведет на экран:

sex=m 

age=22 

name=Вася

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 31.03.2004



Hashintersection


intersection. Пересечение хешей


^хеш_a.intersection[хеш_b]   

Метод выполняет пересечение двух хешей. Возвращает хеш, содержащий ключи, принадлежащие как хешу a, так и b. Результат необходимо присваивать новому хешу.

Пример

$man[

   $.name[Вася]

   $.age[22]

   $.sex[m]

]

$woman[

   $.name[Маша]

   $.age[20]

   $.weight[50]

]

$int_hash[^man.intersection[$woman]]


Получится хеш $int_hash:

$int_hash[

   $.name[Вася]

   $.age[22]

]



Hashintersects


intersects. Определение наличия пересечения хешей


^хеш_a.intersects[хеш_b]   

Метод определяет наличие пересечения (одинаковых ключей) двух хешей. Возвращает булевое значение "истина", если пересечение есть, или "ложь" в противном случае.

Пример

^if(^man.intersects[$woman]){

   Пересечение есть

}{

   Не пересекаются

}



Hashsql


sql. Создание хеша на основе выборки из базы данных


^hash::sql{запрос}  

^hash::sql{запрос}[$.limit(n) $.offset(o) $.distinct(d)]


Конструктор создает хеш, в котором имена ключей совпадают со значениями первого столбца выборки. Имена столбцов формируют ключи хеша, а значения столбцов - соответствующие этим ключам значения. Если столбцов больше одного, получается структура hash of hash.

Если же запрос возвращает только один столбец, формируется хеш, где значения столбца формируют ключи хеша, и им ставится в соответствие логическое значение истина.   [3.1.2]

Дополнительные параметры конструктора:

$.limit(n) - получить только n записей

$.offset(o) - отбросить первые o записей выборки

$.distinct(1/0) - 1=отбирать записи с уникальным ключом, 0=считать наличие дубликата ошибкой

По-умолчанию, наличие в ключевом столбце одинаковых значений считается ошибкой, если вам необходимо именно отобрать из результата записи с уникальным ключом, задайте опцию $.distinct(1).

Примечание: имейте в виду, что так между клиентом и сервером передаются лишние данные, и, скорее всего, запрос можно изменить, чтобы необходимая уникальность ключа обеспечивалась SQL-сервером. Если вам необходимы данные и в виде таблицы и в виде хеша, подумайте над использованием table::sql в паре с table.hash.

Пример hash of hash

В БД содержится таблица hash_table:

pet   food   aggressive

cat   milk   very

dog   bone   never


Выполнение кода…

^connect[строка подключения]{

   $hash_of_hash[^hash::sql{select 

      pet, food, aggressive

   from 

      hash_table

   }]

}


…даст хеш такой структуры…

$hash_of_hash[

   $.cat[

      $.food[milk]

      $.aggressive[very]



   ]

   $.dog[

      $.food[bone]

      $.aggressive[never]

   ]

]



… из которого можно эффективно извлекать информацию, например, так:

$animal[cat]

$animal любит $hash_of_hash.$animal.food

Пример hash of bool   [3.1.2]

В БД содержится таблица participants:

participant

Константин

Александр



Выполнение кода…

^connect[строка подключения]{

   $participants[^hash::sql{select participant from participants}]

}



…даст хеш такой структуры…

$participants[

   $.Константин(1)

   $.Александр(1)

]



…из которого можно эффективно извлекать информацию, например, так:

$person[Иван]

$person ^if($participants.$person){участвует}{не участвует} в мероприятии



Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 31.03.2004

Hashsub


sub. Вычитание хешей


^хеш.sub[хеш-вычитаемое]   

Метод вычитает из хеша другой хеш-вычитаемое, удаляя ключи, общие для обоих хешей.

Пример

$man[

   $.name[Вася]

   $.age[22]

   $.sex[m]

]

$woman[

   $.name[Маша]

   $.age[20]

]

^man.sub[$woman]


В результате в хеше $man останется только один ключ $man.sex со значением m.



Hashunion


union. Объединение хешей


^хеш_a.union[хеш_b]   

Метод выполняет объединение двух хешей. Возвращает хеш, содержащий все ключи хеша a и те из b, которых нет в a. Результат необходимо присваивать новому хешу.

Пример

$man[

   $.name[Вася]

   $.age[22]

   $.sex[m]

]

$woman[

   $.name[Маша]

   $.age[20]

   $.weight[50]

]

$union_hash[^man.union[$woman]]

Получится хеш $union_hash:

$union_hash[

   $.name[Вася]

   $.age[22]

   $.sex[m]

   $.weight[50]

]



Home




Студия Лебедева представляет…



…язык скриптования сайтов Parser3.

Автор технологии Parser:

Константин Моршнев

Автор Parser3:

Александр Петросян (PAF)

Авторы документации:

Алексей Сорокин

Владимир Муров

Александр Петросян (PAF)

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 24.03.2004



How2read


Как работать с документацией


Данное руководство состоит из трех частей.

В первой, учебной части рассматриваются практические задачи, решаемые с помощью Parser. На примере создания учебного сайта показаны базовые возможности языка и основные конструкции. Для создания кода можно пользоваться любым текстовым редактором. Желательно, чтобы в нем был предусмотрен контроль над парностью скобок с параллельной подсветкой, поскольку при увеличении объема кода и его усложнении становится сложно следить за тем, к чему относится та или иная скобка, и эта возможность существенно облегчит ваш труд. Также поможет в работе и выделение цветом конструкций языка. Читать и редактировать код станет намного проще.

Учебная часть построена в виде уроков, в начале которых предлагается рабочий код, который можно просто скопировать в нужные файлы. Далее подробно разбирается весь пример с объяснением логики его работы. В конце каждого урока тезисно перечислены все основные моменты, а также даны рекомендации, на что надо обратить особое внимание. Внимательное изучение представленных уроков обеспечит вас необходимым запасом знаний для последующей самостоятельной работы над проектами на Parser.

Во второй части представлен справочник по синтаксису языка и подробно рассмотрены правила описания различных конструкций.

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

В приложениях к документации рассмотрены вопросы установки и конфигурирования Parser.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 29.09.2003



Imagearc


arc. Рисование дуги


^картинка.arc(center x;center y;width;height;start in degrees;end in degrees;color)    

Метод рисует дугу с заданными параметрами. Дуга представляет собой часть эллипса (как частный случай окружности) и задается координатами центра X и Y, шириной, высотой, а также начальным и конечным углом, задаваемым в градусах.

Пример

$square[^image::create(100;100;0x000000)]

^square.arc(50;50;40;40;0;90;0xFFFFFF)

$response:body[^square.gif[]]


В браузере будет выведен черный квадрат с дугой в четверть (от 0 до 90 градусов) окружности радиусом 40 пикселов.



Imagebar


bar. Рисование закрашенных прямоугольников


^картинка.bar(x0;y0;x1;y1;цвет прямоугольника)    


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

Пример

$square[^image::create(100;100;0x000000)]

^square.bar(5;40;95;60;0xFFFFFF)

$response:body[^square.gif[]]


В браузере будет выведен черный квадрат размером 100 на 100 пикселов, внутри которого находится белый прямоугольник 90 x 20 пикселов, нарисованный по заданным координатам.



Imagecircle


circle. Рисование неокрашенной окружности


^картинка.circle(center x;center y;радиус;цвет линии)    


Метод рисует окружность заданного радиуса линией заданного цвета относительно центра с координатами X и Y.

Пример

$square[^image::create(100;100;0x000000)]

^square.circle(50;50;10;0xFFFFFF)

$response:body[^square.gif[]]


В браузере будет выведен черный квадрат с окружностью радиусом в десять пикселов, нарисованной линией белого цвета с центром в точке (50;50).



Imageclass


Класс image


Класс для работы с графическими изображениями. Объекты класса image бывают двух типов. К первому относятся объекты, созданные на основе существующих изображений в поддерживаемых форматах. Ко второму - объекты, формируемые самим Parser.

Из JPEG файлов можно получить EXIF информацию (http://www.exif.org).

Для представления цветов используется схема RGB, в которой каждый оттенок цвета представлен тремя составляющими компонентами (R-красный, G-зеленый, B-синий). Каждая составляющая может принимать значение от 0x00 до 0xFF (0 - 255 в десятичной системе). Итоговый цвет представляет собой целое число вида 0xRRGGBB, где под каждую составляющую компоненту отведено два разряда в указанной последовательности. Формула для вычисления цвета следующая:

(R*0x100+G)*0x100+B


Так, для белого цвета, у которого все компоненты имеют максимальное значение - FF, данная формула при подстановке дает:

(0xFF*0x100+0xFF)*0x100+0xFF = 0xFFFFFF



Imagecopy


copy. Копирование фрагментов изображений


^картинка.copy[исходное_изображение](x1;y1;ширина1;высота1;x2;y2)  ^картинка.copy[исходное_изображение](x1;y1;ширина1;высота1;x2;y2;ширина2;высота2;приближение цвета)


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

1.Исходное изображение

 

2.координаты (X1;Y1) верхнего левого угла копируемого фрагмента  

3.ширина и высота копируемого фрагмента  

4.координаты (X2;Y2) по которым будет вставлен копируемый фрагмент  

5.в качестве необязательных параметров могут быть заданы новая ширина и высота вставляемого фрагмента (в этом случае происходит масштабирование), а также величина, характеризующая точность передачи цвета. Чем она меньше, тем точнее цветопередача, но количество передаваемых цветом уменьшается и наоборот (по умолчанию равна 150)  


Пример

$mygif[^image::load[test.gif]]

$resample_width($mygif.width*2)

$resample_height($mygif.height*2)

$mygif_new[^image::create($resample_width;$resample_height)]

^mygif_new.copy[$mygif](0;0;20;30;0;0;$mygif_new.width;$mygif_new.height)

$response:body[^mygif_new.gif[]]


В данном примере мы создаем два объекта класса image. Первый создан на основе существующего GIF файла. Второй - вдвое больший по размеру, чем первый, создается самим Parser, после чего в него мы копируем фрагмент первого размером 20х30 и «растягиваем» этот фрагмент на всю ширину и высоту второго рисунка. Последняя строчка кода выводит увеличенный фрагмент на экран. Данный подход можно применять только для изображений, которые не требуется выводить с хорошим качеством.



Imagecreate


create. Создание объекта с заданными размерами


^image::create(размер X; размер Y)  

^image::create(размер X; размер Y; цвет фона)    


Создает объект класса image размером X на Y. В качестве необязательного параметра можно задать произвольный цвет фона. Если этот параметр пропущен, созданное изображение будет иметь белый цвет фона.

Пример

$square[^image::create(100;100;0x000000)]


Будет создан объект square класса image размером 100х100 c черным цветом фона.



Imagefields


Поля


$картинка.src

- имя файла

$картинка.width

- ширина

$картинка.height

- высота

$картинка.exif

- хеш с EXIF информацией

Ключами $картинка.exif являются названия EXIF тегов, см. спецификацию (http://www.exif.org/specifications.html). Значения бывают типов string, int, double, date. Когда тег имеет несколько значений, они считываются в хеш, ключами которого являются цифры (0…количество_значений-1).

Часто используемые EXIF теги (см. подробности в спецификации):

Тег

Тип

Описание

Make

string

Производитель фотоаппарата

Model

string

Модель фотоаппарата

DateTimeOriginal

date

Дата и время съемки

ExposureTime

double

Выдержка в секундах

FNumber

double

Диафрагменное число F

Flash

int

0= не использовалась

другие значения=использовалась

Примечание: ключами нестандартных EXIF тегов являются их значения в десятичной системе счисления.

Пример

$photo[^image::measure[photo.jpg]]

Имя файла: $photo.src<br>

Ширина изображения в пикселах: $photo.width<br>

Высота изображения в пикселах: $photo.height<br>

$date_time_original[$photo.exif.DateTimeOriginal]

^if(def $date_time_original){

    Снимок сделан ^date_time_original.sql-string[]<br>

}


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



Imagefill


fill. Закрашивание одноцветной области изображения


^картинка.fill(x;y;цвет)   


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

Пример

$square[^image::create(100;100;0x000000)]

^square.line(0;0;100;100;0xFFFFFF)

^square.fill(10;0;0xFFFF00)

$response:body[^square.gif[]]


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



Imagefont


font. Загрузка файла шрифта для нанесения надписей на изображение


^картинка.font[набор_букв;имя_файла_шрифта.gif](ширина_пробела)

^картинка.font[набор_букв;имя_файла_шрифта.gif](ширина_пробела;ширина_символа)    

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

После загрузки такого файла с помощью метода font набору букв, заданных в параметрах метода, ставятся в соответствие фрагменты изображения из файла. Данный файл должен быть в формате GIF с прозрачным фоном и содержать изображение необходимого набора символов в следующем виде:

Пример файла digits.gif с изображением цифр:

0

1

2

3

4

5

6

7

8

9

Высота каждого символа определяется как отношение высоты рисунка к количеству букв в наборе.

Методу передаются следующие параметры:


Набор букв - перечень символов, входящих в файл шрифта

Имя и путь к файлу шрифта

Ширина символа пробела (в пикселах)

Ширина символа - необязательный параметр

По умолчанию, при загрузке файла шрифта автоматически измеряется ширина всех его символов и при выводе текста используется пропорциональный (proportional) шрифт. Если задать ширину символа, то шрифт будет моноширинным.

Все символы следует располагать непосредственно у левого края изображения.

Пример

$square[^image::create(100;100;0x00FF00)]

^square.font[0123456789;digits.gif](0)


В данном случае будет загружен файл, содержащий изображения цифр от 0 до 9, и набору цифр от 0 до 9 будет поставлено в соответствие их графическое изображение. После того, как определен шрифт для нанесения надписи, можно использовать метод text для нанесения надписей.



Imagegif


gif. Кодирование объектов класса image в формат GIF


^картинка.gif[]    

^картинка.gif[имя файла]   [3.1.2]


Используется для кодирования созданных Parser объектов класса image в формат GIF.

Имя файла будет передано посетителю при $response:download.

Внимание: в результате использования этого метода создается новый объект класса file, а не image!

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

Пример

$square[^image::create(100;100;0x000000)]

$response:body[^square.gif[]]


В браузере будет выведен черный квадрат размером 100 на 100 пикселов.



Imagehtml


html. Вывод изображения


^картинка.html[]   

^картинка.html[хеш]   


Создает следующий HTML-тег:

<img src="$image.src" width="$image.width" height="$image.height" />

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

Замечание: атрибуты изображения можно переопределять.

Пример

$photo[^image::measure[myphoto.jpg]]

^photo.html[

   $.border[0]

   $.alt[Это я в молодости…]

]


В браузере будет выведена картинка из переменной $photo. При наведении курсора будет появляться надпись: это я в молодости…



Imagelength


length. Получение длины надписи в пикселах


^картинка.length[текст надписи]   

Метод вычисляет полную длину надписи в пикселах.

Пример

$square[^image::create(100;100;0x00FF00)]

^square.font[0123456789;digits.gif](0)

^square.length[128500]


В результате будет вычислена длина надписи «128500» в пикселах с учетом пробелов.



Imageline


line. Рисование линии на изображении


^картинка.line(x0;y0;x1;y1;цвет)    


Метод рисует на изображении линию из точки с координатами (х0:y0) в точку (x1:y1) заданного цвета.

Пример

$square[^image::create(100;100;0x000000)]

^square.line(0;0;100;100;0xFFFFFF)

$response:body[^square.gif[]]


В браузере будет выведен черный квадрат размером 100 на 100 пикселов перечеркнутый по диагонали белой линией.



Imageload


load. Создание объекта на основе графического файла в формате GIF


^image::load[имя_файла.gif]    


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

Пример

$background[^image::load[counter_background.gif]]


Будет создан объект класса image на основе готового изображения в формате GIF. Этот объект может впоследствии использоваться для подложки в методах рисования.



Imagemeasure


measure. Создание объекта на основе существующего графического файла


^image::measure[файл]

^image::measure[имя файла]


Создает объект класса image, измеряя размеры существующего графического файла или объекта класса file в поддерживаемом формате (сейчас поддерживаются GIF, JPEG и PNG).

Из JPEG файлов также считывается EXIF информация (http://www.exif.org), если она там записана. Большинство современных цифровых фотоаппаратов при записи JPEG файла записывают в него также информацию о снимке, параметрах экспозиции и другую информацию в формате EXIF.

Сама картинка не считывается, основное назначение метода - последующий вызов для созданного объекта метода html.

Параметры:

Файл - объект класса file

Имя файла - имя файла с путем

Примечание: поддерживается EXIF 1.0, считываются теги из IFD0 и SubIFD.

Пример создания тега IMG с указанием размеров изображения

$photo[^image::measure[photo.png]]

^photo.html[]


Будет создан объект photo класса image, на основе готового графического изображения в формате PNG, и выдан тег IMG, ссылающийся на данный файл, с указанием width и height.

Пример работы с EXIF информацией

$image[^image::measure[jpg/DSC00003.JPG]]

$exif[$image.exif]

^if($exif){

    Производитель фотоаппарата, модель: $exif.Make $exif.Model<br>

    Время съемки: ^exif.DateTimeOriginal.sql-string[]<br>

    Выдержка: $exif.ExposureTime секунды<br>

    Диафрагма: F$exif.FNumber<br>

    Использовалась вспышка: ^if(def $exif.Flash){^if($exif.Flash){да;нет};неизвестно}<br>

}{

    нет EXIF информации<br>

}

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 09.02.2004



Imagepaint


Методы рисования


Данные методы используются только для объектов класса image, созданных с помощью конструкторов create и load. С их помощью можно рисовать линии и различные геометрические фигуры на изображениях и закрашивать области изображений различными цветами. Это дает возможность создавать динамически изменяемые картинки для графиков, графических счетчиков и т.п.

Отсчет координат для графических объектов ведется с верхнего левого угла, точка с координатами (0:0).



Imagepixel


pixel. Работа с точками изображения


^картинка.pixel(x;y)


Выдает цвет указанной точки изображения. Если координаты попадают за пределы изображения, выдает -1.

^картинка.pixel(x;y;цвет)


Задает цвет указанной точки.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 24.03.2004



Imagepolybar


polybar. Рисование окрашенных многоугольников по координатам узлов


^картинка.polybar(цвет многоугольника)[таблица с координатами узлов]    


Метод рисует многоугольник заданного цвета по координатам узлов, задаваемым в таблице. Последний узел автоматически соединяется с первым.

Пример

$rectangle_coordinates[^table::create{x   y

0   0

50   100

100   0

}]

$square[^image::create(100;100;0x000000)]

^square.polybar(0x00FF00)[$rectangle_coordinates]

$response:body[^square.gif[]]


В браузере будет выведен равнобедренный треугольник зеленого цвета на черном фоне. В таблице заданы координаты вершин треугольника.



Imagepolygon


polygon. Рисование неокрашенных многоугольников по координатам узлов


^картинка.polygon(цвет линии)[таблица с координатами узлов]    


Метод рисует линией заданного цвета многоугольник по координатам узлов, задаваемым в таблице. Последний узел автоматически соединяется с первым.

Пример

$rectangle_coordinates[^table::create{x   y

0   0

50   100

100   0

}]

$square[^image::create(100;100;0x000000)]

^square.polygon(0x00FF00)[$rectangle_coordinates]

$response:body[^square.gif[]]


В браузере будет выведен равнобедренный треугольник, нарисованный линией зеленого цвета на черном фоне. В таблице заданы координаты вершин треугольника.



Imagepolyline


polyline. Рисование ломаных линий по координатам узлов


^картинка.polyline(цвет)[таблица с координатами точек]    


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

Пример

$table_with_coordinates[^table::create{x   y

10   0

10   100

20   100

20   50

50   50

50   40

20   40

20   10

60   10

65   15

65   0

10   0

}]

$square[^image::create(100;100;0xFFFFFF)]

$square.line-style[***   ]

$square.line-width(2)

^square.polyline(0xFF00FF)[$table_with_coordinates]

$file_withgif[^square.gif[]]

^file_withgif.save[binary;letter_F.gif]

$letter_F[^image::load[letter_F.gif]]

^letter_F.html[]


В браузере будет выведена буква F, нарисованная пунктирной линией на белом фоне. В рабочем каталоге будет создан файл letter.gif. В этом примере используются объекты класса image двух различных типов. В таблице задаются координаты точек ломанной линии. Затем на созданном с помощью конструктора create фоне рисуется линия по указанным координатам узлов. Созданный объект класса image кодируется в формат GIF. Полученный в результате этого объект класса file сохраняется на диск. Затем создается новый объект класса image на основе сохраненного файла. Этот объект выводится на экран браузера методом html.



Imagerectangle


rectangle. Рисование незакрашенный прямоугольников


^картинка.rectangle(x0;y0;x1;y1;цвет линии)    


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

Пример

$square[^image::create(100;100;0x000000)]

^square.rectangle(5;40;95;60;0xFFFFFF)

$response:body[^square.gif[]]


В браузере будет выведен черный квадрат размером 100 на 100 пикселов, внутри которого находится прямоугольник 90 x 20 пикселов, нарисованный линией белого цвета по заданным координатам.



Imagereplace


replace. Замена цвета в области, заданной таблицей координат


^картинка.replace(старый цвет;новый цвет)[таблица с координатами точек]    


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

Пример

$paint_nodes[^table::create{x   y

10   20

90   20

90   80

10   80

}]

$square[^image::create(100;100;0x000000)]

^square.line(0;0;100;100;0xFFFFFF)

^square.line(100;0;0;100;0xFFFFFF)

^square.replace(0x000000;0xFF00FF)[$paint_nodes]

$response:body[^square.gif[]]


В браузере будет выведен черный квадрат, перечеркнутый по диагонали белыми линиями, со вписаным в него розовым прямоугольником. Поскольку в методе replace задана замена на розовый цвет только для черного цвета, белые линии не перекрасились.



Imagesector


sector. Рисование сектора


^картинка.sector(center x;center y;width;height;start in degrees;end in degrees;color)    

Метод рисует сектор с заданными параметрами линией заданного цвета. Параметры метода аналогичны методу arc.

Пример

$square[^image::create(100;100;0x000000)]

^square.sector(50;50;40;40;0;90;0xFFFFFF)

$response:body[^square.gif[]]


В браузере будет выведен черный квадрат с сектором в четверть (от 0 до 90 градусов) окружности радиусом 40 пикселов. Сектор нарисован линией белого цвета.



Imagestylewidth


Тип и ширина линий


$картинка.line-style[тип линии]   

$картинка.line-width(толщина линии)


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

Тип линии задается строкой, где пробелы означают отсутствие точек в линии, а любые другие символы - наличие.

Пример

$картинка.line-style[***   ]

$картинка.line-width(2)


Для методов рисования будет использоваться пунктирная линия вида:

***   ***   ***   ***   ***

толщиной в два пиксела.



Imagetext


text. Нанесение надписей на изображение


^картинка.text(x;y)[текст надписи]    

Метод выводит заданную надпись по указанным координатам (X;Y), используя файл шрифта, предварительно загруженный методом font

Пример

$square[^image::create(100;100;0x00FF00)]

^square.font[0123456789;digits.gif](0)

^square.text(5;5)[128500]

$response:body[^square.gif[]]


В браузере будет выведен зеленый квадрат с надписью «128500» левая верхняя точка которой находится в точке с координатами (5;5).



Install


Установка и настройка Parser


Parser3 доступен в нескольких вариантах:

·CGI скрипт (и интепретатор),  

·модуль к веб-серверу Apache 1.3,  

·ISAPI расширение веб-сервера Microsoft Internet Information Server 4.0 или новее.  


Дополнительно можно установить драйверы для различных SQL-серверов (сейчас доступны для MySQL, PgSQL, Oracle, ODBC).

Описание каталогов и файлов :

parser3[.exe] - CGI скрипт (и интерпретатор)

ApacheModuleParser3.dll - модуль к веб-серверу Apache 1.3

parser3isapi.dll - ISAPI расширение веб-сервера IIS 4.0 или новее

auto.p.dist - пример Конфигурационного файла

parser3.charsets/ - каталог с файлами таблиц кодировок:

koi8-r.cfg

 - Cyrillic [KOI8-R]

windows-1250.cfg

 - Central european[windows-1250]

windows-1251.cfg

 - Cyrillic[windows-1251]

windows-1257.cfg

 - Baltic[windows-1257]

Поскольку исходные коды являются открытыми, вы можете сами собрать Parser (см. Сборка Parser их исходных кодов) и написать свой SQL-драйвер.

Доступны скомпилированные версии Parser и его SQL-драйверов под ряд платформ (см. http://parser.ru/download/).

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

Как подключаются конфигурационные файлы?

Для CGI скрипта (parser3[.exe]):

конфигурационный файл считывается из файла, заданного переменной окружения CGI_PARSER_CONFIG,

Если переменная не задана, ищется в том же каталоге, где расположен сам CGI скрипт.

Для модуля к Apache путь к конфигурационному файлу задается директивой:

#can be in .htaccess

ParserConfig полный_путь


Для ISAPI расширения (parser3isapi.dll):

конфигурационный файл auto.p ищется в том же каталоге, где расположен сам файл.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 20.02.2004



Install4apachecgi


Установка Parser на веб-сервер Apache, CGI скрипт


Для установки Parser необходимо внести изменения в основной конфигурационный файл веб-сервера, или, если у вас нет к нему доступа, необходима возможность использовать .htaccess файлы.

По-умолчанию, в установке Apache возможность использования .htaccess отключена.

Если она вам необходима, разрешите их использовать (по крайней мере, задавать FileInfo). Для чего в основном конфигурационном файле веб-сервера (обычно httpd.conf) в секцию <virtualhost …> вашего сайта, или вне ее - для всех сайтов, добавьте директивы:

<Directory /путь/к/вашему/веб/пространству>

AllowOverride FileInfo

</Directory>

Parser3 самостоятельно выполняет необходимые перекодирования, так что для Русского Apache добавьте в основной конфигурационный файл веб-сервера (обычно httpd.conf) строку:

CharsetDisable On

запрещающую использование возможностей перекодирования Русского Apache для вашего сервера.

Если возможности изменить основной конфигурационный файл веб-сервера у вас нет, добавьте эту строку в .htaccess файл.

Поместите файл с исполняемым кодом Parser (в текущей версии, parser3) в каталог для CGI-скриптов.

Под Win32: если вы используете версию Parser с поддержкой XML, в этот же каталог распакуйте XML библиотеки.

Добавьте в файл .htaccess вашего сайта (или в httpd.conf в секцию <virtualhost …> вашего сайта, или вне ее - для всех сайтов) блоки:

# назначение обработчиком .html страниц

AddHandler parser3-handler html

Action parser3-handler /cgi-bin/parser3

# запрет на доступ к .p файлам, в основном, к auto.p

<Files ~ "\.p$">

Order allow,deny

Deny from all

</Files>

Если вас не устраивает расположение конфигурационного файла по умолчанию (см. Установка и настройка Parser), вы можете задать его явно:

# задание переменной окружения с путем к auto.p



SetEnv CGI_PARSER_CONFIG /путь/к/файлу/auto.p

Замечание: для этого необходим модуль mod_env, который по умолчанию установлен.



Об ошибках Parser делает записи в журнал ошибок parser3.log, который, по умолчанию, расположен в том же каталоге, где и CGI-скрипт Parser. Если у Parser нет возможности сделать запись в данный файл, об ошибке будет сообщено в стандартный поток ошибок, и запись об ошибке попадет в журнал ошибок веб-сервера. Если вас не устраивает расположение журнала ошибок parser3.log, вы можете задать его явно:

# задание переменной окружения с путем к parser3.log

SetEnv CGI_PARSER_LOG /путь/к/файлу/parser3.log

Замечание: для этого необходим модуль mod_env, который по умолчанию установлен.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 28.05.2004

Install4apachemodule


Установка Parser на веб-сервер Apache 1.3, модуль сервера


Для установки Parser необходимо внести изменения в основной конфигурационный файл веб-сервера, или, если у вас нет к нему доступа, необходима возможность использовать .htaccess файлы.

По-умолчанию, в установке Apache возможность использования .htaccess отключена.

Если она вам необходима, разрешите их использовать (по крайней мере, задавать FileInfo). Для чего в основном конфигурационном файле веб-сервера (обычно httpd.conf) в секцию вашего <virtualhost …> вашего сайта, или вне ее - для всех сайтов, добавьте директивы:

<Directory /путь/к/вашему/веб/пространству>

AllowOverride FileInfo

</Directory>

Parser3 самостоятельно выполняет необходимые перекодирования, так что для Русского Apache добавьте в основной конфигурационный файл веб-сервера (обычно httpd.conf) строку:

CharsetDisable On

запрещающую использование возможностей перекодирования Русского Apache для вашего сервера.

Если возможности изменить основной конфигурационный файл веб-сервера у вас нет, добавьте эту строку в .htaccess файл.

Под UNIX:

Необходимо собрать Parser из исходных кодов, задав ключ --with-apache13 у скрипта configure, при make на экране появится инструкция по дальнейшей сборке Apache из его исходных кодов.

Внимание: на некоторых системах стандартный make не работает с make-файлами Parser3, воспользуйтесь GNU вариантом: gmake.

Под Win32:

Поместите файлы с исполняемым кодом модуля Parser (в текущей версии, ApacheModuleParser3.dll) в произвольный каталог.

Если вы используете версию Parser с поддержкой XML, в каталог, указанный в переменной окружения PATH (например, C:\WinNT), распакуйте XML библиотеки.

Добавьте в файл httpd.conf после имеющихся строк LoadModule:

# динамическая загрузка модуля

LoadModule parser3_module x:\path\to\ApacheModuleParser3.dll

Внимание: если необходимо, поместите сопутствующие .dll файлы в тот же каталог.

А после имеющихся строк AddModule (если не имеются, не добавляйте):



# добавление модуля к списку активных модулей

AddModule mod_parser3.c

Внимание: до 3.1.1 версии Parser: AddModule mod_parser3.C  (на конце .C большая)



Добавьте в файл .htaccess вашего сайта (или в httpd.conf в секцию <virtualhost …> вашего сайта, или вне ее - для всех сайтов) блоки:

# назначение обработчиком .html страниц

AddHandler parser3-handler html

# задание Конфигурационного файла

ParserConfig x:\path\to\parser3\config\auto.p

# запрет на доступ к .p файлам, в основном, к auto.p

<Files ~ "\.p$">

    Order allow,deny

    Deny from all

</Files>


Install4iis


Установка Parser на веб-сервер IIS 5.0 или новее


Поместите файлы с исполняемым кодом модуля Parser (в текущей версии, parser3isapi.dll) в произвольный каталог.

Если вы используете версию Parser с поддержкой XML, в каталог, указанный в переменной окружения PATH (например, C:\WinNT), распакуйте XML библиотеки.

После чего назначьте Parser обработчиком .html страниц:

1.Запустите Management Console, нажмите на правую кнопку мыши на названии вашего веб-сервера и выберите Properties.  

2.Перейдите на вкладку Home directory и в разделе Application settings нажмите на кнопку Configuration…  

3.В появившемся окне нажмите на кнопку Add.  

4.В поле Executable введите полный путь к файлу parser3.exe или parser3isapi.dll.  

5.В поле Extension введите строку .html.  

6.Включите опцию Check that file exists.  

7.Нажмите на кнопку OK.  




Installcharset


Описание формата файла, описывающего кодировку


Данные в формате tab-delimited со следующими столбцами:

char - символ, или его код, заданный в десятичной или шестнадцатеричной форме

(0xHH) в той кодировке, которую определяет этот файл.

white-space, digit, hex-digit, letter, word - набор флажков, задающих класс этого символа. Пустое содержимое означает непринадлежность символа к этому классу, непустое [например, 'x'] - принадлежность.

Подробнее о символьных классах см. описание регулярных выражений в литературе.

lowercase - если символ имеет пару в нижнем регистре, то символ или код парного символа. Скажем, у буквы 'W' есть парная 'w'. Используется в регулярных выражениях для поиска, нечувствительного к регистру символов, а также в методах lower и upper класса string.

unicode1 - основной Unicode код символа. Если совпадает с кодом символа, то можно не указывать. Скажем, у буквы 'W' он совпадает, а у буквы 'Я' - нет.

unicode2 - дополнительный Unicode символа, если имеется.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 24.02.2004



Intdoubleclasses


Классы int, double


Объектами классов int и double являются целые и вещественные числа, как заданные пользователем, так и полученные в результате вычислений или преобразований. Числа, относящиеся к классу double, имеют представление в формате с плавающей точкой. Диапазон значений зависит от платформы, но, как правило:

для int

от -2147483648

до 2147483647

для double

от 1.7E-308

до 1.7E+308

Класс double обычно имеет 15 значащих цифр и не гарантирует сохранение цифр в последних разрядах. Точное количество значащих цифр зависит от вашей платформы.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 13.01.2004



Intdoublefield


int, double. Преобразование объектов к числам


^имя.int[]

или

^имя.int(default)

^имя.double[]

или

^имя.double(default)



Преобразуют значение переменной $имя к целому или вещественному числу соответственно, и возвращает это число. При преобразовании вещественного числа к целому производится округление.

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

Внимание: пустая строка и строка состоящая только из "white spaces" (символы пробела, табуляция, перевода строки) считается нулем.

Примеры

$str[Штука]

^str.int(1024)


Выведет число 1024, поскольку объект str нельзя преобразовать к классу int.

$double(1.5)

^double.int[]

Выведет число 2, поскольку произведено автоматическое округление.



Intdoubleformat


format. Вывод числа в заданном формате


^имя.format[форматная строка]


Метод выводит значение переменной в заданном формате (см. Форматные строки).

Примеры


$var(15.67678678)

^var.format[%.2f]


Возвратит: 15.68


$var(0x123)

^var.format[0x%04X]


Возвратит: 0x0123



Intdoubleincetc


inc, dec, mul, div, mod. Простые операции над числами


^имя.inc[]

^имя.inc(число)

- увеличивает значение переменной на 1 или число

^имя.dec[]

^имя.dec(число)

- уменьшает значение переменной на 1 или число

^имя.mul(число)

- умножает значение переменной на число

^имя.div(число)

- делит значение переменной на число

^имя.mod(число)

- возвращает остаток от деления значения переменной на число

Пример


$var(5)

^var.inc(7)

^var.dec(3)

^var.div(4)

^var.mul(2)

$var


Пример возвратит 4.5 и эквивалентен записи $var((5+7-3)/4*2).



Intdoublesql


sql. Получение числа из базы данных


^int:sql{запрос}  

^int:sql{запрос}[$.limit(1) $.offset(o) $.default{код}]  

^double:sql{запрос}  

^double:sql{запрос}[$.limit(1) $.offset(o) $.default{код}]   


Возвращает число, полученное в результате SQL-запроса к серверу баз данных. Запрос должен возвращать значение из одного столбца одной строки.

Запрос

- запрос к базе данных, написанный на языке SQL

$.offset(o)

- отбросить первые o записей выборки

$.default{код}

- если результат SQL-запроса не число, то метод возвратит результат выполнения кода

Для работы этого метода необходимо установленное соединение с сервером базы данных (см. оператор connect).

Пример

^connect[строка подключения]{

   ^int:sql{select count(*) from news}

}


Вернет количество записей в таблице news.



Intro


Введение


"И сказал Господь: Я увидел страдания народа Моего в Египте, и услышал вопль его от приставников его; Я знаю скорби его, и иду избавить его от руки египтян и вывести его из земли сей в землю хорошую и пространную, где течет молоко и мед…" (Исход, 3, 7-8)  


Parser?


Самый логичный вопрос, который может возникнуть у вас, уважаемый читатель, это, несомненно: «А что это вообще такое?». Итак, если вы хотите узнать ответ - добро пожаловать! Для начала позвольте сделать несколько предположений.

Первое, очень важное. Вы уже имеете представление о том, что такое HTML. Если данное сочетание букв вам незнакомо, дальнейшее чтение вряд ли будет увлекательным и полезным, поскольку Parser является языком программирования, существенно упрощающим и систематизирующим разработку именно HTML документов.

Второе, существенное. Мы предлагаем вам познакомиться с новой версией Parser на практических примерах, поэтому будем считать, что у вас под руками есть установленный Parser3. Теория, как известно, без практики мертва. Как установить и настроить программу, подробно рассказано в приложении.

Третье, просто третье. У вас есть немного свободного времени, терпения, IQ не ниже 50, а также желание сделать свою работу по разработке HTML документов проще, логичнее и изящнее. Со своей стороны обещаем вам, что время, потраченное на изучение этого языка с лихвой окупится теми преимуществами и возможностями, которые он дает.

Вроде бы не очень много, не так ли? Все остальное - это уже наша забота!

Parser…


Parser появился на свет в 1997 году в Студии Артемия Лебедева (www.design.ru). Целью его создания было облегчить труд тех, кто по сегодняшний день успешно и в кратчайшие сроки создает лучшие сайты рунета, избавить их от рутинной работы и позволить отдавать свое время непосредственно творчеству. Зачем забивать гвозди микроскопом, если его настоящее предназначение совсем не в этом?

Именно по этому большинство интернет-проектов студии делаются на Parser. Он проще в использовании, чем что-либо, созданное для подобных целей.
Но эта простота не означает примитивность. Она позволяет использовать Parser не только опытным программистам, но и тем людям, которые далеки от программирования. Позволяет создавать красивые, полноценные сайты быстро, эффективно и профессионально. Мы хотим дать такую возможность и вам.

Идея Parser довольно проста. В HTML-страницы внедряются специальные конструкции, обрабатываемые нашей программой перед тем, как страницы увидит пользователь. Программа сама доделывает за вас работу по окончательному формированию и оформлению сложного документа. Это похоже на собирание из конструктора, в котором есть готовые модули для всех обычных целей. Если же вы мыслите нестандартно, просто создайте свои модули, которые будут делать то, что необходимо именно вам. Ничего невозможного нет, при этом все делается просто и быстро.

Вы сами в этом убедитесь, как только начнете работать с Parser.

Parser!



Подведем итоги. Что дает вам Parser? Вы получаете в свое распоряжение переменные, циклы, условия и т.д., все то, чего так не хватает привычному HTML. Без использования Parser аналогичный по внешнему виду документ будет гораздо больше по объему, а некоторые задачи останутся неразрешенными. С Parser у вас пропадет необходимость повторять одни и те же инструкции по несколько раз, но появится возможность формирования динамических страниц в зависимости от действий пользователя, работать с базами данных и XML, внешними HTTP-серверами, в считанные минуты менять дизайн страниц. И все это без обычного в подобных случаях сложного программирования.

Ваши страницы будут формироваться из отдельных законченных объектов, а вы просто скажете Parser какие из них, сколько, куда и в какой последовательности поставить. Если нужно что-то поменять местами или добавить, вы просто указываете это - и все. Остальное будет сделано автоматически. При этом сам проект станет логичным и понятным за счет структуризации.

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

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

Впрочем, перечислять преимущества можно долго, но может быть, мы и так убедили вас попробовать? Разве наш опыт не является доказательством правоты? К тому же, мы не просим за использование Parser денег, мы просто хотим, чтобы рунет стал лучшим! И у нас есть для этого готовое, проверенное решение - Parser. Вы полюбите его так же, как и мы.

Приступаем? Вперед!


Junctionclass


Класс junction


Класс предназначен для хранения кода и контекста его выполнения.

При обращении к переменным, хранящим в себе junction, Parser выполняет код в сохраненном контексте.

Значение типа junction появляется в переменной…

…при присваивании ей кода:

$junction{Код, присваиваемый переменной: ^do_something[]}


…при передачи кода параметром:

@somewhere[]

^method{Код, передаваемый параметром: ^do_something_else[]}


@method[parameter]

#здесь в $parameter придет junction


…при обращении к имени метода класса:

$action[$user:edit]

#$action[$user:delete]

^action[параметр]


Здесь $action хранит ссылку на метод и его класс, вызов action теперь аналогичен вызову ^edit[параметр].

…при обращении к имени метода объекта:

$action[$person.show_info]

^action[full]


Здесь $action хранит ссылку на метод и его объект, вызов action теперь аналогичен вызову ^person.show_info[параметры].

Пример junction выражений и кода

@possible_reminder[age;have_passport]

^myif($age>=16 && !$have_passport){

    Тебе уже $age лет, пора сходить в милицию.

}

@myif[condition;action][age]

$age(11)

^if($condition){

    $action

}


Напоминание: параметр с выражением, это код, вычисляющий выражение, он выполняется - вычисляется выражение - при каждом обращении к параметру внутри вызова.

Здесь оператору myif передан код, печатающий, среди прочего, $age. Выполнение проверки и кода оператор производит в сохраненном (внутри $condition и $action) контексте, поэтому наличие в myif локальной переменной age и ее значение никак не влияет на то, что будет проверено и что напечатано.

Пример проверки наличия метода

^if($some_method is junction){

    ^some_method[параметр]

}{

    нет метода

}


Метод some_method, будет вызван только, если определен.



с самого начала. Итак, вы


Урок 1. Меню навигации



Давайте начнем с самого начала. Итак, вы хотите сделать сайт (узел, сервер). Первым делом, необходимо уяснить, каким образом на сайте будет упорядочена та или иная информация. Сколько будет категорий, подразделов т.д. Все эти вопросы возникают на первом этапе - "Организация сайта".

А какой должна быть навигация сайта? Требований к хорошей навигации много. Она должна быть понятна, легко узнаваема, единообразна, удобна в использовании, быстро загружаться, давать четкое понятие о текущем местоположении. При этом на сайте не должно возникать 404-й ошибки, т.е. все ссылки должны работать. Если у вас есть опыт создания сайтов, то вам, скорее всего, приходилось сталкиваться с проблемой создания грамотной навигации.

Не правда ли, хочется иметь какое-то решение, которое всегда будет под рукой и позволит автоматизировать весь этот процесс? Что-то такое, что даст возможность единственный раз написать код и потом, в одном месте, дописывать столько разделов, сколько нужно?

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

<a href="страница_сайта.html">



трудно контролировать. А если вам понадобится добавить еще один раздел? Придется в каждую страницу вносить изменения, а человеку свойственно делать ошибки. При этом отнюдь не исключено, что после такой «модернизации» ваш ресурс в ответ на запросы пользователей сообщит о том что «данная страница не найдена». Вот где проблема, которую с помощью Parser можно решить очень легко.

Решение следующее. Мы создаем некую функцию на Parser, которая будет генерировать нужный нам фрагмент HTML-кода. В терминологии Parser функции называются методами. В тех местах, где этот код понадобится, будем просто давать указание «Вставить меню навигации» и сразу же будет создана страница, содержащая меню. Для этого сделаем несколько простых шагов:



1. Всю информацию о наших ссылках будем хранить в одном файле, что позволит впоследствии вносить необходимые изменения только в нем. В корневом каталоге будущего сайта создаем файл sections.cfg, в который помещаем следующую информацию:



section_id



name



uri



1



Главная



/



2



Новости



/news/



3



Контакты



/contacts/



4



Цены



/price/



5



Ваше мнение



/gbook/

      

Здесь используется так называемый формат tab-delimited. Столбцы разделяются знаком табуляции, а строки - переводом каретки. При копировании этой таблицы в текстовый редактор данное форматирование будет создано автоматически, но если вы будете создавать таблицу вручную, необходимо это учитывать. Для таблиц ВСЕГДА применяется формат tab-delimited.

2. В том же каталоге, где и sections.cfg, создаем файл auto.p

В нем мы будем хранить все те кирпичики, из которых впоследствии Parser соберет наш сайт. AUTO означает, что все эти кирпичики будут всегда доступны для Parser в нужный момент, а расширение ".p", как вы, наверное, догадались, это… правильно! Он самый!

3. В файл auto.p вставим следующий код:

@navigation[]

$sections[^table::load[sections.cfg]]

<table width="100%" border="1">

   <tr>

   ^sections.menu{

      <td align="middle">

          <a href="$sections.uri"><nobr>$sections.name</nobr></a>

      </td>

   }

   </tr>

</table>



Данные из этого файла и будут служить основой для нашего навигационного меню.

Вот и все, подготовительные работы закончены. Теперь открываем код страницы, где все это должно появиться (например, index.html), и говорим: «Вставить меню навигации». На Parser это называется «вызов метода» и пишется так:

^navigation[]





Осталось только открыть в браузере файл, в который мы вставили вызов метода и посмотреть на готовое меню навигации. Теперь в любом месте на любой странице мы можем написать заветное ^navigation[], и Parser вставит туда наше меню. Страница будет сформирована «на лету». Что хотели, то и получили.

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

Однако не будем радоваться раньше времени. Давайте разберемся, что же мы сделали, чтобы добиться такого результата. Взгляните на код в auto.p. Если кажется, что все непонятно, не надо бежать прочь. Уверяем, через несколько минут все встанет на свои места. Итак, посмотрим на первую строчку:

@navigation[]



Она аналогична строке ^navigation[], которую мы вставили в текст страницы для создания меню. Различие только в первом символе: ^ и @. Однако логический смысл этого выражения совершенно иной - здесь мы определяем метод, который вызовем позже. Символ @ (собака) в первой колонке строки в Parser означает, что мы хотим описать некоторый блок, которым воспользуемся в дальнейшем. Следующее слово определяет имя нашего метода: navigation. Это только наше решение, как ее назвать. Вполне допустимы имена: а_ну_ка_вставь_меню_быстро. Но читаться такая программа будет хуже, впрочем, кому как понятнее, можете назвать и так.

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

Идем дальше.

$sections[^table::load[sections.cfg]]



Это ключевая строка нашего кода. Она достаточно большая, поэтому давайте разберем ее по частям.

Строка начинается символом $ (рубль) и следующим сразу за ним именем sections.


Так в Parser обозначаются переменные. Это надо запомнить. Все просто: видим в тексте $var - имеем дело с переменной var. Переменная может содержать любые данные: числа, строки, таблицы, файлы, рисунки и даже часть кода. Присвоение переменной $parser_home_url значения www.parser3.ru на Parser выглядит так: $parser_home_url[www.parser3.ru]. После этого мы можем обратиться к переменной по имени, т.е. написать $parser_home_url и получить значение www.parser3.ru.

Еще раз тоже самое:



$var[…]



- присваиваем



$var



- получаем

Подробности в разделе «Переменные».

В нашем случае переменная $sections будет хранить таблицу из файла sections.cfg.

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

Лирическое отступление.

Пример из жизни. Всю автомобильную технику можно грубо разделить на несколько классов: легковые автомашины, грузовики, трактора и гусеничная техника. Любой автомобиль является объектом одного из этих классов. Вы легко можете определить, к какому классу относится автомобиль, поскольку их всех объединяют общие характеристики, такие как вес, масса перевозимого груза и т.д. Любой автомобиль может совершать действия: двигаться, стоять или ломаться. Каждый из автомобилей обладает своими собственными свойствами. И самое главное, автомобиль не может появиться сам собой, его нужно создать. Когда конструктор придумывает новую модель автомобиля, он точно знает, автомобиль какого класса он создает, какими свойствами будет наделено его творение и что оно сможет делать. Также и в Parser: каждый объект относится к определенному классу, объект класса создается конструктором этого класса и наделен характеристиками (полями) и методами (действиями), общими для всех подобных объектов.

Итог

Любой объект в Parser принадлежит конкретному классу, характеризуется полями и методами именно этого класса.


Чтобы он появился, его нужно создать. Делает это конструктор данного класса. Разберитесь с этой терминологией, это основа.

Отвлеклись? Продолжим. Переменной $sections мы присвоили вот что:

^table::load[sections.cfg]



Буквально это означает следующее: мы создали объект класса table при помощи конструктора load. Общее правило для создания объекта записывается так:



^имя_класса::конструктор[параметры_конструктора]



Подробности в разделе «Передача параметров».

В качестве параметра конструктору мы передали имя файла с таблицей и путь к нему.

Теперь переменная $sections содержит таблицу с разделами нашего сайта. Parser считает ее объектом класса table и точно знает, какие действия с ней можно выполнить. Пока нам понадобится только один метод этого класса - menu, который последовательно перебирает все строки таблицы. Также нам потребуются значения из полей самой таблицы. Синтаксис вызова методов объекта:

^объект.метод_класса[параметры]

Получение значений полей объекта (мы ведь имеем дело с вполне определенной таблицей с заданными нами же полями):

$объект.имя_поля



Знания, полученные выше, теперь позволяют без труда разобраться в последней части нашего кода:

<table width="100%" border="1">

   <tr>

   ^sections.menu{

      <td align="middle">

         <a href="$sections.uri"><nobr>$sections.name</nobr></a>

      </td>

   }

   </tr>

</table>

Мы формируем HTML-таблицу, в каждый столбец которой помещаем значения, содержащиеся в полях нашей таблицы $sections: uri - адрес и name - имя. При помощи метода menu мы автоматически перебираем все строки таблицы. Таким образом, даже если у нас будет несколько десятков разделов, ни один из них не будет потерян или пропущен.


Мы можем свободно добавлять разделы, удалять их и даже менять местами. Изменения вносятся только в файл sections.cfg. Логика работы не нарушится. Все просто и красиво.

Давайте подведем итоги первого урока.

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

Что узнали: познакомились c концептуальными понятиями языка (класс, объект, свойство, метод), а также некоторыми базовыми конструкциями Parser.

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

Синтаксис работы с объектами:



$переменная[значение]



- задаем значение



$переменная



- получаем значение



$переменная

[^имя_класса::конструктор[параметры]] 



- создаем объекта класса имя_класса и присваиваем его переменной



$переменная.имя_поля



- получаем поле самого объекта, хранящегося в переменной



^переменная.метод[]



- вызываем действие (метод класса, к которому принадлежит объект, хранящийся в переменной)

Что будем делать дальше: заниматься модернизацией меню. Ведь пока оно не отвечает многим требованиям: ставит лишнюю ссылку на текущий раздел, выдает столбцы разной ширины. На втором уроке мы исправим все эти недостатки и сделаем еще кое-что.


Предыдущий урок мы закончили тем,


Урок 2. Меню навигации и структура страниц



Предыдущий урок мы закончили тем, что определили недостатки в реализации меню. Давайте займемся их устранением. Наше меню выводит лишнюю ссылку на текущую страницу, что нисколько не украшает будущий сайт. Чтобы этого избежать, необходимо проверить, не является ли раздел, на который мы выводим ссылку, текущим. Иными словами, нам нужно сравнить URI раздела, на который собираемся ставить ссылку, с текущим URI. В случае если они совпадают, ссылку на раздел ставить не надо. Дополнительно для удобства пользователей мы изменим в меню навигации цвет столбца текущего раздела.

Открываем файл auto.p и меняем его содержимое на:

@navigation[]

$sections[^table::load[/sections.cfg]]

<table width="100%" border="0" bgcolor="#000000" cellspacing="1">

   <tr  bgcolor="#FFFFFF">

   ^sections.menu{

      ^navigation_cell[]

   }

   </tr>

</table>

<br>

@navigation_cell[]

$cell_width[^eval(100\$sections)%]

^if($sections.uri eq $request:uri){

   <td width="$cell_width" align="middle" bgcolor="#A2D0F2"> 

   <nobr>$sections.name</nobr>

   </td>

}{

   <td width="$cell_width" align="middle"> 

   <a href="$sections.uri"><nobr>$sections.name</nobr></a>

   </td>

}



Что изменилось? На первый взгляд не так уж и много, но функциональность нашего модуля существенно возросла. Мы описали еще один метод - navigation_cell, который вызывается из метода navigation. В нем появилась новая структура:

^if(условие){код если условие "истина"}{код если условие "ложь"}



Что она делает, понять не сложно. В круглых скобках задается условие, в зависимости от того, какое значение возвращает условие, "ложь" или "истина", можно получить разный результат. Также, если в условии записано выражение, значение которого равно нулю, то результат - "ложь", иначе - "истина". Мы используем оператор if для того, чтобы в одном случае поставить ссылку на раздел, а другом нет. Осталось только разобраться с условием. Будем сравнивать на равенство две текстовых строки, в одной из которых - значение URI раздела из таблицы sections, в другой - текущий URI ($request:uri возвращает строку, содержащую URI текущей страницы). Тут возникает вопрос о том, какие же строки равны между собой? Несомненно, только те, которые полностью совпадают и по длине, и по символьному содержанию.

Для сравнения двух строк в Parser предусмотрены следующие операторы:

eq - строки равны (equal): parser eq parser

ne - строки не равны (not equal): parser ne parser3

lt - первая строка меньше второй (less than): parser lt parser3

gt - первая строка больше второй (greater than): parser3 gt parser 

le - первая строка меньше или равна второй (less or equal)

ge - первая строка больше или равна второй (greater or equal)

С условием разобрались: если $sections.uri и $request:uri совпадают, ссылку не ставим (а заодно красим столбец в другой цвет - подумаем о наших пользователях, так им будет удобнее), если нет - ставим.

Идем дальше. Меню из первого урока выводило столбцы разной ширины. Ничего страшного, но некрасиво. Проблема решается очень просто: всю ширину меню (100%) делим на количество разделов, которое равно количеству строк в таблице sections. Для этого воспользуемся оператором ^eval() и тем, что можно использовать объекты класса table в математических выражениях. При этом их числовое значение равно числу записей в таблице. Обратите внимание также на то, что мы пользуемся целочисленным делением, используя обратный слеш вместо прямого.



На ^eval() остановимся чуть подробнее. Он позволяет получить результат математического выражения без введения дополнительных переменных, иными словами, хотим что-то посчитать - пишем:

^eval(выражение)[формат]



Использование [формат] дает возможность вывода результата выражения в том виде, который нужен. Форматная строка [%d] отбрасывает дробную часть, [%.2f] дает два знака после запятой, а [%04d] отводит 4 знака под целую часть, дополняя недостающие символы нулями слева. Форматированный вывод нужен, когда необходимо представить число в определенном виде (скажем, 12.44 $ смотрится куда лучше 12.44373434501 $).

Вот, собственно, и все, что касается меню. Теперь оно функционально и готово к использованию.

Наш первый кирпичик для будущего сайта готов. Теперь займемся структурой страниц. Давайте разобьем их на следующие блоки: header - верхняя часть страницы, body - основной информационный блок, включающий также наше меню и footer - нижняя часть страницы. Многие сайты имеют похожую структуру.

Footer будет для всех страниц одинаковым, header - для всех страниц одинаковый по стилю, но с разными текстовыми строками - заголовками страницы, а body будет разный у всех страниц, сохраняя только общую структуру (предположим, два вертикальных информационных блока, соотносящихся по ширине как 3:7). К body отнесем и наше меню.

Каждая из страниц будет иметь следующую структуру:



header



navigation

body_additional

(30%)




body_main

(70%)



footer

Также, как в случае с меню, опишем каждый из этих блоков методом (функцией) на Parser. Давайте подробно разберемся с каждым блоком.

С footer все очень просто - в auto.p добавляем код:

@footer[]

<table width="100%" border="0" bgcolor="#000000" cellspacing="0">

   <tr>

      <td></td>

   </tr>

</table>

$now[^date::now[]]

<font size="-3">

<center>Powered by Parser3<br>1997-$now.year</center>



</font>

</body>

</html>



Никаких новых идей здесь нет, разве что мы впервые использовали класс date с конструктором now для получения текущей даты, а затем из объекта класса date взяли поле year (год). Если это кажется вам непонятным, обязательно вернитесь к первому уроку, где рассказано о работе с объектами на примере класса table. Все идентично, только теперь мы имеем дело с объектом другого класса.

Немного сложнее с модулем header. С одной стороны, нам нужно формировать уникальный заголовок-приветствие для каждой страницы. В то же время он будет одинаковым с точки зрения внешнего вида, различие только в тексте, который будет выводиться. Как же быть? Мы предлагаем сделать следующее: определить в нашем auto.p новую функцию header, внутри которой будет вызываться другая функция - greeting. А функция greeting, в свою очередь, будет определяться на самих страницах сайта и содержать только то, чем отличаются заголовки страниц (в нашем случае строку-приветствие).

Дополняем auto.p следующим кодом:

@header[]

<html>

<head>

<title>Тестовый сайт Parser3</title>

</head>

<body bgcolor="#FAEBD7">

<table width="100%" border="0" bgcolor="#000000" cellspacing="1">

   <tr  bgcolor="#FFFFFF" height="60">

      <td align="middle">

         <font size="+2"> <b>^greeting[]</b></font>

      </td>

   </tr>

</table>

<br>



Теперь внимание, кульминация. Parser позволяет сделать очень интересный финт: определить один раз общую структуру страниц в файле auto.p, создать каркас, а затем, используя функции, подобные greeting, в тексте самих страниц, получать разные по содержанию страницы одинаковой структуры.


Как это работает?

В самом начале файла auto.p мы определим функцию @main[], которая всегда, причем автоматически, исполняется первой. В нее включим вызовы функций, формирующих части страниц.

В начале auto.p пишем:

@main[]

^header[]

^body[]

^footer[]



А для получения уникального заголовка страниц в каждой из них определим функцию greeting, которая вызывается из header:

для главной страницы:

@greeting[]

Добро пожаловать!



для гостевой книги:

@greeting[]

Оставьте свой след…



и т.д.

Теперь при загрузке, например, главной страницы произойдет следующее:

1. Из файла auto.p автоматически начнет выполняться main.

2. Первой вызывается функция header, из которой вызывается функция greeting.

3. Поскольку функция greeting определена в коде самой страницы, будет выполнена именно она, вне зависимости от того, определяется она в auto.p или нет (происходит переопределение функции).

4. Затем выполняются функции body и footer из main.

В результате мы получаем страницу, у которой будут все необходимые элементы, а в верхней части дополнительно появится наше уникальное приветствие. Переопределяемые функции носят название виртуальных. Мы из файла auto.p вызываем функцию, которая может быть переопределена на любой из страниц и для каждой из них выполнит свой код. При этом общая структура страниц будет абсолютно одинаковой, и сохранится стилистическое и логическое единство.

Осталось описать только основной блок - body. Как мы договорились, он будет состоять из двух частей, каждую из которых будем создавать своей функцией, например, body_main и body_additional, а поскольку навигационное меню, по логике, относится к основной части страниц, вызовем navigation также из body. Снова воспользуемся механизмом виртуальных функций. Редактируем auto.p - дополняем:

@body[]

^navigation[]

<table width="100%" height="65%" border="0" bgcolor="#000000" cellspacing="1">

   <tr  bgcolor="#ffffff" height="100%">



      <td width="30%" valign="top" bgcolor="#EFEFEF">

         <b>^body_additional[]</b>

      </td>

      <td width="70%" valign="top">

         ^body_main[]

      </td>

   </tr>

</table>

<br>



Определение функций body_main и body_additional, также как и в случае с greeting вставим в страницы:

@body_additional[]

Главная страница сайта



@body_main[]

Основное содержание



Этот текст приводится как образец для index.html. Отлично! Структура окончательно сформирована. Мы описали все необходимые модули в файле auto.p, сформировали общую структуру и теперь можем запросто генерировать страницы. Больше не нужно помногу писать одни и те же куски HTML кода. Привычные HTML-страницы трансформируются примерно в следующее (примерное содержание index.html файла для главной страницы):



@greeting[]

Добро пожаловать!



@body_additional[]

Главная страница сайта



@body_main[]

Основное содержание



Просто и понятно, не правда ли? Все разложено по полочкам и легко доступно. При этом после обработки подобного кода Parser создаст HTML-код страницы, у которой будет уникальный заголовок, меню, основной информационный блок заданной структуры и footer, одинаковый для каждой страницы. Фактически, мы уже создали готовый сайт, который осталось только наполнить информацией. Это готовое решение для изящного сайта-визитки, который можно создать прямо на глазах. Естественно, это не единственное решение, но такой подход дает отличную структуризацию нашего сайта. Некоторые умственные усилия при разработке структуры с лихвой окупятся легкостью последующей поддержки и модернизации. Каркас хранится в auto.p, а все, что относится непосредственно к странице, - в ней самой.



Дальше открываются безграничные просторы для фантазии. Допустим, вам понадобилось поменять внешний вид заголовка страниц на сайте. Мы открываем auto.p, редактируем один единственный раз функцию @header[] и на каждой из страниц получаем новый заголовок, по стилю идентичный всем остальным. Для обычного HTML нам пришлось бы вручную переписывать код для каждой страницы. Та же самая ситуация и с остальными модулями. Если возникло желание или необходимость изменить общую структуру страниц, например, добавить какой-то блок, достаточно определить его новой функцией и дополнить функцию main в auto.p ее вызовом.

Подобная организация страниц сайта дополняет проект еще одним мощным средством. Предположим, на одной из страниц нам понадобилось получить footer, отличный от других страниц (напомним, изначально мы предполагали, что footer везде одинаковый). Единственное, что нужно сделать, это переопределить функцию footer на нужной странице. Например, такое наполнение /contacts/index.html:



@greeting[]

Наша контактная информация



@body_additional[]

Главная страница тестового сайта



@body_main[]

Основное содержание



@footer[]

Здесь у нас контакты



изменит привычный footer на обозначенный выше, т.е. если Parser находит в тексте страницы код для функции, вызываемой из auto.p, он выполнит именно его, даже если функция определена в самом auto.p. Если же функция не переопределена на странице, то будет использован код из auto.p.

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

Помните, мы использовали в нашем коде конструкцию $request:uri? Она отличается по синтаксису от всего того, с чем мы имели дело раньше. Что же это такое? Внешне похоже на $объект.свойство (урок 1) - значение полей объекта, только вместо точки использовано двоеточие. На самом деле, это тоже значение поля, только не объекта, а самого класса request. В Parser не предусматриваются конструкторы для создания объектов этого класса.


Поля подобных классов формируются самим Parser, а мы можем сразу напрямую обращаться к ним. Техническим языком это называется статическая переменная (поле) uri класса request. Она хранит в себе URI текущей страницы. Также, наряду со статическими переменными, существуют статические методы, с которыми мы столкнемся уже в следующем уроке. При этом можно сразу же вызывать их также без создания каких-либо объектов с помощью конструкторов. Запомните, что в синтаксисе статических полей и методов всегда присутствует двоеточие. Если встречается конструкция вида $класс:поле - мы получаем значение поля самого класса, а запись ^класс:метод является вызовом статического метода класса. Например, для работы с математическими функциями в Parser существует класс math. В нем используются только статические методы и переменные:

$math:PI -  возвращает число p. Это статическая переменная класса math.

^math:random(100) - возвращает псевдослучайное число из диапазона от 0 до 100. Это статический метод класса math.

Отличие от записи методов и полей объектов состоит только в двоеточии.

Давайте подведем итоги второго урока.

Что мы сделали: исправили недостатки в меню навигации, созданном на предыдущем уроке, а также описали новые блоки header, footer и body, формирующие внешний вид страниц нашего сайта. Теперь мы имеем готовое решение для быстрого создания сайта начального уровня.

Что узнали: познакомились с ветвлением кода, научились вставлять в текст страниц результаты математических вычислений, сравнивать строки и получать URI текущей страницы. Также мы узнали новые методы объектов класса table и класса date и познакомились с мощным механизмом виртуальных функций Parser.

Что надо запомнить: первым методом в файле auto.p можно определить функцию main, которая выполняется автоматически. Любая из функций может содержать вызовы других функций. Все вызываемые из main функции обязательно должны быть определены или в auto.p, или в тексте страниц. В случае если функция будет определена и там и там, то больший приоритет имеет функция, определенная в тексте страницы.Она переопределяет одноименную функцию из main (т.н. виртуальная функция) и выполняется вместо нее.

Что будем делать дальше: нет предела совершенству! От создания сайта начального уровня мы переходим к более сложным вещам, таким как работа с формами и базами данных для создания по-настоящему интерактивного сайта. Параллельно с этим познакомимся с новыми возможностями, предоставляемыми Parser для облегчения жизни создателям сайтов.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 05.03.2004

На двух предыдущих уроках мы


Урок 3. Первый шаг - раздел новостей



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

Создать календарь средствами одного HTML - задача достаточно нетривиальная, к тому же код получится очень громоздким. Сейчас Вы увидите, как легко это сделать на Parser. Приступаем.

Все файлы, относящиеся к разделу новостей, будем размещать в разделе /news/, что было указано нами в файле sections.cfg. Для начала создадим там (!) файл auto.p. Удивлены? Да, файлы auto.p можно создавать в любом каталоге сайта. Однако при этом надо иметь в виду, что функции, описанные в auto.p разделов, будут явно доступны только внутри этих разделов. Согласитесь, ни к чему загромождать корневой auto.p функциями, которые нужны для одного раздела. Логичнее вынести их в отдельный файл, относящийся именно к этому разделу.

Еще одно замечание: если в auto.p раздела переопределить функцию, ранее описанную в корневом auto.p, то будет исполняться именно эта, переопределенная функция. Сработает механизм виртуальных функций, описанный в предыдущем уроке.

Итак, в auto.p раздела news пишем такой код:

@calendar[]

$calendar_locale[

   $.month_names[

         $.1[Январь]

         $.2[Февраль]

         $.3[Март]

         $.4[Апрель]

         $.5[Май]

         $.6[Июнь]

         $.7[Июль]



         $.8[Август]

         $.9[Сентябрь]

         $.10[Октябрь]

         $.11[Ноябрь]

         $.12[Декабрь]

   ]

   $.day_names[

         $.0[пн]

         $.1[вт]

         $.2[ср]

         $.3[чт]

         $.4[пт]

         $.5[сб]

         $.6[вс]

   ]

   $.day_colors[

         $.0[#000000]

         $.1[#000000]

         $.2[#000000]

         $.3[#000000]

         $.4[#000000]

         $.5[#800000]

         $.6[#800000]

   ]

]

$now[^date::now[]]

$days[^date:calendar[rus]($now.year;$now.month)]

<center>

<table bgcolor="#000000" cellspacing="1">

   <tr>

      <td bgcolor="#FFFFFF" colspan="7" align="middle">

         <b>$calendar_locale.month_names.[$now.month]</b>

      </td>

   </tr>

   <tr>

      ^for[week_day](0;6){



         <td width="14%" align="middle" bgcolor="#A2D0F2">

            <font color="$calendar_locale.day_colors.$week_day">

               $calendar_locale.day_names.$week_day

            </font>

         </td>

      }

   </tr>

^days.menu{

   <tr>

      ^for[week_day](0;6){

         ^if($days.$week_day){

            ^if($days.$week_day==$now.day){

            <td align="middle" bgcolor="#FFFF00">

               <font color="$calendar_locale.day_colors.$week_day">

               <b>$days.$week_day</b>

               </font>

            </td>

            }{         

            <td align="middle" bgcolor="#FFFFFF">

               <font color="$calendar_locale.day_colors.$week_day">



               $days.$week_day

               </font>

            </td>

            }

         }{

            <td bgcolor="#DFDFDF">&nbsp</td>   

         }

      }

   </tr>

}

</table>

</center>



Мы определили функцию calendar, которая создает HTML- код календаря. Получился довольно громоздкий код, но ведь и задачи, которые мы ставим перед собой, тоже усложнились. Не волнуйтесь, сейчас во всем разберемся.

Самая объемная часть кода, начинающаяся с определения $calendar_locale, оказалась незнакомой. Посмотрите на эту структуру. Похоже, в ней мы определяем какие-то данные для календаря, напоминающие таблицу. То, что определено как $calendar_locale, в терминологии Parser называется «хеш», или ассоциативный массив. Зачем он нужен можно сказать, просто бегло просмотрев код примера: здесь мы сопоставляем русское написание месяца его номеру в году (3 - март), название дня недели его номеру, а также связываем шестнадцатиричное значение цвета с некоторым числом. Теперь идея хешей должна проясниться: они нужны для сопоставления (ассоциативной связи) имени с объектом. В нашем случае мы ассоциируем порядковые номера месяцев и дней с их названиями (строками). Parser использует объектную модель, поэтому строка тоже является объектом. Нам несложно получить порядковый номер текущего месяца, но намного нагляднее будет вывести в календаре «Ноябрь» вместо «11» или «пн» вместо «1». Для этого мы и создаем ассоциативный массив.

В общем виде порядок объявления переменных-хешей такой:





$имя[

   $.ключ[значение]

]



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

После определения хеша мы видим уже знакомую переменную now (текущая дата), а вот дальше идет незнакомая конструкция:

$days[^date:calendar[rus]($date.year;$date.month)]



По логике работы она напоминает конструктор, поскольку в переменную days помещается таблица с календарем на текущий месяц текущего года. Тем не менее, привычного :: здесь не наблюдается. Это один из статических методов класса date. Статические методы наряду с уже знакомыми конструкторами могут возвращать объекты, поэтому в данном случае необходимо присвоить созданный объект переменной. Про статические переменные и методы уже было немного сказано в конце предыдущего урока. Своим появлением они обязаны тому факту, что некоторые объекты или их свойства (поля) существуют в единственном экземпляре, как, например, календарь на заданный месяц или URI страницы. Поэтому подобные объекты и поля выделены в отдельную группу, и к ним можно обращаться напрямую, без использования конструкторов. В случае если мы обращаемся к статическому полю, мы получаем значение поля самого класса. В качестве примера можно привести класс math, предназначенный для работы с математическими функциями. Поскольку существует только одно число p, то для того, чтобы получить его значение, используется статическое поле $math:PI - это значение поля самого класса math.

В результате исполнения этого кода в переменной days будет содержаться такая таблица:

Таб.1 (для ноября 2001 года)



0



1



2



3



4



5



6



 









01



02



03



04



05



06



07



08



09



10



11



12



13



14



15



16



17



18



19



20



21



22



23



24



25



26



27



28



29



30





Это таблица, содержащая порядковый номер дней недели и календарь на 11.2001.

С ней мы и будем дальше работать.


Нельзя сразу же выводить содержимое переменной $days, просто обратившись к ней по имени. Если мы обратимся к таблице просто как к переменной, будет непонятно, что мы хотим получить - строку, всю таблицу целиком или значение только из одного столбца. Также явно требуется доработка содержимого полученной таблицы. Но ведь не зря же мы создавали наш хеш с названиями дней недели и месяцев. Поэтому далее по коду средствами HTML создается таблица, в первой строке которой мы выводим название текущего месяца, пользуясь данными из хеша, связанными с номером месяца в году:

$calendar_locale.month_names.[$now.month]



Что здесь что? Мы выводим значение поля month_names хеша calendar_locale с порядковым номером текущего месяца, полученным как $now.month. Результатом выполнения этой конструкции будет название месяца на русском (или любом другом) языке, которое было определено в хеше.

В следующей строке календаря выведем названия дней недели, пользуясь данными хеша. Давайте чуть подробнее определимся с задачей. Нам надо последовательно перебрать номера дней недели (от 0 до 6) и поставить в соответствие номеру дня его название из поля day_names хеша calendar_locale. Для этой цели удобнее всего воспользоваться циклом: последовательностью действий, выполняющейся заданное количество раз. В данном случае мы используем цикл for. Его синтаксис такой:

^for[счетчик](диапазон значений, например 0;6){последовательность действий}



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

^for[week_day](0;6){

   <td width="14%" align="middle" bgcolor="#A2D0F2">

      <font color="$calendar_locale.day_colors.$week_day">

         $calendar_locale.day_names.$week_day

      </font>

   </td>



}



Все просто и понятно, если знать, что такое цикл: последовательно меняя значение week_day от 0 до 6 (здесь week_day является счетчиком цикла), мы получаем семь значений:

$calendar_locale.day_colors.$week_day   - для цвета шрифта

$calendar_locale.day_names.$week_day   - для названия дня недели.

Идея получения данных та же, что и для получения названия месяца, только используются другие ключи хеша.

Возможно, возник вопрос: зачем в хеше ключ day_colors? Ответ прост - все должно быть красиво! Если есть возможность максимально приблизить наш календарь к реальному, то так и сделаем - перекрасим выходные дни в красный цвет.

Далее по тексту следует большой красивый блок. Чтобы в нем разобраться, определимся с задачами. Итак, нам нужно:

1. Последовательно перебрать строки таблицы days (Таб.1).

2. В каждой строке таблицы days последовательно перебрать и вывести значения столбцов (числа месяца).

3. Корректно вывести пустые столбцы (то есть проверить первую и последнюю недели месяца на полноту).

4. Как-то выделить текущее число, например другим цветом и жирным шрифтом.

   

Приступаем. Первый пункт решается с помощью знакомого метода menu класса table:

^days.menu{…}



Перебор столбцов логичнее всего сделать циклом for, с которым мы только что познакомились:

^for[week_day](0;6){…}



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

^if($days.$week_day){

   …

}{

   <td bgcolor="#DFDFDF">&nbsp</td>

}



Обратите внимание, что в условии if мы ни с чем не сравниваем $days.$week_day. Так осуществляется проверка на неравенство нулю.

Parser это условие понимает так:

«Если существует $days.$week_day, то {…}, если нет, то вывести пустую ячейку таблицы серого цвета»

Основная часть работы выполнена. Осталось только выделить текущее число.


Решается это использованием еще одного if, где условием задается сравнение текущего значения таблицы days с текущим числом ($days.$week_day==$now.day):

^if($days.$week_day==$now.day){

   <td align="middle" bgcolor="#FFFF00">

      <font color="$calendar_locale.day_colors.$week_day">

         <b>$days.$week_day</b>

      </font>

   </td>

}{         

   <td align="middle" bgcolor="#FFFFFF">

      <font color="$calendar_locale.day_colors.$week_day">

      $days.$week_day

      </font>

   </td>

}



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

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

#перебираем строки таблицы с календарем

^days.menu{

#перебираем столбцы таблицы с календарем   

   ^for[week_day](0;6){

      ^if($days.week_day){

         ^if($month.$week_day==$date.day){

            число на другом фоне жирным шрифтом

         }{

            число

         }

      }{

         пустой серый столбец

      }



   }

}



Эту конструкцию простой не назовешь. Здесь используются вложенные друг в друга конструкции. Однако она позволяет понять возможность комбинирования различных средств Parser для решения конкретной задачи. Есть более элегантное решение - вынести проверку текущей даты и ее раскрашивание нужным цветом в отдельную функцию, которую и вызывать внутри цикла. Похожее решение мы использовали во втором уроке. Это позволит разгрузить блок и сделать его более читабельным. Но поскольку в данном примере мы хотели показать вам возможность комбинирования нескольких логических структур, то оставляем эту возможность вам в качестве задания.

Если хотите убедиться в работоспособности этого модуля, создайте в разделе /news/ файл test.html и в нем наберите одну единственную строчку ^calendar[]. Теперь откройте этот файл из браузера и полюбуйтесь результатом своих трудов.

Подведем итоги третьего урока.

Что мы сделали: описали функцию, формирующую календарь на текущий месяц.

Что узнали:

·файл auto.p может содержаться не только в корневом каталоге сайта, но и в любом другом, при этом функции, в нем определенные, явно доступны только внутри этого каталога  

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

·статический метод calendar создает таблицу с календарем на текущий месяц  

·цикл for позволяет последовательно выполнить определенные действия заданное количество раз  

Что надо запомнить:

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

·в циклах for можно обращаться к счетчику как к переменной по имени и получать его текущее значение  

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


В Parser комментариями считается любая строка, начинающаяся со знака #. До сих пор мы не пользовались этим, но в дальнейшем нам пригодится комментирование кода. Следующая строка - пример комментария:

# весь этот текст Parser проигнорирует - это комментарий !!!!



Обязательно комментируйте свой код! В идеале он должен быть самодокументирующимся, а человек, читающий его, должен сразу же понимать о чем идет речь, что из чего следует и т.д. Если этого не сделать, то спустя какое-то время вспомнить что делает та или иная функция станет очень сложно даже вам самим, не говоря уже про остальных. Помните об этом!

Что будем делать дальше: на следующем уроке мы научим созданный нами календарь ставить ссылки на числа месяца. А самое главное, мы перейдем к работе с формами и базами данных для создания полноценного новостного раздела.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 13.01.2004

не пугайтесь названия урока, даже


Урок 4. Шаг второй - переходим к работе с БД



Самое главное - не пугайтесь названия урока, даже если вы никогда не работали с базами данных. Без них просто невозможно построить гибкий, легко настраиваемый сайт. Отказ от использования БД не дает никаких преимуществ разработчику, а наоборот, здорово уменьшает возможности по созданию сайта и быстрому динамическому изменению содержимого. Построение серьезного ресурса без БД - это как рыбалка без удилища: вроде бы и можно кого-то поймать, однако делать это крайне неудобно. Иными словами, если вы пока не умеете работать с БД - обязательно научитесь и активно используйте их в своих проектах. На этом закончим агитацию, будем считать, что мы вас убедили в необходимости использования БД.

Работать с БД на Parser очень удобно. В Parser встроена мощная система взаимодействия с различными СУБД. В настоящее время Parser может работать с MySQL, Oracle, PgSQL, а также с любой СУБД через драйверы ODBC (в т.ч. MS SQL, MS Access). Поскольку исходные коды Parser3 являются открытыми, возможно добавление поддержки любых других знакомых вам СУБД после создания соответствующего драйвера. При этом работа с ними не требует практически никаких дополнительных знаний собственно Parser. Все, что нужно - это подключится к выбранной СУБД и работать, используя SQL в объеме и формате, поддерживаемом СУБД. При передаче SQL-запросов Parser может только заменить апострофы соответствующей конструкцией в зависимости от СУБД, для «защиты от дурака», а все остальное передается, как есть.

Существует еще специальная конструкция для записи больших строковых литералов. Oracle, PgSQL и, возможно, какие-то серверы, драйверы к которым будут написаны в будущем, не умеют работать с большими строковыми литералами. Если передаваемая, например, из формы, строка будет содержать больше 2000 [Oracle 7.x] или 4000 [Oracle 8.x] букв, сервер выдаст ошибку «слишком длинный литерал». Если пытаться хитрить, комбинируя «2000букв» + «2000букв», то также будет выдана ошибка «слишком длинная сумма».
Для хранения таких конструкций используется тип данных CLOB[Oracle] и OID[PgSQL], а для того, чтобы SQL команды были максимально просты, при записи таких строк необходимо лишь добавить управляющий комментарий, который драйвер соответствующего SQL-сервера соответствующим образом обработает:



insert into news text values (/**text**/'$form:text')



Слово text в записи /**text**/ - это имя колонки, в которую предназначен следующий за этой конструкцией строковый литерал. Пробелы здесь недопустимы!

Со всеми возможностями Parser по работе с различными СУБД в рамках данного урока мы знакомиться, конечно же, не будем. Остановимся на MySQL. Почему именно на ней? Прежде всего потому, что она очень распространена, и многие веб-проекты используют именно ее. Кроме того, практически все компании, занимающиеся сетевым хостингом, предоставляют клиентам возможность работы с этой СУБД. Ну и, несомненно, немаловажный фактор - она бесплатна, доступна и легка в освоении.

Давайте определимся, что будем хранить в базе данных. Очевидный ответ : будем хранить новости. Причем таблица СУБД с новостями должна содержать такие поля: уникальный номер новости в базе, который будет формироваться автоматически СУБД, дата внесения новости в базу, по которой мы будем проводить выборку новостей за конкретное число, заголовок новости и собственно ее текст. Просто, без тонкостей и премудростей, однако это эффективно работает.

Есть еще один вопрос, с которым нужно определиться: каким образом новости будут попадать в базу? Можно их заносить и из командной строки СУБД, но это не удобно. В случае если вы предполагаете строить сайт для intranet, есть вариант использовать в качестве СУБД или средства доступа к БД широко распространенную MS Access. Привычный GUI и copy+paste обеспечат вам любовь многих коллег по работе на долгие годы. Для маленьких баз данных это решение может оказаться оптимальным. Мы же предлагаем решение, ориентированное на Internet - создание на сайте раздела администрирования с формой для ввода новостей прямо из браузера.



Постановка задачи закончена, переходим к ее практическому решению. Для дальнейшей работы вам потребуется установленная СУБД MySQL, без которой рассматриваемый здесь пример просто не будет работать.

Прежде всего, средствами MySQL создаем новую базу данных с именем p3test, содержащую одну единственную таблицу news с полями id, date, header, body:



id



int not null auto_increment primary key



date



date



header



varchar(255)



body



text



Теперь создадим раздел администрирования, который даст возможность заполнить созданную базу данных новостями. Для этого в корневом каталоге сайта создаем каталог admin, а в ней index.html, в который пишем следующее:

@greeting[]

Администрирование новостей



@body_additional[]

Добавление новостей

@body_main[]

$now[^date::now[]]

<center>

<form method="POST">

<p>

Date: <input name="date" value="${now.year}-${now.month}-${now.day}">

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

Header: <input name="header">

</p>

<p>Body:<br>

<textarea cols="50" name="body" rows="5"></textarea>

</p>

<p>

<input type="submit" value="Add New" name="posted">&nbsp;&nbsp;&nbsp;

<input type="reset" value="Cancel">

</p>

</form>

#начало обработки

^if(def $form:date && def $form:header && def $form:body){

   ^connect[$connect_string]{

      ^void:sql{insert into news

         (date, header, body)

      values 

         ('$form:date', '$form:header', '$form:body')



      }

      …сообщение добавлено

      }

}{

   …для добавления новости необходимо заполнить все поля формы

}

</center>



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

@auto[]

$connect_string[mysql://root@localhost/p3test]

Как видите, структура этой страницы полностью соответствует придуманной нами структуре страниц сайта. Все элементы, как то: приветствие, две части body, footer и header присутствуют. Кстати, вы помните, откуда на этой странице появятся header и footer? Правильно, из функции main корневого auto.p).

Незнакомые конструкции только в основной части. Давайте с ней разберемся. В начале обычная HTML форма, с подстановкой текущей даты в поле date как значения по умолчанию. Сделано это исключительно для удобства пользователей.

Легкое недоумение может вызвать запись:

${now.year}-${now.month}-${now.day}



Фигурные скобки здесь используются для того, чтобы получить строку вида «2001-11-06» (в таком формате мы собираемся хранить дату новости в БД). Если скобки не ставить, то Parser выдаст ошибку при обработке этого кода, поскольку не сможет понять, что нужно делать. Для него «-» будет частью имени. Запомните, если вам нужно четко отделить имя переменной от следующей за ним буквы, скажем «-», как в нашем случае, нужно записать:

${имя_переменной}-



И в результате вы получите:

значение_переменной-



Обязательно прочитайте страницу, посвященную правилам составления имен.

Лучшим решением этой проблемы было бы использовать в этом месте конструкцию ^date.sql-string[]. Попробуйте самостоятельно доработать этот пример, пользуясь справочником. Если не получится - не расстраивайтесь, на следующем уроке мы покажем, как это сделать.



Продолжим. Если вам уже доводилось работать с формами, то вы знаете, что формы передают введенные в них значения на дальнейшую обработку каким-либо скриптам. Здесь обработчиком данных формы будет сама страница, содержащая эту форму. Никаких дополнительных скриптов нам не понадобится.

После закрывающего тега </form> начинается блок обработки. Вначале с помощью if мы проверяем поля формы на пустоту. Этого можно опять же не делать, но мы хотим создать нечто большее, чем учебный экспонат без практического применения. Для того чтобы осуществить проверку, необходимо получить значения полей этой формы. В Parser это реализуется через статические переменные (поля). Мы просто обращаемся к полям формы, как к статическим полям:

$form:поле_формы



Полученные таким образом значения полей мы и будем проверять на пустоту с помощью оператора def и логического «И»(&&). Мы уже проверяли объект на существование в третьем уроке, но там был опущен оператор def, поскольку проверяли на пустоту таблицу. Как вы помните, таблица в выражении имеет числовое значение, равное числу строк в ней, поэтому любая непустая таблица считается определенной. Здесь же необходимо использовать def, как и в случае проверки на def других объектов. Если в поле ничего не было введено, то значение $form:поле_формы будет считаться неопределенным (undefined). После того, как все значения полей заполнены, необходимо поместить их в базу данных. Для этого нужно сначала подключиться к базе данных, а затем выполнить запрос SQL для вставки данных в таблицу. Посмотрите, как мы это делаем:

^connect[$connect_string]{

   ^void:sql{insert into news

      (date, header, body)

   values 

      ('$form:date', '$form:header', '$form:body')

   }

   …cообщение добавлено

}



Удобство Parser при работе с базами данных состоит в том, что он, за исключением редких случаев, не требует изучать какие-либо дополнительные операторы, кроме тех, которые предусмотрены в самой СУБД.


Сессия работы с базой данных находится внутри оператора connect, общий синтаксис которого:

^connect[протокол://строка соединения]{методы, передающие запросы SQL}



Для MySQL это запишется так:

^connect[mysql://пользователь:пароль@хост/база_данных]{…}



В фигурных скобках помещаются методы, выполняющие SQL-запросы. При этом любой запрос может возвратить или не возвратить результат (например, в нашем случае нужно просто добавить запись в таблицу БД, не возвращая результат), поэтому Parser предусматривает различные конструкции для создания этих двух типов SQL-запросов. В нашем случае запрос записывается как:

^void:sql{insert into news 

      (date, header, body)

   values

      ('$form:date', '$form:header', '$form:body')

}



Кстати, это статический метод класса void, помните про двоеточие?

То, что здесь не выделено цветом, является командами SQL. Ничего сложного здесь нет. Если вы знакомы с SQL, то больше ничего и не потребуется, а если почему-то пока не знакомы, мы вновь рекомендуем его изучить. Вам это многократно пригодится в дальнейшем. Время, потраченное на это изучение, не пропадет даром.

Оцените все изящество этого варианта взаимодействия с базой данных - Parser обеспечивает прозрачный доступ к СУБД и, за редким исключением, не требует каких-либо дополнительных знаний. При этом, как вы видите, мы можем помещать в запросы SQL еще и данные из нашей формы, пользуясь конструкциями Parser. Возможности этого симбиоза просто безграничны. СУБД решает все задачи, связанные с обработкой данных (она ведь именно для этого и предназначена и очень неплохо с этим справляется), а нам остается только воспользоваться результатами ее работы. Все аналогично и с другими СУБД, с которыми вы можете столкнуться в своей работе.

Теперь у нас есть форма, позволяющая помещать записи в нашу БД. Занесите в нее несколько записей. А теперь давайте их оттуда извлекать, но перед этим неплохо бы немного доработать функцию calendar, созданную на предыдущем уроке.


Нужно, чтобы в календаре ставились ссылки на дни месяца, а выбранный день передавался как поле формы. Тогда по числам-ссылкам в календаре пользователь будет попадать в архив новостей за выбранный день. Модернизация эта неcложная, просто добавим немного HTML в auto.p раздела news: $days.$week_day в коде if обнесем ссылками таким образом:

<a href="/news/?day=$days.$week_day">$days.$week_day</a>



В результате мы получаем возможность использовать наш календарь в качестве меню доступа к новостям за определенный день.

Теперь займемся /news/index.html. В него заносим такой код:

@greeting[]

Страница новостей,  заходите чаще!



@body_additional[]

<center>Архив новостей за текущий месяц:</center>

<br>

^calendar[]

@body_main[]

<b><h1>НОВОСТИ</h1></b>

$day(^if(def $form:day){

   $form:day

}{

   $now.day

})

^connect[$connect_string]{

   $news[^table::sql{select

       date, header, body 

   from

      news 

   where

      date='${now.year}-${now.month}-$day'

   }]

   ^if($news){

      ^news.menu{

         <b>$news.date - $news.header</b><br>

         ^untaint{$news.body}<br>

      }[<br>]

   }{

      За указанный период новостей не найдено.

   }

}



Структура обычная. В дополнительной части body помещаем меню-календарь вызовом ^calendar[] (напомним, что эта функция определена в auto.p раздела news). Основа информационной части страницы - выборка из базы данных новостей за тот день, по которому щелкнул пользователь (условие where в SQL-запросе).


Это второй вариант SQL-запроса, при котором результат возвращается. Обратите внимание, здесь результатом запроса будет таблица, с которой в дальнейшем мы будем работать. Поэтому необходимо создать объект класса table.

Познакомимся с еще одним конструктором класса table - конструктором на базе SQL-запроса. Его логика абсолютно аналогична работе конструктора ^table::load[], только источником данных для таблицы является не текстовый файл, как в случае с пунктами меню, а результат работы SQL-запроса - выборка из базы данных:

$переменная[^table::sql{код SQL запроса}]



Воспользоваться этим конструктором вы можете только внутри оператора ^connect[], то есть когда имеется установленное соединение с базой данных, поскольку обработкой SQL-запросов занимается сама СУБД. Результатом будет именованная таблица, имена столбцов которой совпадают с заголовками, возвращаемыми SQL-сервером в ответ на запрос.

Небольшое отступление. При создании SQL-запросов следует избегать использования конструкций вида select * from … поскольку для постороннего человека, не знающего структуру таблицы, к которой происходит обращение, невозможно понять, какие данные вернутся из БД. Подобные конструкции можно использовать только для отладочных целей, а в окончательном коде лучше всегда явно указывать названия полей таблиц, из которых делается выборка данных.

Остальная часть кода уже не должна вызывать вопросов: if обрабатывает ситуацию, когда поле day (выбранный пользователем день на календаре, который передается из функции calendar) не определено, то есть человек пришел из другого раздела сайта через меню навигации. Если поле формы day определено (def), то используется день, переданный посетителем, в противном случае используем текущее число. Далее соединяемся с БД, также как мы это делали, когда добавляли новости, создаем таблицу $news, в которую заносим новости за запрошенный день (результат SQL-запроса), после чего с помощью метода menu последовательно перебираем строки таблицы news и выводим новости, обращаясь к ее полям.


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

^untaint{$news.body}



Отвлекитесь немного и внимательно прочитайте раздел справочника, посвященный операторам taint и untaint, где подробно описана логика их работы. Это очень важные операторы и вы наверняка столкнетесь с необходимостью их использования. К тому же большой объем работы по обработке данных Parser делает самостоятельно, она не видна на первый взгляд, но понимать логику действий необходимо.

Прочитали? Теперь продолжим. Зачем он нужен здесь? У нас есть страница для администрирования новостей, и мы хотим разрешить использование тегов HTML в записях. По умолчанию это запрещено, чтобы посторонний человек не мог внести Java-скрипт, например, перенаправляющий пользователя на другой сайт. Как это сделать? Да очень просто: достаточно выборку записей из таблицы преобразовать с помощью оператора untaint:

^untaint{текст новости}



В нашем случае используется значение по умолчанию [as-is], которое означает, что данные будут выведены так, как они есть в базе. Мы можем позволить себе поступить так, поскольку изначально не предполагается доступ обычных пользователей к разделу администрирования, через который добавляются новости.

Теперь можно немного расслабиться - новостной блок нашего сайта завершен. Мы можем добавлять новости и получать их выборку за указанный пользователем день. На этом четвертый урок будем считать оконченным, хотя есть некоторые детали, которые можно доработать, а именно: научить календарь не ставить ссылки на дни после текущего, выводить в заголовке информационной части дату, за которую показываются новости, да и просто реализовать возможность доступа к новостям не только за текущий месяц, но и за предыдущие. Однако это уже задание вам. Знаний, полученных на предыдущих уроках вполне достаточно, чтобы доработать этот пример под свои требования и желания. Творите!

Подведем итоги четвертого урока.

Что мы сделали: создали раздел администрирования для добавления новостей.


Модернизировали функцию, формирующую календарь на текущий месяц. Наполнили раздел новостей данными из БД на основе запроса пользователей либо по умолчанию за текущую дату.

Что узнали:

·механизм взаимодействия Parser с СУБД MySQL  

·как осуществлять различные SQL-запросы к БД (статический метод sql класса void и конструктор sql класса table)  

·оператор untaint  

Что надо запомнить: работа с базами данных в Parser осуществляется легко и понятно, нужно только изучить работу самой СУБД. Не отказывайтесь от использования БД в своих работах.

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

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 31.03.2004

Во всех предыдущих уроках мы


Урок 5. Пользовательские классы Parser



Во всех предыдущих уроках мы оперировали классами и объектами, предопределенными в Parser. Например, есть уже хорошо знакомый нам класс table, у него существуют свои методы, которые мы широко использовали. Полный список всех методов этого класса можно посмотреть в справочнике. Однако ограничение разработчиков рамками только базовых классов в какой-то момент может стать сдерживающим фактором. «Неспособность не есть благодетель, а есть бессилие…», поэтому для удовлетворения всех потребностей пользователей необходимо иметь возможность создавать собственные (пользовательские) классы объектов со своими методами. На этом уроке мы и создадим средствами Parser новый класс объектов со своими собственными методами.

Объектом, в принципе, может быть все что угодно: форум, гостевая книга, различные разделы и даже целый сайт. Здесь мы подошли к очередному уровню структуризации - на уровне объектов, а не методов. Как мы поступали раньше? Мы выделяли отдельные куски кода в методы и вызывали их, когда они были необходимы. Но в качестве отдельных блоков сайта было бы намного удобнее использовать собственные объекты: для получения форума создаем объект класса «форум», после чего используем его методы, например «удалить сообщение», «показать все сообщения» и поля, например, «количество сообщений». При этом обеспечивается модульный подход на качественно ином уровне, чем простое использование функций. В единую сущность собираются код и данные (методы и поля). Разрозненные ранее методы и переменные объединяются воедино и используются применительно к конкретному объекту - «форуму». В терминах объектно-ориентированного программирования это называется инкапсуляцией. Кроме того, один раз создав класс форум, его объекты можно использовать в различных проектах, абсолютно ничего не меняя.

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

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

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

С целями определились, займемся реализацией. Прежде всего, создадим таблицу gbook в базе данных p3test:





id



int not null auto_increment primary key



author



varchar(255)



email



varchar(255)



date



date



body



text



Теперь необходимо познакомиться еще с несколькими понятиями Parser - классом MAIN и наследованием. Как уже говорилось, класс является объединяющим понятием для объектов, их методов и полей. Класс MAIN объединяет в себя методы и переменные, описанные пользователями в файлах auto.p и запрашиваемом документе (например, index.html). Каждый следующий уровень вложенности наследует методы, описанные в auto.p предыдущих уровней каталога. Эти методы, а также методы, описанные в запрашиваемом документе, становятся статическими функциями класса MAIN, а все переменные, созданные в auto.p вверх по каталогам и в коде запрошенной страницы, - статическими полями класса MAIN.

Для пояснения рассмотрим следующую структуру каталогов:

   /

   |__ auto.p

   |__ news/



   |   |___auto.p

   |   |___index.html

   |   |___details/

   |       |_______ auto.p

   |       |_______index.html

   |__contacts/ |

            |_______auto.p

          |_______index.html

   

При загрузке страницы index.html из каталога /news/details/ класс MAIN будет динамически «собран» из методов, описанных в корневом файле auto.p, а также в файлах auto.p разделов /news/ и /news/details/. Методы, описанные в auto.p раздела /contacts/, будут недоступны для страниц из раздела /news/details/.

Как «собирается» класс MAIN теперь понятно, но, прежде чем приступить к созданию собственного класса, необходимо также выяснить, как из пользовательского класса вызывать методы и получать значения переменных класса MAIN. Методы класса MAIN вызываются как статические функции:

^MAIN:метод[],



а переменные являются статическими полями класса MAIN. К ним можно получить доступ так же, как к любым другим статическим полям:

$MAIN:поле



Теперь переходим к практике. В корневой auto.p добавляем еще один метод, с помощью которого можно будет не только соединяться с БД, но и передавать ей произвольный SQL-запрос:

@dbconnect[code]

^connect[$connect_string]{$code}

# connect_string определяется в методе @auto[]

# $connect_string[mysql://root@localhost/p3test]



Метод вынесен в корневой auto.p для того, чтобы впоследствии можно было бы легко подключаться к серверу баз данных с любой страницы, поскольку методы из корневого auto.p будут наследоваться всегда. Обратите внимание на то, что здесь используется передача методу параметра. В нашем случае он один - code, с его помощью мы и будем передавать код, выполняющий SQL-запросы.


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

Дальше в каталоге нашего сайта создаем подкаталог, в которой будем хранить файл с нашим классом, например, classes. Далее в этом каталоге создаем файл gbook.p (пользовательские файлы мы предлагаем хранить в файлах с расширением имени .p) и в него заносим следующий код:

@CLASS

gbook

@load[]

^MAIN:dbconnect{

   $messages[^table::sql{select author, email, date, body from gbook}]

}

@show_messages[]

^if($messages){

   ^messages.menu{

      <table width="100%">

         <tr>

         <td align="left"><b>$messages.author

            ^if(def $messages.email){

               $messages.email

            }{

               Нет электронного адреса

            }</b>

         </td>

         <td align="right">$messages.date</td>

         </tr>

      </table>

      <table width="100%">

      <tr>

         <td>$messages.body</td>

      </tr>

      </table>



   }[<table width="100%" border="0" bgcolor="000000" cellspacing="0"> 

        <tr><td>&nbsp^;</td></tr>

   </table>]

}{

   Гостевая книга пуста.

}

@show_form[]

<hr>

<br>

$date[^date::now[]]

<center>

<form method="POST">

<p>

Author<sup>*</sup><input name="author"><br>

E-mail&nbsp;&nbsp;<input name="email">

<br>text<br><textarea cols="50" name="text" rows="5"></textarea>

</p>

<p>

<input type="submit" value="Send" name="post">&nbsp;&nbsp;&nbsp;

<input type="reset" value="Cancel">

</p>

</form>

</center>

@test_and_post_message[]

^if(def $form:post){

   ^if(def $form:author){

      ^MAIN:dbconnect{

         ^void:sql{insert into gbook

            (author, email, date, body)

         values (

            '$form:author',

            '$form:email',

            '${date.year}-${date.month}-${date.day}',

            '$form:text'

         )}

      }

      $response:location[$request:uri]



   }{

      <center>Поле автор обязательно для заполнения</center>

   }

}



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

@CLASS



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



@CLASS

имя класса



@USE

файл родительского класса

@BASE 

имя родительского класса    

Следующей строкой пишем имя нашего класса gbook. Необходимо помнить, что Parser чувствителен к регистру букв в именах, поэтому классы gbook и Gbook являются разными. При этом имя не обязательно должно совпадать с именем файла, в котором храниться пользовательский класс, более того, может быть набрано русскими буквами.    

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

Первый метод load будет конструктором нашего класса. При этом надо иметь в виду, что задача конструктора - создать объект. Кроме этого, он может объявить переменные и присвоить им значения. Эти переменные станут полями объекта пользовательского класса. В нашем случае мы при помощи конструктора sql класса table создаем нужную таблицу. Обратите внимание, что в методах нового класса мы свободно пользуемся методами системных классов и методом dbconnect класса MAIN:

@load[]

^MAIN:dbconnect{

   $messages[^table::sql{select author, email, date, body from gbook}]

}



Как уже говорилось выше, поскольку мы находимся за пределами класса MAIN, для использования методов этого класса перед именем необходимо указать класс, к которому эти методы/поля относятся. Делается это таким образом:

^имя_класса:метод[параметры]

$имя_класса:переменная



В случае, если мы захотим использовать методы/поля другого пользовательского класса, а не класса MAIN, необходимо в начале кода выполнять инструкцию:



@USE

путь к файлу, описывающему класс



Она позволяет использовать модуль, определенный в другом файле. О работе Parser с путями к файлам, рассказано в приложении 1.

Итак, наш новый конструктор будет создавать таблицу с сообщениями, подключаясь к указанной БД. С конструктором разобрались, начинаем описание собственно методов нового класса. Метод show_messages нашего класса выводит на экран сообщения из таблицы gb, созданной в методе load. Строки перебираются при помощи метода menu класса table. Все знакомо, ничего нового нет и в других методах:

show_form - выводит на экран форму для добавления нового сообщения гостевой книги

test_and_post_message - проверяет, нажата ли кнопка post, заполнено ли поле author и, если все условия выполнены, заносит сообщение в базу данных, используя все тот же метод dbconnect, определенный в классе MAIN

На этом создание пользовательского класса, описывающего методы объектов класса gbook, завершено. Его осталось только подключить для использования на нашем сайте. Перед нами стоит задача сообщить Parser, что на некоторой странице мы собираемся использовать свой класс. Для этого в файле index.html каталога gbook в первой строке напишем следующее:

@USE

/classes/gbook.p



Теперь на этой странице можно создать объект класса gbook и использовать затем его методы. Сделаем это в основной информационной части:

@body_main[]

Гостевая книга тестового сайта<br>

<hr>



$gb[^gbook::load[]]

^gb.show_messages[]

^gb.show_form[]

^gb.test_and_post_message[]

# и конечно же не забываем про остальные части 

@greeting[]

Оставьте свой след:



@body_additional[]

Нам пишут…



Здесь мы уже работаем с объектом созданного пользовательского класса, как с любым другим объектом: создаем его при помощи конструктора класса и вызываем методы, определенные в новом классе. Посмотрите, насколько изящным получилось наше решение. Читабельность кода очевидна и, глядя на этот фрагмент, сразу понятно, что он делает.


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

В заключение хочется заметить, что изящнее было бы вынести методы вроде dbconnect из класса MAIN в отдельный класс. Это позволило бы не перегружать класс MAIN, улучшилась бы читаемость кода, а также легче стало бы ориентироваться в проекте. Там, где эти нужны методы этого класса, его можно было бы подключать с помощью @USE.



Подведем итоги пятого урока.

Что мы сделали: создали свой собственный класс и на основе объекта этого класса создали гостевую книгу на нашем сайте.

Что узнали:



·класс MAIN

 

·создание пользовательского класса  

·как передавать параметры методам  

Что надо запомнить: класс является «высшей формой» структуризации, поэтому необходимо стремиться к выделению в отдельные классы кубиков, из которых вы будете строить ваши сайты. Это позволяет достичь максимальной понятности логики работы проектов и дает невероятные удобства в дальнейшей работе.

Что делать дальше: на этом создание нашего учебного сайта можно считать завершенным. Конечно, он далек от идеала и использовать его в таком виде не стоит. Для реального использования необходимо выполнить целый ряд доработок: модифицировать календарь в разделе новостей, в гостевой книге организовать проверку введенных данных на корректность и т.д. Но мы и не ставили задачу сделать полнофункциональный проект. Мы просто хотели показать, что работать с Parser совсем не сложно, а производительность от его использования возрастает существенно. Теперь вы сами обладаете всеми необходимыми базовыми знаниями для полноценной работы с Parser, остается только совершенствовать их и приобретать опыт.

Удачи!

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 07.10.2003

но не их форматирование. Подготовкой


Урок 6. Работаем с XML



<?xml version="1.0" encoding="windows-1251" ?>

<article>

    <author id="1" />

    <title>Урок 6. Работаем с XML</title>

    <body>

        <para>Представьте, что вам позволено придумывать любые теги

              с любыми атрибутами. То есть вы сами можете определять,  

              что означает тот или иной выдуманный вами тег или атрибут.</para>

        <para>Такой код будет содержать данные, …</para>

    </body>

    <links>

        <link href="http://parser.ru/docs/lang/xdocclass.htm">Класс xdoc</link>

        <link href="http://parser.ru/docs/lang/xnodeclass.htm">Класс xnode</link>

    </links>

</article>



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

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

Однако прогресс не стоит на месте, и сейчас мы имеем не зависящие от средства скриптования стандарты XML и XSLT, позволяющие нам реализовать то, что мы только что представляли.
А также стандарты DOM и XPath, открывающие для нас еще больше возможностей.

Parser полностью поддерживает все эти стандарты.

Сейчас откройте выбранную вами вчера в книжном магазине книгу, описывающую XML и XSLT. Используйте ее как справочник.

Посмотрим, как можно приведенную статью преобразовать из XML в HTML.

Запишем текст из начала статьи в файл article.xml

И создадим файл article.xsl, в котором определим выдуманные нами теги:

<?xml version="1.0" encoding="windows-1251" ?> 

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="article">

    <html>

        <head><title><xsl:value-of select="title" /></title></head>

        <body><xsl:apply-templates select="body | links" /></body>

    </html>

</xsl:template>

<xsl:template match="body">

    <xsl:apply-templates select="para" />

</xsl:template>

<xsl:template match="links">

    Ссылки по теме:

    <ul>

        <xsl:for-each select="link">

            <li><xsl:apply-templates select="." /></li>

        </xsl:for-each>

    </ul>

</xsl:template>

<xsl:template match="para">

    <p><xsl:value-of select="." /></p>

</xsl:template>

<xsl:template match="link">



    <a href="{@href}"><xsl:value-of select="." /></a>

</xsl:template>

</xsl:stylesheet>



Данные и шаблон преобразования готовы. Создаем article.html, в который заносим следующий код:

# входной xdoc документ

$sourceDoc[^xdoc::load[article.xml]]

# преобразование xdoc документа шаблоном article.xsl

$transformedDoc[^sourceDoc.transform[article.xsl]]

# выдача результата в HTML виде

^transformedDoc.string[

    $.method[html]

]



Первой строкой мы загружаем XML-файл, получая в sourceDoc его DOM-представление.

Конструкция похожа на загрузку таблицы, помните ^table::load[…]? Только в этот раз мы загружаем не таблицу (получая объект класса table), а XML-документ (получаем объект класса xdoc).

Второй строкой мы преобразуем входной документ по шаблону article.xsl.

Из входного документа получаем выходной, применяя XSLT преобразование, описанное в шаблоне.

Последней строкой мы выдаем пользователю текст выходного документа в HTML формате (параметр method со значением html).

Здесь можно задать все параметры, допустимые для тега <xsl:output … />.

Рекомендуем также задать параметр "без отступов" (параметр indent со значением no: $.indent[no]), чтобы избежать известной проблемы с пустым местом перед </td>.

Обратившись теперь к этой странице, пользователь получит результат преобразования:

<html>

<head><title>Урок 6. Работаем с XML</title></head>

<body>

<p>Представьте, что вам позволено придумывать любые теги

с любыми атрибутами. То есть вы сами можете определять,  

что означает тот или иной выдуманный вами тег или атрибут.

</p>

<p>Такой код будет содержать данные, …



</p>

Ссылки по теме:

<ul>

<li><a href="http://parser.ru/docs/xdocclass.htm">Класс xdoc</a></li>

<li><a href="http://parser.ru/docs/xnodeclass.htm">Класс xnode</a></li>

</ul>

</body>

</html>

Как вы заметили, тег <author … /> никак не был определен, как следствие, информация об авторе статьи не появилась в выходном HTML. Со временем, когда вы решите где и как будете хранить и показывать данные об авторах, достаточно будет дополнить шаблон - исправлять данные статей не потребуется.

Внимание: если вы не хотите, чтобы пользователи вашего сервера имели доступ к .xml и .xsl файлам, храните эти файлы вне веб-пространства (^xdoc::create[/../directory_outside_of_web_space/article.xml]), или запретите к ним доступ средствами веб-сервера (пример запрета доступа к .p файлам здесь: «Установка Parser на веб-сервер Apache. CGI скрипт»).

Подведем итоги шестого урока.



Что мы сделали: создали заготовку для публикации информации в XML формате с последующим XSLT преобразованием в HTML.

Что узнали:



·класс xdoc

 

·как загружать XML, делать XSLT преобразования, выводить объекты класса xdoc в виде HTML  

Что надо запомнить: что надо купить книжку по XML, XSLT и DOM.

Что делать дальше: читать эту книжку и экспериментировать с примерами из нее, радуясь тому, что на свете есть хорошие стандарты. А также почитать о postprocess, и придумать, как его приспособить, чтобы обращение к XML-файлу вызывало его преобразование в HTML?


Loops


Циклы


Цикл - процесс многократного выполнения некоторой последовательности действий.

В Parser существует два оператора циклов: for, в котором количество повторов тела цикла ограничивается заданными значениями счетчика, и while, где количество повторов зависит от выполнения условия. Для того, чтобы избежать зацикливания, в Parser встроен механизм обнаружения бесконечных циклов. Бесконечным считается цикл, тело которого выполняется более 10000 раз.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 16.04.2002



Mailclass


Класс mail


Класс предназначен для работы с электронной почтой. Описание настройки Parser для работы этого класса см. Конфигурационный метод.

Copyright © 1997?2004 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 06.02.2004