Отправляет email-рассылки с помощью сервиса Sendsay

KirovLUG: пользователи Linux в Вятке

Работа над проектом Lindocs. Скрипты конверта из текущего состояния

Работа над проектом Lindocs. Скрипты конверта из текущего состояния

Создаем список обрабатываемых документов:

$ ls -1 *.html > htmllist

Удаляем те документы, которые не несут данных:

begin.html
default.html
index.html

Удалим "не-юниксовые" окончания строк в html-файлах:

$ ls -1 *.html | xargs dos2unix

Каждый файл выглядит примерно следующим образом:

<!-- тут стандартное для всех начало -->
<strong>&nbsp;&nbsp;&nbsp;&nbsp;Теоретические основы</strong><BR>
<BR>
<a href="Linux/Docs/vodol.html">В. Водолазкий "Путь к LINUX"</a><br>
<br>
<a href="Linux/other/html/acquaintance_part_01.htm">Знакомство с Linux.</a>
&nbsp;<a href="Linux/Sites/www.kuzbass.ru/docs/unixprogenv/ch1.txt">1</a>
<a href="Linux/other/html/acquaintance_part_02.htm">2</a>
<a href="Linux/other/html/acquaintance_part_23.htm">23</a><br>
В.А.Костромин. 14 дней жизни одной операционной системы.<br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="Linux/Docs/general/day_1-6.htm">День 1-6</a><br>
<a href="Linux/Sites/MyComp/224_02.htm">Висит? Снимем!</a><br>
<!-- тут стандартный для всех конец -->
Начнем писать скрипт по шагам:

Шаг первый. Вычленяем информацию из одной строки

Напишем отдeльную функцию извлекающую ссылку и ее описание из
передаваемой строки.

sub extract_data {
my($l_str) = @_[0];
my $l_link = $l_str;
my $l_desc = $l_str;
# Выделяем ссылку из строки
$l_link =~ s/(?i)(.*)\<a\shref\=\"(.*)\"\>(.*)/\2/;
# Выделяем описание из строки
$l_desc =~ s/(?i)(.*)\<a\shref\=\"(.*)\"\>(.*)\<\/a\>(.*)/\3/;
return ($l_link, $l_desc);
}
Напишем отдeльную функцию извлекающую описание темы материала,
состоящего из нескольких частей:

sub extract_topic {
my($l_str) = @_[0];
# Выделяем описание из строки
my $l_desc = $l_str;
$l_desc =~ s/(?i)^(.*)\<BR\>(.*)/\1/;
return $l_desc;
}
Напишем отдeльную функцию извлекающую описание для всего файла, т.е.
для индекса:

sub extract_index {
my($l_str) = @_[0];
my $l_desc = $l_str;
# Выделяем описание из строки
$l_desc =~ s/(?i)^\<strong\>(\&nbsp\;){4}(.*)\<\/strong\>(.*)/\2/;
return $l_desc;
}
Шаг второй. Определение типа строки

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

sub def_str_type {
my ($l_num) = @_[0];
my $l_res = 0;
# Строка, которая выглядит как обычная
if ( @f_array[$l_num] =~ /(?i)^\<a\shref.*\<br\>/ ) {
# Надо проверить следующие за ней
if ( def_str_type($l_num+1) == 31 ) {
# Строка - начало материала из нескольких частей с одной темой
# так как за ней соответствующая строка
$l_res = 30;
}
else {
# Все таки обычная строка
$l_res = 1;
}
}
# Строка - начало материала из нескольких частей
elsif ( @f_array[$l_num] =~ /(?i)^\<a\shref/ ) {
$l_res = 2;
}
# Строка - продолжение и конец материала из нескольких частей
elsif ( @f_array[$l_num] =~ /(?i)^\s+.*\<a\shref/ ) {
$l_res = 21;
}
# Строка - продолжение и конец материала из нескольких частей с одной
темой
elsif ( @f_array[$l_num] =~ /(?i)^(\&nbsp\;){2,}.*\<a\shref.*\<br\>/
) {
$l_res = 31;
}
# Строка выглядит как не несущая в себе данных, но за ней продолжение
материала
# состоящего из нескольких частей, значит, данная строка начало этого
материала
elsif ( ( $l_num+1 < $#f_array ) && ( def_str_type($l_num+1) == 31 )
) {
$l_res = 3;
}
return $l_res;
}
Видно, что внутри функции происходит ее рекурсивный вызов...

Шаг третий. Генерация xml-блоков

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

sub generate_record {
my ($l_type, $l_id, $l_part, $l_link, $l_desc, $l_index) = @_;
# Генерируем xml-блок
my $l_res = "";
$l_res = $l_res." <element";
length($l_type) != 0 ? $l_res = $l_res." type=\"topic\"" : $l_res = $l_res;
length($l_id) != 0 ? $l_res = $l_res." id=\"".$l_id."\"" : $l_res = $l_res;
length($l_part) != 0 ? $l_res = $l_res." part=\"".$l_part."\"" : $l_res
= $l_res;
$l_res = $l_res.">\n";
length($l_link) != 0 ? $l_res = $l_res." <link type=\"rel\">".$l_link."</link>\n"
: $l_res = $l_res;
$l_res = $l_res." <desc>".$l_desc."</desc>\n";
$l_res = $l_res." <author></author>\n";
$l_res = $l_res." <index>".$l_index."</index>\n";
$l_res = $l_res." </element>\n";
return $l_res;
}
Процедура, которая учитывает переданные ей параметры и в зависимости
от них генерирует xml-блок для индекса:

sub generate_index {
my ($l_index, $l_desc) = @_;
# Генерируем xml-блок
my $l_res = "";
$l_res = $l_res." <index>\n";
$l_res = $l_res." <value>".$l_index."</value>\n";
$l_res = $l_res." <parent></parent>\n";
$l_res = $l_res." <desc>".$l_desc."</desc>\n";
$l_res = $l_res." </index>\n";
return $l_res;
}
Шаг четвертый. Работа с содержимым html-файла

Итак, нужно последовательно перебирать все строки файла,
определять их тип, извлекать из нее нужные данные и генерировать
xml-блоки. Так как при генерации блока для ссылок, обозначающих
материал состоящий из нескольких частей, необходим уникальный
идентификатор, то его генерировать будем с помощью функции md5_base64
из модуля Digest::MD5.

while ( $count < $#f_array ) {
# Выбираем строки по одной
$next_s = @f_array[$count];
# Подошли к концу файла
if ( $is_content && ( ( $cur_s =~ /(?i)^\<\/BODY/ ) && ( $next_s =~ /(?i)^\<\/HTML/
) ) ) {
$is_content = 0;
}
if ( $is_content ) {
# В зависимости от типа строки генерируем необходимый элемент
$str_type = def_str_type($count-1);
if ( $str_type == 1 ) {
$xml_block = $xml_block.generate_record("", "", "", extract_data($cur_s),
$cur_index);
}
elsif ( $str_type == 2 ) {
$id_in = md5_base64($cur_s);
$part_in = 0;
$xml_block = $xml_block.generate_record("", $id_in, $part_in,
extract_data($cur_s), $cur_index);
}
elsif ( $str_type == 21 ) {
$part_in += 1;
$xml_block = $xml_block.generate_record("", $id_in, $part_in,
extract_data($cur_s), $cur_index);
}
elsif ( $str_type == 3 ) {
$id_in = md5_base64($cur_s);
$xml_block = $xml_block.generate_record(1, $id_in, "", "", extract_topic($cur_s),
$cur_index);
}
elsif ( $str_type == 30 ) {
$id_in = md5_base64($cur_s);
($var, $topic) = extract_data($cur_s);
$xml_block = $xml_block.generate_record(1, $id_in, "", "", $topic,
$cur_index);
$xml_block = $xml_block.generate_record("", $id_in, "", extract_data($cur_s),
$cur_index);
}
elsif ( $str_type == 31 ) {
$xml_block = $xml_block.generate_record("", $id_in, "", extract_data($cur_s),
$cur_index);
}
else {
print $cur_s."\n";
}
}
# Сейчас начнутся ссылки на материал
if ( ! $is_content && ( ( $cur_s =~ /(?i)^\<BR/ ) && ( $prev_s =~ /(?i)^\<strong/
) ) ) {
$is_content = 1;
$index_block = generate_index($cur_index, extract_index($prev_s));
}
$prev_s = $cur_s;
$cur_s = $next_s;
$count += 1;
}
Шаг пятый - заключительный. Сварка и спайка

После сварки и спайки получился следующий скрипт:

begin genrate.pl #!/usr/bin/perl

# Импортируем функцию из модуля, необходимую для генерации уникальных
# идентификаторов
use Digest::MD5 qw(md5_base64);

# Считываем параметры переданные из командной строки
# Имя файла с листингом обрабатываемых файлов
my $f_list = @ARGV[0];
# Имя файла куда помещаются результаты
my $f_out = @ARGV[1];

# Начальные значения рабочих переменных
# xml-блок, где накапливаются индексы
my $xml_index = " <indexes>\n";
# xml-блок, где накапливаются ссылки
my $xml_content = " <content>\n";
# Переменные, в которых находятся текущий индексный блок и текущий блок
# ссылок
my $t_xi = "";
my $t_xc = "";

##
# Функция: convert_one
# Входные параметры: $f_name: строковая величина
# Выходные данные: $index_block: строковая величина
# $xml_block: строковая величина
# Описание: Выполняет преобразование из html-файла, имя
# которого передано во входном параметре, в xml-блок по определенным
# правилам. В итоге получается два xml-блока: для индексной секции и
# секции ссылок. Эти блоки возвращаются как результат функции
sub convert_one {
# Имя файла, с которым работаем
my ($f_name) = $_[0];
# Список строк, входящих в файл
local @f_array = ();
# Заполняем список строк
open(F_IN, $f_name) || die "cannot open $f_name for reading: $!";
while (<F_IN>) {
chomp;
push(@f_array, $_);
}
# Закрываем файл
close(F_IN) || die "can't close $f_name: $!";
# Текущий индекс для документа
my $cur_index = substr($f_name, 0, length($f_name)-5);
# Начальное значение, обрабатываемой строки
my $cur_s = "";
# Строки вокруг обрабатываемой
my $prev_s = "";
my $next_s = "";
# Флаг наличия содержания
my $is_content = 0;
# Первоначальное значение счетчика строк
my $count = 0;
# Переменные, куда будет помещаться xml-блок, возращаемый как
# результат
my $index_block = "";
my $xml_block = "";

##
# Функция: generate_record
# Входные параметры: $l_type: строковая величина
# $l_id: строковая величина
# $l_part: строковая величина
# $l_link: строковая величина
# $l_desc: строковая величина
# $l_index: строковая величина
# Выходные данные: $l_res: строковая величина
# Описание: Генерирует xml-запись, атрибутами и полями которой
# являются переданные функции параметры. Сгенерированная запись
# помещается в переменную, которую функция возвращает как результат
sub generate_record {
my ($l_type, $l_id, $l_part, $l_link, $l_desc, $l_index) = @_;
# Генерируем xml-блок
my $l_res = "";
$l_res = $l_res." <element";
length($l_type) != 0 ? $l_res = $l_res." type=\"topic\"" : $l_res
= $l_res;
length($l_id) != 0 ? $l_res = $l_res." id=\"".$l_id."\"" : $l_res
= $l_res;
length($l_part) != 0 ? $l_res = $l_res." part=\"".$l_part."\"" :
$l_res = $l_res;
$l_res = $l_res.">\n";
length($l_link) != 0 ? $l_res = $l_res." <link type=\"rel\">".$l_link."</link>\n"
: $l_res = $l_res;
$l_res = $l_res." <desc>".$l_desc."</desc>\n";
$l_res = $l_res." <author></author>\n";
$l_res = $l_res." <index>".$l_index."</index>\n";
$l_res = $l_res." </element>\n";
return $l_res;
}

##
# Функция: generate_index
# Входные параметры: $l_index: строковая величина
# $l_desc: строковая величина
# Выходные данные: $l_res: строковая величина
# Описание: Генерирует xml-запись, атрибутами и полями которой
# являются переданные функции параметры. Сгенерированная запись
# помещается в переменную, которую функция возвращает как результат
sub generate_index {
my ($l_index, $l_desc) = @_;
# Генерируем xml-блок
my $l_res = "";
$l_res = $l_res." <index>\n";
$l_res = $l_res." <value>".$l_index."</value>\n";
$l_res = $l_res." <parent></parent>\n";
$l_res = $l_res." <desc>".$l_desc."</desc>\n";
$l_res = $l_res." </index>\n";
return $l_res;
}

##
# Функция: extract_data
# Входные параметры: $l_str: строковая величина
# Выходные данные: $l_link: строковая величина
# $l_desc: строковая величина
# Описание: Извлекает из входной строки ссылку и описание
# материала, которые потом возвращает как результат
sub extract_data {
my($l_str) = @_[0];
my $l_link = $l_str;
my $l_desc = $l_str;
# Выделяем ссылку из строки
$l_link =~ s/(?i)(.*)\<a\shref\=\"(.*)\"\>(.*)/\2/;
# Выделяем описание из строки
$l_desc =~ s/(?i)(.*)\<a\shref\=\"(.*)\"\>(.*)\<\/a\>(.*)/\3/;
return ($l_link, $l_desc);
}

##
# Функция: extract_topic
# Входные параметры: $l_str: строковая величина
# Выходные данные: $l_desc: строковая величина
# Описание: Извлекает из входной строки описание материала,
# которое является описанием для целой темы
sub extract_topic {
my($l_str) = @_[0];
# Выделяем описание из строки
my $l_desc = $l_str;
$l_desc =~ s/(?i)^(.*)\<BR\>(.*)/\1/;
return $l_desc;
}

##
# Функция: extract_index
# Входные параметры: $l_str: строковая величина
# Выходные данные: $l_desc: строковая величина
# Описание: Извлекает из входной строки описание, которое
# является описанием индекса
sub extract_index {
my($l_str) = @_[0];
my $l_desc = $l_str;
# Выделяем описание из строки
$l_desc =~ s/(?i)^\<strong\>(\&nbsp\;){4}(.*)\<\/strong\>(.*)/\2/;
return $l_desc;
}

##
# Функция: def_str_type
# Входные параметры: $l_num: целое число
# Выходные данные: $l_res: строковая величина
# Описание: Функция работает с глобальным массивом @f_array,
# определяя тип строк, которые в него входят, номер строки - $l_num
# Тип, определенный у строки, возращается как результат. В функции
# происходит рекурсивный вызов самой себя.
# Возвращаемые типы:
# 0 - строка не несущая информации
# 1 - обычная ссылка
# 2 - ссылка - начало материала из нескольких частей
# 21 - ссылка - продолжение или конец материала из нескольких частей
# 3 - строка - начало материала из нескольких частей с одной темой
# 30 - ссылка - начало материала из нескольких частей с одной темой
# 31 - ссылка - продолжение или конец материала из нескольких частей
# с одной темой
sub def_str_type {
my ($l_num) = @_[0];
my $l_res = 0;
# Строка, которая выглядит как обычная
if ( @f_array[$l_num] =~ /(?i)^\<a\shref.*\<br\>/ ) {
# Надо проверить следующие за ней
if ( def_str_type($l_num+1) == 31 ) {
# Строка - начало материала из нескольких частей с одной
темой
# так как за ней соответствующая строка
$l_res = 30;
}
else {
# Все таки обычная строка
$l_res = 1;
}
}
# Строка - начало материала из нескольких частей
elsif ( @f_array[$l_num] =~ /(?i)^\<a\shref/ ) {
$l_res = 2;
}
# Строка - продолжение и конец материала из нескольких частей
elsif ( @f_array[$l_num] =~ /(?i)^\s+.*\<a\shref/ ) {
$l_res = 21;
}
# Строка - продолжение и конец материала из нескольких частей с одной
темой
elsif ( @f_array[$l_num] =~ /(?i)^(\&nbsp\;){2,}.*\<a\shref.*\<br\>/
) {
$l_res = 31;
}
# Строка выглядит как не несущая в себе данных, но за ней продолжение
материала
# состоящего из нескольких частей, значит, данная строка начало этого
материала
elsif ( ( $l_num+1 < $#f_array ) && ( def_str_type($l_num+1) == 31
) ) {
$l_res = 3;
}
return $l_res;
}

# Цикл выборки строк из файла
while ( $count < $#f_array ) {
# Выбираем строки по одной
$next_s = @f_array[$count];
# Подошли к концу файла
if ( $is_content && ( ( $cur_s =~ /(?i)^\<\/BODY/ ) && ( $next_s
=~ /(?i)^\<\/HTML/ ) ) ) {
$is_content = 0;
}
if ( $is_content ) {
# В зависимости от типа строки генерируем необходимый элемент
$str_type = def_str_type($count-1);
if ( $str_type == 1 ) {
$xml_block = $xml_block.generate_record("", "", "", extract_data($cur_s),
$cur_index);
}
elsif ( $str_type == 2 ) {
$id_in = md5_base64($cur_s);
$part_in = 0;
$xml_block = $xml_block.generate_record("", $id_in, $part_in,
extract_data($cur_s), $cur_index);
}
elsif ( $str_type == 21 ) {
$part_in += 1;
$xml_block = $xml_block.generate_record("", $id_in, $part_in,
extract_data($cur_s), $cur_index);
}
elsif ( $str_type == 3 ) {
$id_in = md5_base64($cur_s);
$xml_block = $xml_block.generate_record(1, $id_in, "", "",
extract_topic($cur_s), $cur_index);
}
elsif ( $str_type == 30 ) {
$id_in = md5_base64($cur_s);
($var, $topic) = extract_data($cur_s);
$xml_block = $xml_block.generate_record(1, $id_in, "", "",
$topic, $cur_index);
$xml_block = $xml_block.generate_record("", $id_in, "", extract_data($cur_s),
$cur_index);
}
elsif ( $str_type == 31 ) {
$xml_block = $xml_block.generate_record("", $id_in, "", extract_data($cur_s),
$cur_index);
}
else {
print $cur_s."\n";
}
}
# Сейчас начнутся ссылки на материал
if ( ! $is_content && ( ( $cur_s =~ /(?i)^\<BR/ ) && ( $prev_s =~
/(?i)^\<strong/ ) ) ) {
$is_content = 1;
$index_block = generate_index($cur_index, extract_index($prev_s));
}
$prev_s = $cur_s;
$cur_s = $next_s;
$count += 1;
}
return ($index_block, $xml_block);
}

# Выбираем по одной строки из файла со списком - определяем имя
# обрабатываемого файла.
open(F_LIST, $f_list) || die "cannot open $f_list for reading: $!";
while (<F_LIST>) {
chomp;
# Вызыаем процедуру конверта для данного файла
($t_xi, $t_xc) = convert_one($_);
# Накапливаем полученные результаты
$xml_index = $xml_index.$t_xi;
$xml_content = $xml_content.$t_xc;
}
close(F_LIST) || die "can't close $f_list: $!";
# Ставим закрывающие теги в блоках
$xml_index = $xml_index." </indexes>\n";
$xml_content = $xml_content." </content>\n";
# Формируем выходной файл
open(F_OUT,">".$f_out) || die "cannot open $f_out for write: $!";
print F_OUT "<lindocs>\n";
print F_OUT $xml_index;
print F_OUT $xml_content;
print F_OUT "</lindocs>\n";
close(F_OUT) || die "can't close $f_out: $!";
end genrate.pl В качестве входноых параметров для него передается имя файла со
списком обрабатываемых файлов и выходной файл, в который будет помещено
получившееся xml-дерево.

Ответить   Wed, 17 Nov 2004 18:00:36 +0300 (#266277)

 

Ответы:

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

Ответить   Thu, 18 Nov 2004 11:03:25 +0300 (#266650)

 

Здравствуйте, Kolotov.

Вы писали 18 ноября 2004 г., 11:03:25:

Могу помочь. Нужны исходные данные и требуемый результат.

Ответить   Thu, 18 Nov 2004 15:48:34 +0300 (#266854)

 

Исходные данные - html-файлы из существующего lindocs пропущенные через
скрипт "обиксээмеливания"...
Требуемые данные - сборка из xml обратно html... Дальнейший вид xml
(примерно как он будет выглядеть в будущем) приведен на сайте
http://kirov.lug.ru/wiki/RazrabotkaFormataLindocs

Ответить   Thu, 18 Nov 2004 16:18:59 +0300 (#266870)

 

Здравствуйте, Kolotov.

Вы писали 18 ноября 2004 г., 16:18:59:

Об этом проекте я знаю немного, видел только архивчик tbz2 на 700 МБ..
Вопрос что хочется получить в дальнейшем, просто из того что я
прочитал, вы не думаете, что получите больше проблем чем решите?
Расскажите поподробнее, или на форуме, а то он какой-то мёртвый
совсем.. Тогда можно будет конструктивно покритиковать :)

Ответить   Mon, 22 Nov 2004 12:44:26 +0300 (#268485)

 

тут я еще накатал небольшой материальчик - может понятнее станет... Если
нет - задавайте вопросы:

Некоторым уже известен проект lindocs - проект offline документации по
linux и unix-подобным системам. Сейчас он переживает переходный период,
когда базой ссылок стало уже неудобно управлять и производить по ней
навигацию.

Сейчас база представляет набор html-файлов, в которых собраны ссылки по
схожим (или не очень) тематикам. Основным является файл begin.html, в
котором хранятся ссылки на файлы-тем - html-страницы отвечающие за одну
какую-то тему. А уже в из файлах-тем хранятся ссылки на материалы,
хранящиеся в lindocs.

begin.html
| / Linux/Sendmail/pages/lessons.htm
mail.html - Linux/Sites/opennet.ru/base/net/mta_chouse.txt
| \ Linux/Sites/Perm_doc/tune/28.12.1998.html
|
bd.html
|
general.html
|
| / Linux/Docs/pdf/Python.pdf
python.html - Linux/Programing/Python/whats_new_22.html
\ Linux/Docs/pdf/samag12832-0.pdf

Проблема в том, что один материал может попадать в разные файлы-тем, так
как в нем могут затрагиваться различные аспекты настройки и управления
системой. Например, материал освещающий настройку почтового сервера с
хранением базы пользователей в какой-нибудь СУБД с использованием
скриптов для автоматического управления этой связкой - в данном случае
материал должен появиться сразу в трех разделах: "настройка почты",
"базы данных", "программирование". При ручном управлении базой ссылок
пришлось бы добавить ссылку на этот материал в три html-файла, что
вызывает избыточность, а также неочевидность и сложность поиска
дублирующихся материалов при добавлении новых.

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

INDEXES: mail, bd, programing, postfix, exim, fetchmail, mysql,
postgresql, perl, python, java

/ postfix / perl
mail - exim bd - mysql programing - python
\ fetchmail \ postrgesql \ java

При очередной публикации содержимого проекта lindocs эта куча ссылок
автоматически в соответствии с их индексами распределяется по множеству
html-файлов для offline просмотра документации.

Более подробно.

На текущий момент индексы можно получить из имени html-файла, в котором
упоминается тот или иной материал - этому материалу присваивается данный
индекс. В дальнейшем индекс у материала может быть изменен или даже
удален (материал без индекса также помещается в результирующую выборку и
помещается на основной странице проекта - так, например, очень удобно
следить за поступлением новых материалов). Чтобы не придумывать новые
индексы, которые будут использоваться для дальнейшей "продвинутой"
индексации, - можно использовать уже существующие в проекте opennet.ru:
индексы помещены в начале каждой статьи, оформленной как "*.txt", и они
легко получаются из этих файликов простым скриптом.

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

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

Также пользователь может добавлять и удалять (эту возможность нужно
оставить только для мантейнера проекта) материалы при работе с базой.

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

Чуть-чуть о реализации.

У материала в базе должны быть следующие атрибуты: название, автор(ы),
относительная ссылка - место в файловой системе, абсолютная ссылка -
место расположения материала в Интернет, один или несколько индексов, а
также служебные атрибуты (идентификатор записи, номер части, если
материал состоит из нескольких частей и др.). Абсолютная ссылка нужна
для того, чтобы можно было говорить об online версии проекта - ресурса,
на котором пользователь мог бы найти место положение в Интеренте
интересющей его информации.

Индекс в базе тоже имеет атрибуты: описание (будет выводиться как тема
обобщенных материалов) и родитель (значение индекса, которое
непосредственно указывает подтемой какой темы является данный индекс;
например, postfix - mail, mysql - bd)

При получении конечной информации (html-файлов) следует учитывать, что
если среди индексов материала есть "дерево" - и индекс-родитель и
индекс-потомок (не важно какой вложенности), то материал помещается
только один раз в тему индекса-потомка. Например, некоторый материал
имеет индексы "mail", "procmail", "filter", а индексы соотносятся
следующим образом: дерево "mail" -> "procmail", и отдельно "filter" -
значит, материал помещается в файлы "filter.html", "mail_procmail.html",
но не в "mail.html".

Смежные темы могут быть также перечислены в конце каждого из итоговых
файлов в зависимости от тех дополнительных индексов которые не относятся
на прямую к данной теме. Так если мы говорим про уже рассмотренный
пример, то в конце файла "filter.html" будет иметься ссылка на
"mail_procmail.html", а в конце "mail_procmail.html" - ссылка на
"filter.html".

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

Можно предложить следующие связки для программирования интерфейса: Java,
Python+GTK, Perl+GTK.

Что же выбрать в качестве хранилища для базы данных ссылок (не для
материалов)? Можно рассматривать как варианты:
1. XML
2. SQLite

О каждой поподробнее.

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

SQLite. "Это безтиповая, безсерверная (нет процесса-демона,
обрабатывающего запросы клиентов) СУБД, с поддержкой транзакций,
блокировок, триггеров, полного синтаксиса языка SQL92." Вся информация
базы данных хранится в одном файле специального формата. Работа с этим
файлом происходит на SQL-языке с помощью подключения специальных
библиотек (уже существующих для всех популярный языков программирования,
возможно даже выполнение SQL-запросов прямо из shell-скриптов). В
отличие от других СУБД с ним не нужно дополнительных плясок при переносе
базы в другое место. Как минус следует отметить необходимость
использования специального ПО для работы с базой.

Итак, подведем итог. Так как c XML плохо производить такие действия как
удаление и модификация, то в качестве БД можно использовать SQLite, а
XML использовать для хранения и перемещения изменений между разными
копиями проекта.

Ответить   Thu, 25 Nov 2004 10:31:38 +0300 (#270058)

 

ссылка на индексные статьи проекта:
http://kirov.lug.ru/projects/lindocs/index.shtml

Ответить   Thu, 25 Nov 2004 10:37:23 +0300 (#270062)