OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Вторник, 16 Апрель, 2024 20:07

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 27 ]  На страницу Пред.  1, 2
Автор Сообщение
 Заголовок сообщения: Re: YSon - Парсер/генератор JSON
СообщениеДобавлено: Четверг, 21 Ноябрь, 2013 22:37 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
На днях приступили к ударному склеиванию YSon и O3 Web Server с целью создания веб-сервиса внутри местной информсистемы.
Ну, REST, вот это всё.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: YSon - Парсер/генератор JSON
СообщениеДобавлено: Пятница, 22 Ноябрь, 2013 19:06 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
Наличие сменных записывателей серьёзно облегчает жизнь при подключении парсера к зоопарку источников байтов для буковок JSON, а наличие полуавтоматического генератора позволяет корректно и безошибочно формировать JSON-ответ без использования динамических структур объектной модели документа, заливая результирующие цепочки байтов прямо в буфер веб-сервера.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: YSon - Парсер/генератор JSON
СообщениеДобавлено: Пятница, 22 Ноябрь, 2013 19:18 
Администратор

Зарегистрирован: Вторник, 15 Ноябрь, 2005 01:14
Сообщения: 4695
Откуда: Россия, Орёл
Реализуете JSON-RPC?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: YSon - Парсер/генератор JSON
СообщениеДобавлено: Пятница, 22 Ноябрь, 2013 19:26 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
Да, реализуем. Прототип сделали, сервлет+разбор сообщения+запрос к БД+генерация ответного сообщения. Пока возможностей O3 хватает.
Только у нас не RPC, а REST.
Разница в подходах, в первом случае у веб-ресурса выдумывают методы, а во втором - веб-ресурсу надо считать сериализованные данные объектами. Ну, так я это понял.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: YSon - Парсер/генератор JSON
СообщениеДобавлено: Пятница, 22 Ноябрь, 2013 20:18 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
Реализация записывателей и конвертера:
Код:
MODULE some;

   IMPORT
      YSonConverters, YSonModels, YSonParser, YSonGenerator, O3baseFiles, StringsUtf;
   
   TYPE
      O3FileConv = POINTER TO RECORD (YSonConverters.Converter) END;
      
      O3FileReader = POINTER TO RECORD (YSonParser.Reader)
         base: O3baseFiles.File;
         rd: O3baseFiles.Reader;
      END;
      
      O3FileWriter = POINTER TO RECORD (YSonGenerator.Writer)
         wr: O3baseFiles.Writer;
      END;
   
   VAR
      conv: O3FileConv;
      
   PROCEDURE ReadUtf8Char(rd: O3baseFiles.Reader; OUT res: INTEGER): CHAR;
      VAR c: ARRAY 3 OF BYTE; ch: CHAR; len: INTEGER;
   BEGIN
      ASSERT(rd#NIL, 20);
      res:=0; ch:=0X;
      rd.Read(c[0]);
      len:=StringsUtf.ProposeUtf8Len(c[0]);
      IF (len>1) & ((rd.Pos()+len)<=rd.File().Len()) THEN
         rd.ReadBlock(c, 1, len-1, res);
         IF res=len-1 THEN
            StringsUtf.Utf8ToChar(c, ch);
         ELSE res:=-1 END;
      ELSE ch:=CHR(c[0]) END;
      RETURN ch;
   END ReadUtf8Char;
   
   PROCEDURE (r: O3FileReader) Read (OUT ch: CHAR): BOOLEAN;
      VAR res: INTEGER;
   BEGIN
      ASSERT(r.Base()#NIL, 20);
      res:=-1;
      IF ~r.rd.end THEN ch:=ReadUtf8Char(r.rd, res) END;
   RETURN (res>=0)
   END Read;
   
   PROCEDURE (r: O3FileReader) SetPos (x: INTEGER);
   BEGIN
      IF x<r.base.Len() THEN r.rd.PosSet(x) END;
   END SetPos;
   
   PROCEDURE (r: O3FileReader) Pos (): INTEGER;
   BEGIN
   RETURN r.rd.Pos()
   END Pos;
   
   PROCEDURE (r: O3FileReader) ConnectTo (source: ANYPTR);
   BEGIN
      ASSERT(source#NIL, 20);
      WITH source: O3baseFiles.File DO
         r.base:=source; r.rd:=r.base.RdNew();
         ASSERT(r.rd#NIL, 60)
      ELSE HALT(100) END;
   END ConnectTo;
   
   PROCEDURE (r: O3FileReader) Base (): ANYPTR;
   BEGIN
   RETURN r.base
   END Base;
   
   PROCEDURE (r: O3FileReader) Eot(): BOOLEAN;
   BEGIN
   RETURN r.rd.end;
   END Eot;
   
   PROCEDURE (w: O3FileWriter) Utf8Char (ch: CHAR), NEW;
      VAR i, len : INTEGER; x: ARRAY 3 OF BYTE;
   BEGIN   (* UTF-8 format *)
      len:=0;
      StringsUtf.Utf8FromChar(ch, x, len);
      FOR i:=0 TO len-1 DO w.wr.Write(x[i]) END;
   END Utf8Char;
   
   PROCEDURE (w: O3FileWriter) Char* (c: CHAR);
   BEGIN
      w.Utf8Char(c);
   END Char;
   
   PROCEDURE (w: O3FileWriter) Whitespace (s: ARRAY OF CHAR), EMPTY;
      
   PROCEDURE (c: O3FileConv) Supported(op: INTEGER; x: ANYPTR): BOOLEAN;
   BEGIN
   RETURN (x#NIL) & (x IS O3baseFiles.File)
   END Supported;
   
   PROCEDURE (c: O3FileConv) Load (source: ANYPTR; OUT res: INTEGER): YSonModels.Value;
      VAR p: YSonParser.Parser; rd: O3FileReader; x: ANYPTR; rs: YSonModels.Value;
   BEGIN
      ASSERT(source#NIL, 20);
      WITH source: O3baseFiles.File DO
         NEW(rd); rd.ConnectTo(source);
         p:=YSonParser.dir.New(rd);
         x:=p.Parse(res);
         IF x#NIL THEN
            WITH x: YSonModels.Value DO rs:=x
            ELSE HALT(100) END
         END;
      ELSE HALT(100) END;
      RETURN rs;
   END Load;
   
   PROCEDURE (c: O3FileConv) Store (v: YSonModels.Value; target: ANYPTR; OUT res: INTEGER);
      VAR g: YSonGenerator.Generator; wr: O3FileWriter;
   BEGIN
      res:=-1;
      NEW(wr);
      IF target # NIL THEN
         WITH target: O3baseFiles.File DO wr.SetBase(target); wr.wr:=target.WrNew() ELSE END;
      END;
      g:=YSonGenerator.dir.New(wr);
      g.ConnectTo(v);
      g.Generate;
   END Store;
   
   PROCEDURE NewWriter (target: O3baseFiles.File): YSonGenerator.Writer;
      VAR wr: O3FileWriter;
   BEGIN
      NEW(wr);
      IF target # NIL THEN
         wr.SetBase(target); wr.wr:=target.WrNew();
      END;
   RETURN wr;
   END NewWriter;
   
   PROCEDURE Install;
   BEGIN
      NEW(conv);
      YSonConverters.Install(conv);
   END Install;
   
BEGIN
   Install
CLOSE
   IF conv#NIL THEN YSonConverters.Remove(conv); conv:=NIL END;
END some

В реализацию O3-сервлета прилетает запрос O3stdWebServer.ServletMsg.rq, у которого есть поле body: O3baseFiles.File. Реализовав для такого источника байтов Reader/Writer, а поверх них конвертер мы получим возможность разобрать json с помощью конвертера, а так же записать громадный json в ответном сообщении O3-сервлета.
Конвертер может быть полезен тем, кто принимает маленькие json, их удобно превращать в модель из YSonModels и разбирать на месте, они же маленькие :)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: YSon - Парсер/генератор JSON
СообщениеДобавлено: Суббота, 23 Ноябрь, 2013 22:15 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
А вот пример генерации прямо в файл:
Код:
   IMPORT
      SqlDB, YSonFormatter, YSonFileConverter, Files;
      
   PROCEDURE DumpSome (tb: SqlDB.Table);
      VAR f: YSonFormatter.Formatter; file: Files.File; wr: YSonFileConverter.Writer; res, i, j: INTEGER; labels, data: SqlDB.Row;
   BEGIN      
      file:=Files.dir.Temp();
      wr:=YSonFileConverter.NewWriter(file);
      f:=YSonFormatter.dir.New(wr);
         f.WriteSym(YSonFormatter.objBegin, res);
            f.WriteName('data', res); f.WriteSym(YSonFormatter.arrBegin, res);
            i:=0;
            tb.Read(SqlDB.names, labels);
            IF labels.fields#NIL THEN
               WHILE i<tb.rows DO
                  f.WriteSym(YSonFormatter.objBegin, res);
                     tb.Read(i, data); j:=0;
                     WHILE j<tb.columns DO
                        f.WriteName(labels.fields[j], res);
                        f.WriteValue(YSonFormatter.stringVal, data.fields[j]$, res);
                        INC(j);
                     END;
                  f.WriteSym(YSonFormatter.objEnd, res);
                  INC(i)
               END;
            END;
            f.WriteSym(YSonFormatter.arrEnd, res);
         f.WriteSym(YSonFormatter.objEnd, res);
   END DumpSome;

Неверное форматирование сырца здесь показывает уровни вложенности в структуре json, чисто для ориентирования.
Здесь мы подаём команды механизму, который контролирует их корректность, а на выходе мы получаем файл с данными из таблицы.
Примерно вот такой:
Код:
{
   "data":[
      {"field": "value"},
      {"field": "value"}
   ]
}


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: YSon - Парсер/генератор JSON
СообщениеДобавлено: Понедельник, 25 Ноябрь, 2013 20:30 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
Пётр Кушнир писал(а):
Реализация записывателей и конвертера:
Оказывается, у меня была не финальная версия веб-сервера от О3, они там немного поменяли интерфейс в финальной версии, поэтому выкладаю актуальный конвертер.
Код:
MODULE some;
   IMPORT
      YSonConverters, YSonModels, YSonParser, YSonGenerator, O3baseFiles, StringsUtf;
      
   CONST
      thisContentType* = 'application';
      thisContentSubtype* = 'json';
   
   TYPE
      O3FileConv = POINTER TO RECORD (YSonConverters.Converter) END;
      
      O3FileReader = POINTER TO RECORD (YSonParser.Reader)
         base: O3baseFiles.File;
         rd: O3baseFiles.Reader;
      END;
      
      O3FileWriter = POINTER TO RECORD (YSonGenerator.Writer)
         wr: O3baseFiles.Writer;
      END;
   
   VAR
      conv: O3FileConv;
      
   PROCEDURE ReadUtf8Char(rd: O3baseFiles.Reader; OUT res: INTEGER): CHAR;
      VAR c: ARRAY 3 OF BYTE; ch: CHAR; len: INTEGER;
   BEGIN
      ASSERT(rd#NIL, 20);
      res:=0; ch:=0X;
      rd.Byte(c[0]);
      len:=StringsUtf.ProposeUtf8Len(c[0]);
      IF (len>1) & ((rd.Pos()+len)<=rd.File().Len()) THEN
         rd.Block(c, 1, len-1, res);
         IF res=len-1 THEN
            StringsUtf.Utf8ToChar(c, ch);
         ELSE res:=-1 END;
      ELSE ch:=CHR(c[0]) END;
      RETURN ch;
   END ReadUtf8Char;
   
   PROCEDURE (r: O3FileReader) Read- (OUT ch: CHAR): BOOLEAN;
      VAR res: INTEGER;
   BEGIN
      ASSERT(r.Base()#NIL, 20);
      res:=-1;
      IF ~r.rd.end THEN ch:=ReadUtf8Char(r.rd, res) END;
   RETURN (res>=0)
   END Read;
   
   PROCEDURE (r: O3FileReader) SetPos- (x: INTEGER);
   BEGIN
      IF x<r.base.Len() THEN r.rd.PosSet(x) END;
   END SetPos;
   
   PROCEDURE (r: O3FileReader) Pos* (): INTEGER;
   BEGIN
   RETURN r.rd.Pos()
   END Pos;
   
   PROCEDURE (r: O3FileReader) ConnectTo* (source: ANYPTR);
   BEGIN
      ASSERT(source#NIL, 20);
      WITH source: O3baseFiles.File DO
         r.base:=source; r.rd:=r.base.RdNew();
         ASSERT(r.rd#NIL, 60)
      ELSE HALT(100) END;
   END ConnectTo;
   
   PROCEDURE (r: O3FileReader) Base* (): ANYPTR;
   BEGIN
   RETURN r.base
   END Base;
   
   PROCEDURE (r: O3FileReader) Eot*(): BOOLEAN;
   BEGIN
   RETURN r.rd.end;
   END Eot;
   
   PROCEDURE (w: O3FileWriter) Utf8Char (ch: CHAR), NEW;
      VAR i, len : INTEGER; x: ARRAY 3 OF BYTE;
   BEGIN   (* UTF-8 format *)
      len:=0;
      StringsUtf.Utf8FromChar(ch, x, len);
      FOR i:=0 TO len-1 DO w.wr.Byte(x[i]) END;
   END Utf8Char;
   
   PROCEDURE (w: O3FileWriter) Char* (c: CHAR);
   BEGIN
      w.Utf8Char(c);
   END Char;
   
   PROCEDURE (w: O3FileWriter) Whitespace* (s: ARRAY OF CHAR), EMPTY;
      
   PROCEDURE (c: O3FileConv) Supported(op: INTEGER; x: ANYPTR): BOOLEAN;
   BEGIN
   RETURN (x#NIL) & (x IS O3baseFiles.File) (* потенциально опасно *)
   END Supported;
   
   PROCEDURE (c: O3FileConv) Load (source: ANYPTR; OUT res: INTEGER): YSonModels.Value;
      VAR p: YSonParser.Parser; rd: O3FileReader; x: ANYPTR; rs: YSonModels.Value;
   BEGIN
      ASSERT(source#NIL, 20);
      WITH source: O3baseFiles.File DO
         NEW(rd); rd.ConnectTo(source);
         p:=YSonParser.dir.New(rd);
         x:=p.Parse(res);
         IF x#NIL THEN
            WITH x: YSonModels.Value DO rs:=x
            ELSE HALT(100) END
         END;
      ELSE HALT(100) END;
      RETURN rs;
   END Load;
   
   PROCEDURE (c: O3FileConv) Store (v: YSonModels.Value; target: ANYPTR; OUT res: INTEGER);
      VAR g: YSonGenerator.Generator; wr: O3FileWriter;
   BEGIN
      res:=-1;
      NEW(wr);
      IF target # NIL THEN
         WITH target: O3baseFiles.File DO wr.SetBase(target); wr.wr:=target.WrNew() ELSE END;
      END;
      g:=YSonGenerator.dir.New(wr);
      g.ConnectTo(v);
      g.Generate;
   END Store;
   
   PROCEDURE NewWriter* (target: O3baseFiles.File): YSonGenerator.Writer;
      VAR wr: O3FileWriter;
   BEGIN
      NEW(wr);
      IF target # NIL THEN
         wr.SetBase(target); wr.wr:=target.WrNew();
      END;
   RETURN wr;
   END NewWriter;
   
   PROCEDURE Install;
   BEGIN
      NEW(conv);
      YSonConverters.Install(conv);
   END Install;
   
BEGIN
   Install
CLOSE
   IF conv#NIL THEN YSonConverters.Remove(conv); conv:=NIL END;
END some


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 27 ]  На страницу Пред.  1, 2

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4


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

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB