CftClub.ru
Клуб специалистов ЦФТ-Банк

Простой разбор документов XML
На страницу 1, 2, 3  След.
 
Ответить на тему    Клуб специалистов ЦФТ-Банк (IBSO) -> Справочник PL/PLUS: Функции, примеры, приёмы
Предыдущая тема :: Следующая тема  
Автор Сообщение
dnk_dz
Эксперт


Вступление в Клуб: 19.09.2007
СообщениеПн Сен 14, 2009 11:44   Простой разбор документов XML Ответить с цитатой
Полезность: 5
Может, кому пригодится.
Недавно столкнулся с проблемой разбора различных видов XML документов. После написания километров кода для разбора каждого XML документа в отдельности, пришел к мысли, что в таком темпе я буду долго писать обработку десятка XML документов. А если нужно будет добавить обработку еще двадцати? В общем, пришли к мысли, что проще XML выгрузить в PL/SQL таблицу и ее уже обрабатывать. Так оказалось гораздо проще.

Ниже приведен код пакета, который разбирает xml из строки и заполняет два массива (PL/SQL таблицы):
1. XML_values - содержит значения узлов.
Структура таблицы следующая:
self_id - Уникальный ID узла
name - Полное имя узла.
value - Значение узла.
2. XML_attributes - содержит значения атрибутов узлов.
self_id - Уникальный ID атрибута
collection_id - ID узла из таблицы XML_values.
name - Полное имя атрибута. Включает имя узла.
value - Значение атрибута.
dnk_dz
Эксперт


Вступление в Клуб: 19.09.2007
СообщениеПн Сен 14, 2009 11:45    Ответить с цитатой
Полезность: Нет оценки
Глобальные описания:

Код:

pragma macro(xml, '::[RUNTIME].[XML_DOM]');

type t_XML_record is record (
   self_id         number,
   name            varchar2(4000),
   value            varchar2(4000)
);

type t_XML_attr is record (
   self_id         number,
   collection_id   number,
   name            varchar2(4000),
   value            varchar2(4000)
);

type t_XML_values is table of t_XML_record;      -- Тип Таблица значений тегов XML
type t_XML_attributes is table of t_XML_attr;   -- Тип Таблица значений атрибутов XML

-- Процедура разбирает XML и возвращает таблицы значений тегов и атрибутов XML
procedure parse_buffer(doc in varchar2(32767), xml_values out t_XML_values, xml_attributes out t_XML_attributes);
-- Обход дерева XML
procedure parse(node in &xml.DOMNode, lvl in varchar2, xml_values in out t_XML_values, xml_attributes in out t_XML_attributes);
-- Возвращает значение для узла XML из таблицы xml_values
function get_node_value(node_name in varchar2(4000), xml_values in t_XML_values) return varchar2(4000);

dnk_dz
Эксперт


Вступление в Клуб: 19.09.2007
СообщениеПн Сен 14, 2009 11:46    Ответить с цитатой
Полезность: Нет оценки
Локальные описания:
Код:


-- Возвращает значение для узла XML из таблицы xml_values
function get_node_value(node_name in varchar2(4000), xml_values in t_XML_values) return varchar2(4000) is
   ret_val   varchar2(4000);
begin
   ret_val := '';
   
   for i in 1..xml_values.count
   loop
      if upper(xml_values(i).name) = upper(node_name) then
         ret_val := xml_values(i).value;
         exit;
      end if;
   end loop;
   
   return ret_val;
end;

-- Процедура разбирает XML и возвращает таблицы значений тегов и атрибутов XML
procedure parse_buffer(doc in varchar2(32767), xml_values out t_XML_values, xml_attributes out t_XML_attributes) is
   xmldoc      &xml.DOMDocument;
   parser       &xml.Parser;   
   p_node      &xml.DOMNode;
   child         &xml.DOMNode;   
begin   
   xml_values.delete;
   xml_attributes.delete;
   
   &xml.initialize;
   parser := &xml.newParser;
   
   &xml.parseBuffer(parser, doc);
   
   xmldoc       := &xml.getDocument(parser);
   p_node      := &xml.makeNode(xmldoc);
   child       := &xml.getFirstChild(p_node);

   parse(child, '/', xml_values, xml_attributes);

   -- Отладка - вывод содержимого таблиц
   for i in 1..xml_values.count
   loop
      stdio.put_line_buf(xml_values(i).self_id||'. '||xml_values(i).name||' = '||xml_values(i).value);
   end loop;
   
   for i in 1..xml_attributes.count
   loop
      stdio.put_line_buf(xml_attributes(i).collection_id||'.'||xml_attributes(i).self_id||'. '||xml_attributes(i).name||' = '||xml_attributes(i).value);
   end loop;
   
end;

-- Обход дерева XML
procedure parse(node in &xml.DOMNode, lvl in varchar2, xml_values in out t_XML_values, xml_attributes in out t_XML_attributes) is
   cur_node         &xml.DOMNode;
   child_node      &xml.DOMNode;
   val_node       &xml.DOMNode;
   AttrMap          &xml.DOMNamedNodeMap;

   node_name      varchar2(1000);
   node_val         varchar2(1000);
   values_id      number;
   attr_id         number;
begin
   cur_node      := node;
   values_id   := xml_values.count + 1;

   while not &xml.isNull(cur_node)
   loop
      node_name := &xml.getNodeName(cur_node);
      
      val_node   := &xml.getFirstChild(cur_node);
      node_val   := replace(replace(&xml.getNodeValue(val_node), chr(10), ''), chr(13), '');
      
      AttrMap   :=   &xml.getAttributes(cur_node);
      
      if node_name = '#text' then
         cur_node := &xml.getNextSibling(cur_node);
         continue;      
      end if;
      
      xml_values(values_id).self_id := values_id;
      xml_values(values_id).name      := lvl||node_name||'/';
      xml_values(values_id).value   := node_val;
      
      attr_id := xml_attributes.count + 1;
      
      for i in 0..&xml.getLength(AttrMap) - 1
      loop   
         xml_attributes(attr_id).self_id         := attr_id;
         xml_attributes(attr_id).collection_id   := values_id;
         xml_attributes(attr_id).name            := lvl||node_name||'/'||&xml.getNodeName(&xml.item(AttrMap, i));
         xml_attributes(attr_id).value            := &xml.getNodeValue(&xml.item(AttrMap, i));

         attr_id                                  := attr_id + 1;
      end loop;
      
      child_node := &xml.getFirstChild(cur_node);
      parse(child_node, lvl||node_name||'/', xml_values, xml_attributes);

      cur_node    := &xml.getNextSibling(cur_node);      
      values_id   := xml_values.count + 1;      
   end loop;      
end;

dnk_dz
Эксперт


Вступление в Клуб: 19.09.2007
СообщениеВт Сен 15, 2009 05:30    Ответить с цитатой
Полезность: Нет оценки
Пример XML:

Код:

<?xml version="1.0" encoding="utf-8" ?>
<Root>
   <Record>
      <FIO>Иванов Иван Иванович</FIO>
      <SEX>M</SEX>
      <PASNOM>11 22 333333</PASNOM>
      <ACCOUNTS>
         <ACCOUNT NO="22222222222222222222" A2TSTAT="1" A2CDESC="Депозит"/>
         <ACCOUNT NO="40817810200000000079" A2TSTAT="3" A2CDESC="Текущий"/>
      </ACCOUNTS>
   </Record>
</Root>


Результат (содержимое PL/SQL таблиц)

Код:

xml_values:
ID Name                           Value
--------------------------------------------------------
1  /Root/     
2  /Root/Record/        
3  /Root/Record/FIO/               Иванов Иван Иванович
4  /Root/Record/SEX/               M
5  /Root/Record/PASNOM/            11 22 333333
6  /Root/Record/ACCOUNTS/           
7  /Root/Record/ACCOUNTS/ACCOUNT/ 
8  /Root/Record/ACCOUNTS/ACCOUNT/ 

xml_attributes:
COLLECTION_ID  ID Name                                    Value
-------------------------------------------------------------------------------
7              1  /Root/Record/ACCOUNTS/ACCOUNT/A2CDESC   Депозит
7              2  /Root/Record/ACCOUNTS/ACCOUNT/A2TSTAT   1
7              3  /Root/Record/ACCOUNTS/ACCOUNT/NO        22222222222222222222
8              4  /Root/Record/ACCOUNTS/ACCOUNT/A2CDESC   Текущий
8              5  /Root/Record/ACCOUNTS/ACCOUNT/A2TSTAT   3
8              6  /Root/Record/ACCOUNTS/ACCOUNT/NO        40817810200000000079
Volod
Эксперт


Вступление в Клуб: 19.09.2007
СообщениеВт Сен 15, 2009 10:38    Ответить с цитатой
Полезность: Нет оценки
Тогда уж, чтобы циклы не крутить,
type t_XML_values is table of t_XML_record index by varchar2,
где index содержит name
dnk_dz
Эксперт


Вступление в Клуб: 19.09.2007
СообщениеВт Сен 15, 2009 10:55    Ответить с цитатой
Полезность: Нет оценки
Volod пишет:
Тогда уж, чтобы циклы не крутить,
type t_XML_values is table of t_XML_record index by varchar2,
где index содержит name

Тогда мы теряем однозначную связку узла с атрибутами. Так, в примере
есть два узла с именем /Root/Record/ACCOUNTS/ACCOUNT/. Чтобы получить атрибуты для конкретного узла ACCOUNT из xml_attributes необходимо однозначно идентифицировать этот узел. Для этого и служит self_id в xml_values - collection_id в xml_attributes равен self_id в xml_values. Например, для узла ACCOUNT с ID = 7 атрибут A2CDESC равен "Депозит".
Volod
Эксперт


Вступление в Клуб: 19.09.2007
СообщениеВт Сен 15, 2009 11:07    Ответить с цитатой
Полезность: 1
И пусть служит self_id в xml_values , он же останется в таблице. Тут вопрос, наверное, в способе обработке xml_values. Либо один раз последовательно по узлам, либо поиск по избранным узлам.
dnk_dz
Эксперт


Вступление в Клуб: 19.09.2007
СообщениеВт Сен 15, 2009 11:19    Ответить с цитатой
Полезность: Нет оценки
Volod пишет:
И пусть служит self_id в xml_values , он же останется в таблице. Тут вопрос, наверное, в способе обработке xml_values. Либо один раз последовательно по узлам, либо поиск по избранным узлам.

Согласен
dnk_dz
Эксперт


Вступление в Клуб: 19.09.2007
СообщениеСр Сен 30, 2009 08:29    Ответить с цитатой
Полезность: 1
Обновленная версия пакета.
Добавлена функция для разбора XML из файла.
Добавлено описание (в глобальных описаниях).
Исправлена ошибка преобразования XML с наличием тега xml-stylesheet.
Ниже находится текст пакета.
dnk_dz
Эксперт


Вступление в Клуб: 19.09.2007
СообщениеСр Сен 30, 2009 08:30    Ответить с цитатой
Полезность: 1
Глобальные описания:

Код:

pragma macro(xml, '::[RUNTIME].[XML_DOM]');

/* Автор: Корпушов Д.Н.
   Описание:
      Пакет предназначен для упрощения разбора XML.
      Результат разбора XML помещается в две PL/SQL - таблицы (массива) типов t_XML_values и t_XML_attributes.
      
      В таблицу t_XML_values помещаются значения тегов. Таблица имеет следующую структуру:
         self_id   - Уникальный ID тега. Генерируется автоматически.
         name      - Полное имя тега.
         value    - Значение тега.
      
      В таблицу t_XML_attributes помещаются атрибуты тегов.    Таблица имеет следующую структуру:
         self_id         - Уникальный ID атрибута. Генерируется автоматически.
         collection_id   - Ссылка на конкретный тег, к которому относится атрибут (содержит self_id из таблицы t_XML_values)
         name            - Полное имя атрибута. Включает в себя имя тега.
         value            - Значение атрибута.

   Пакет имеет две интерфейсные функции:
      parse_buffer(doc in varchar2(32767), xml_values out t_XML_values, xml_attributes out t_XML_attributes)
         Разбирает XML из строки, переданной в параметре doc. Результат разбора помещается
         в выходные параметры xml_values и xml_attributes.
         
      parse_file(xml_file_name in varchar2(256), xml_values out t_XML_values, xml_attributes out t_XML_attributes)
         Разбирает XML из файла. Полное имя файла передается в параметре xml_file_name. Результат разбора помещается
         в выходные параметры xml_values и xml_attributes.

   Пример вызова:
      declare
         xml_values [KOU_XML].t_XML_values;
         xml_attributes [KOU_XML].t_XML_attributes;
         xml_file_name   varchar2(256);
      begin
         xml_file_name := './test.xml';
         [KOU_XML].parse_file(xml_file_name, xml_values, xml_attributes);

         stdio.put_line_buf('Массив xml_values');
         for i in 1..xml_values.count
         loop
            stdio.put_line_buf(xml_values(i).self_id||'. '||xml_values(i).name||' = '||xml_values(i).value);
         end loop;

         stdio.put_line_buf('Массив xml_attributes');
         for i in 1..xml_attributes.count
         loop
            stdio.put_line_buf(xml_attributes(i).collection_id||'.'||xml_attributes(i).self_id||'. '||xml_attributes(i).name||' = '||xml_attributes(i).value);
         end loop;         
      end;               

   Пример результата работы.
   XML:
      <?xml version="1.0" encoding="utf-8" ?>
      <Root>
         <Record>
            <FIO>Иванов Иван Иванович</FIO>
            <SEX>M</SEX>
            <PASNOM>11 22 333333</PASNOM>
            <ACCOUNTS>
               <ACCOUNT NO="22222222222222222222" A2TSTAT="1" A2CDESC="Депозит"/>
               <ACCOUNT NO="40817810200000000079" A2TSTAT="3" A2CDESC="Текущий"/>
            </ACCOUNTS>
         </Record>
      </Root>
      
   Результат разбора:
      xml_values:
         ID Name                           Value
         --------------------------------------------------------
         1  /Root/
         2  /Root/Record/
         3  /Root/Record/FIO/               Иванов Иван Иванович
         4  /Root/Record/SEX/               M
         5  /Root/Record/PASNOM/            11 22 333333
         6  /Root/Record/ACCOUNTS/
         7  /Root/Record/ACCOUNTS/ACCOUNT/
         8  /Root/Record/ACCOUNTS/ACCOUNT/

         xml_attributes:
         COLLECTION_ID  ID Name                                    Value
         -------------------------------------------------------------------------------
         7              1  /Root/Record/ACCOUNTS/ACCOUNT/A2CDESC   Депозит
         7              2  /Root/Record/ACCOUNTS/ACCOUNT/A2TSTAT   1
         7              3  /Root/Record/ACCOUNTS/ACCOUNT/NO        22222222222222222222
         8              4  /Root/Record/ACCOUNTS/ACCOUNT/A2CDESC   Текущий
         8              5  /Root/Record/ACCOUNTS/ACCOUNT/A2TSTAT   3
         8              6  /Root/Record/ACCOUNTS/ACCOUNT/NO        40817810200000000079

*/

type t_XML_record is record (
   self_id         number,
   name            varchar2(4000),
   value            varchar2(4000)
);

type t_XML_attr is record (
   self_id         number,
   collection_id   number,
   name            varchar2(4000),
   value            varchar2(4000)
);

type t_XML_values is table of t_XML_record;      -- Тип Таблица значений тегов XML
type t_XML_attributes is table of t_XML_attr;   -- Тип Таблица значений атрибутов XML

-- Процедура разбирает XML из буфера и возвращает таблицы значений тегов и атрибутов XML
procedure parse_buffer(doc in varchar2(32767), xml_values out t_XML_values, xml_attributes out t_XML_attributes);

-- Процедура разбирает XML из файла и возвращает таблицы значений тегов и атрибутов XML
procedure parse_file(xml_file_name in varchar2(255), xml_values out t_XML_values, xml_attributes out t_XML_attributes);

-- Обход дерева XML
procedure parse(node in &xml.DOMNode, lvl in varchar2, xml_values in out t_XML_values, xml_attributes in out t_XML_attributes);
-- Возвращает значение для узла XML из таблицы xml_values
function get_node_value(node_name in varchar2(4000), xml_values in t_XML_values) return varchar2(4000);

dnk_dz
Эксперт


Вступление в Клуб: 19.09.2007
СообщениеСр Сен 30, 2009 08:32    Ответить с цитатой
Полезность: 1
Локальные описания:
Код:

-- Возвращает значение для узла XML из таблицы xml_values
function get_node_value(node_name in varchar2(4000), xml_values in t_XML_values) return varchar2(4000) is
   ret_val varchar2(4000);
begin
   ret_val := '';

   for i in 1..xml_values.count
   loop
      if upper(xml_values(i).name) = upper(node_name) then
         ret_val := xml_values(i).value;
         exit;
      end if;
   end loop;

   return ret_val;
end;

-- Процедура разбирает XML из файла и возвращает таблицы значений тегов и атрибутов XML
procedure parse_file(xml_file_name in varchar2(255), xml_values out t_XML_values, xml_attributes out t_XML_attributes) is
   xmldoc   &xml.DOMDocument;
   parser   &xml.Parser;
   p_node   &xml.DOMNode;
   child      &xml.DOMNode;
begin
   xml_values.delete;
   xml_attributes.delete;

   &xml.initialize;
   parser := &xml.newParser;

   &xml.parse(parser, xml_file_name);

   xmldoc   := &xml.getDocument(parser);
   p_node   := &xml.makeNode(xmldoc);
   child      := &xml.getFirstChild(p_node);
   if lower(&xml.getNodeName(child)) = 'xml-stylesheet' then
      child := &xml.getNextSibling(child);
   end if;
   parse(child, '/', xml_values, xml_attributes);
   /*
   -- Отладка - вывод содержимого таблиц
   for i in 1..xml_values.count
   loop
      stdio.put_line_buf(xml_values(i).self_id||'. '||xml_values(i).name||' = '||xml_values(i).value);
   end loop;

   for i in 1..xml_attributes.count
   loop
      stdio.put_line_buf(xml_attributes(i).collection_id||'.'||xml_attributes(i).self_id||'. '||xml_attributes(i).name||' = '||xml_attributes(i).value);
   end loop;
   */
end;

-- Процедура разбирает XML и возвращает таблицы значений тегов и атрибутов XML
procedure parse_buffer(doc in varchar2(32767), xml_values out t_XML_values, xml_attributes out t_XML_attributes) is
   xmldoc      &xml.DOMDocument;
   parser       &xml.Parser;
   p_node      &xml.DOMNode;
   child         &xml.DOMNode;
begin
   xml_values.delete;
   xml_attributes.delete;

   &xml.initialize;
   parser := &xml.newParser;

   &xml.parseBuffer(parser, doc);

   xmldoc   := &xml.getDocument(parser);
   p_node   := &xml.makeNode(xmldoc);
   child      := &xml.getFirstChild(p_node);

   if lower(&xml.getNodeName(child)) = 'xml-stylesheet' then
      child := &xml.getNextSibling(child);
   end if;

   parse(child, '/', xml_values, xml_attributes);

   /*
   -- Отладка - вывод содержимого таблиц
   for i in 1..xml_values.count
   loop
      stdio.put_line_buf(xml_values(i).self_id||'. '||xml_values(i).name||' = '||xml_values(i).value);
   end loop;

   for i in 1..xml_attributes.count
   loop
      stdio.put_line_buf(xml_attributes(i).collection_id||'.'||xml_attributes(i).self_id||'. '||xml_attributes(i).name||' = '||xml_attributes(i).value);
   end loop;
   */
end;

-- Обход дерева XML
procedure parse(node in &xml.DOMNode, lvl in varchar2, xml_values in out t_XML_values, xml_attributes in out t_XML_attributes) is
   cur_node      &xml.DOMNode;
   child_node   &xml.DOMNode;
   val_node      &xml.DOMNode;
   AttrMap      &xml.DOMNamedNodeMap;

   node_name   varchar2(1000);
   node_val      varchar2(1000);
   values_id   number;
   attr_id      number;
begin
   cur_node      := node;
   values_id   := xml_values.count + 1;

   while not &xml.isNull(cur_node)
   loop
      node_name   := &xml.getNodeName(cur_node);
      val_node      := &xml.getFirstChild(cur_node);
      node_val      := replace(replace(&xml.getNodeValue(val_node), chr(10), ''), chr(13), '');
      AttrMap      := &xml.getAttributes(cur_node);

      if node_name = '#text' then
         cur_node := &xml.getNextSibling(cur_node);
         continue;
      end if;

      xml_values(values_id).self_id   := values_id;
      xml_values(values_id).name      := lvl||node_name||'/';
      xml_values(values_id).value   := node_val;

      attr_id := xml_attributes.count + 1;

      for i in 0..&xml.getLength(AttrMap) - 1
      loop
         xml_attributes(attr_id).self_id         := attr_id;
         xml_attributes(attr_id).collection_id   := values_id;
         xml_attributes(attr_id).name            := lvl||node_name||'/'||&xml.getNodeName(&xml.item(AttrMap, i));
         xml_attributes(attr_id).value            := &xml.getNodeValue(&xml.item(AttrMap, i));
         attr_id                                 := attr_id + 1;
      end loop;

      child_node := &xml.getFirstChild(cur_node);
      parse(child_node, lvl||node_name||'/', xml_values, xml_attributes);

      cur_node      := &xml.getNextSibling(cur_node);
      values_id   := xml_values.count + 1;
   end loop;
end;

dumpino
Участник со стажем


Вступление в Клуб: 13.12.2011
СообщениеВт Фев 14, 2012 06:03    Ответить с цитатой
Полезность: Нет оценки
привет, друзья!

на дворе 2012 год, а последний пост по разбору XML файлов от 2009 года.

Я хотел узнать, какие сейчас следует использовать библиотеки для чтения/создания XML файлов (записей ожидается от 1 до 100, атрибутов тоже не много)?

пока то что я нарыл это: XML_DOM, XML, и TRANS_LIB_XML (в этом не уверенSmile

Как вам описанный пример выше?

спасибо за любые наводки.
dnk_dz
Эксперт


Вступление в Клуб: 19.09.2007
СообщениеВт Фев 14, 2012 07:18    Ответить с цитатой
Полезность: Нет оценки
dumpino пишет:

на дворе 2012 год, а последний пост по разбору XML файлов от 2009 года.


Боюсь ошибиться, но думаю, что особых изменений не произошло с тех пор, правда с дистрибутивом IBSO последние два года не работал.

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

Как показала моя практика использования xml в IBSO, да и не только, - самый простой и эффективный способ создания xml - через обычную строковую переменную без использования парсера/модели.
maestro
Профи


Вступление в Клуб: 12.10.2010
СообщениеВт Фев 14, 2012 08:18    Ответить с цитатой
Полезность: Нет оценки
dumpino пишет:
привет, друзья!

на дворе 2012 год, а последний пост по разбору XML файлов от 2009 года.

Я хотел узнать, какие сейчас следует использовать библиотеки для чтения/создания XML файлов (записей ожидается от 1 до 100, атрибутов тоже не много)?

пока то что я нарыл это: XML_DOM, XML, и TRANS_LIB_XML (в этом не уверенSmile

Как вам описанный пример выше?

спасибо за любые наводки.


Я пользуюсь стандартными Оракловыми XMLType и DBMS_XMLDOM. Постоянно использую XSLT-преобразование. В качестве отладчика XSLT - Altova XML spy.

Достоинства - быстро и удобно!
Недостатки: отсутствие поддержки со стороны PL+, приходится использовать PL/SQL вставки. Не понимаю почему ЦФТ использует какие-то левые библиотеки для парсинга XML, и не добавит в спецификацию PL+ обертку для стандартных оракловых конструкций.
maestro
Профи


Вступление в Клуб: 12.10.2010
СообщениеВт Фев 14, 2012 08:29    Ответить с цитатой
Полезность: 1
dnk_dz пишет:
самый простой и эффективный способ создания xml - через обычную строковую переменную без использования парсера/модели.


!! Не вздумайте так делать!!
Дело в том, что при создании XML стандартным парсером, выходной XML получается валидным! Разработчику нет нужды заморачиваться экранированием спецсимволов, вложенныхь XML-конструкций, кодировками и прочей херью, которая может не отвалидироваться на стороне приёмника. Стандартный парсер просто не даст Вам создать невалидный XML!

Собирать XML c F1 конкатенации в наше время - сродни каменному топору.
ИМХО, лучше потратить некоторое количество времени на изучение XML+XSD+XSLT, и затем эффективно пользоваться этими инструментами. Они дают возможность БЫСТРО создавать НАДЕЖНЫЕ приложения.
Показать сообщения:   
Ответить на тему    Клуб специалистов ЦФТ-Банк (IBSO) -> Справочник PL/PLUS: Функции, примеры, приёмы Часовой пояс: GMT + 3
На страницу 1, 2, 3  След.
Страница 1 из 3

 
Перейти:  
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Рейтинг@Mail.ru