Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Создание строки JSON на си  (Прочитано 14000 раз)
0 Пользователей и 1 Гость смотрят эту тему.
pokk
Помогающий

ru
Offline Offline

« : 25-01-2016 10:04 » 

Добрый день, подскажите какие функции должны использоваться, что бы можно было сформировать такую строку ключ значене.
Код:
{
  "orderID": 12345,
  "shopperName": "Ваня Иванов",
  "shopperEmail": "ivanov@example.com",
  "contents": [
    {
      "productID": 34,
      "productName": "Супер товар",
      "quantity": 1
    },
    {
      "productID": 56,
      "productName": "Чудо товар",
      "quantity": 3
    }
  ],
  "orderCompleted": true
}
Я частично создал велосипед для формирования ключ значения и он меня более менее устраивает, но как дошёл до массива тут всё если в ручную ещё хоть что-то получается,а при проходе циклом уже нет всё разваливается(непонятно когда надо закрывать его).

Вот хотелось бы по смотреть как это делают по фэншую.
   
Записан
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 25-01-2016 10:53 » 

Код с циклом в студию. Без этого непонятно, где сложность возникает.
Записан
pokk
Помогающий

ru
Offline Offline

« Ответ #2 : 25-01-2016 12:13 » 

Сейчас нету доступа к коду с циклом, но примерно у меня такой колхоз.
Код:
index=MakeStr_int(buf,index,"Pout:",',',THttpPageConfing.Pout);
index=MakeStr_text(buf,index,"NameOfTheUnit:",',',THttpPageConfing.NameOfTheUnit);
index=MakeStr_text(buf,index,"IP:",',',THttpPageConfing.IP);
*file_len+=MakeStr_text(buf,index,"SerNumber:",',',THttpPageConfing.SerNumber);
Не большая проблема возникает с определением места  постановки "]," но это всё из за того что добавление новой пары ключ значение сделано через ж, а как правильно не могу придумать.




Записан
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 25-01-2016 12:58 » 

pokk, какой смысл несёт index - текущее место в буфере?
Задачу формирования строки можно разбить на составляющие примерно так (на глаз и без учёта обработки ошибок и проверки границ):
Код:
char * itemToStr(char * buf, const ItemType * item)
{
    buf += sprintf(buf, "\"%s:\"", item->name);
    if (typeof(item->value) == /*атомарный тип*/) {
         buf += sprintf(buf, "%format", item->value);
    }
    else{ // массив:
         *buf++ = '[';
         for (/*перебираем элементы item->value*/) {
             buf = itemToStr(buf, subitem);
             // добавляем разделитель по необходимости
         }
         *buf++ = ']';
    }
    return buf;
}
плюс для словаря вставить аналогичное массиву, или я что-то упустил?
Вроде бы, можно сделать попроще, если поступиться эффективностью и под каждый элемент отдельную строку создавать.
« Последнее редактирование: 25-01-2016 13:03 от Вад » Записан
pokk
Помогающий

ru
Offline Offline

« Ответ #4 : 25-01-2016 14:14 » 

itemToStr рекурсивная функция?
Я что-то похожее начинал делать но не допёр как быть с разным форматом Value, теперь вроде понял что надо всё в строку переводить а потом добавлять(я пытался сразу два действия делать).
По этому меня интересуют вот эти моменты 
Что за типа и что он там ещё содержит или может содержать кроме value
Код:
const ItemType * item
И
Код:
if (typeof(item->value) == /*атомарный тип*/) {
         buf += sprintf(buf, "%format", item->value);
    }
Это как-то совсем не понятно для чего.
Цитата
плюс для словаря вставить аналогичное массиву, или я что-то упустил?
Вроде бы, можно сделать попроще, если поступиться эффективностью и под каждый элемент отдельную строку создавать
Тоже не понятно =((
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 25-01-2016 14:47 » 

По моему нужно исходить из формата:
1) фиксированный формат или формат неизвестен?
2) нафига нам неизвестный формат?

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

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
pokk
Помогающий

ru
Offline Offline

« Ответ #6 : 25-01-2016 15:00 » new

Формат чего? Значений?
То его несколько:
1) Текст
2) char,Int
3) IP(массив из 4х байт)
Записан
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 25-01-2016 21:11 » 

itemToStr рекурсивная функция?
да, но это не так важно, важен принцип: "если одно - делаем так, если другое - оборачиваем в скобки, в середине делаем цикл, внутри цикла сводим задачу к предыдущей" (в качестве решения первой задачи можно ведь и вашими MakeStr_int/MakeStr_text пользоваться).

Цитата
Что за типа и что он там ещё содержит или может содержать кроме value
тут универсальный тип может быть (мы ведь про язык Си), я себе представил что-то вроде
Код:
typedef struct {
    char * name;
    int type;
    void * value;
} ItemType;
- ну, может, void * на union можно заменить, содержащий int/void*
Это всё тоже не особо важно, просто был вопрос про "как бы стали делать" — я бы стал как-то так (но я на Си почти не пишу, может, кто и лучше предложит).
Соответственно, на деле там был бы switch по значению type (например, INT/DOUBLE/STR/ARRAY/DICT), и у каждого свой формат (атомарные типы через sprintf выводятся напрямую, остальные два -- как и сказал, отдельный случай с циклом).

Цитата
Цитата
плюс для словаря вставить аналогичное массиву, или я что-то упустил?
Вроде бы, можно сделать попроще, если поступиться эффективностью и под каждый элемент отдельную строку создавать
Тоже не понятно =((
Встречное непонимание, уточните вопрос.

Вообще, согласен с RXL, если там пару типов значений сбросить надо (int, char* и один тип структур в массиве), то можно забыть про универсальные типы, но тогда и ничего сложного в том, чтобы сделать запись массива. Не смотрите на конкретную реализацию, ищите идеи декомпозиции вашей задачи.
« Последнее редактирование: 25-01-2016 21:15 от Вад » Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #8 : 25-01-2016 21:12 » 

Нет-нет, разбивать на молекулы и атомы не надо. Я имел в виду структуру данных. Зачем хранить и обрабатывать данные, которые тебе не нужны? Например, программа ждет {"a": <int>, "b": <string>}, а приходит {"a": <int>, "b": <string>, "c": <float>, "d: [1,2], "f": {"g": <string>}}. Поля c, d, e, f и g программа может смело игнорировать. Парсеру нужно пройти все поля, но сохранять ненужные необходимости нет.

Кстати, откуда такое жесткое ограничение - Си? C++ куда удобнее для работы с динамическими коллекциями.
« Последнее редактирование: 25-01-2016 21:16 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
pokk
Помогающий

ru
Offline Offline

« Ответ #9 : 26-01-2016 02:44 » 

Благодарю всех помощь, решил остановится примерно на таком варианте (помог универсальный тип ItemType)
Тут все ключи собраны воедино, и при отправке надо только заполнить Value и указать какие данные выдавать (после Access).
Хотя ещё подумываю добавить в структуру сразу адреса переменных Value, тогда перед отправкой нечего заполнять не надо будет прост разрешить какие данные отправляются.

PS: Остался не большой вопрос когда ставить разделители в начале функции itemToStr или после добавления строки, но в любом случае этот разделить вылезит или в начале всей строки или в конце. Так что решил поставить его в конце строки а после заполнения всех пунктов заменить на "/0".

Код:
enum{
NAME_ITEM1,
NAME_ITEM2,
MAX_ITEM,
}

ItemType Item[MAX_ITEM]={
.Item[NAME_ITEM1]={
.Type=INT,
.KEY="KEY1:",
.Access=0,
},
.Item[NAME_ITEM2]={
.Type=Str,
.KEY="KEY2:",
.Access=0,
},
}
//----------------------------------------------------------
Item[NAME_ITEM1].access=1; //Разрешено
Item[NAME_ITEM1].access=1; //Разрешено

Item[NAME_ITEM1].value.int16=123;
Item[NAME_ITEM2].value.STR="TEST1"; //адрес строки
Item[NAME_ITEM3].value.ip=IP; //адрес строки
Item[NAME_ITEM3].value.mac=mac; //адрес строки
Item[NAME_ITEM4].value.char8=123;

Item[NAME_ITEM5].array.str[]="str1","str2",...;

Item[NAME_ITEM6].array.int16[]=1,2,3,4,...;

for(i=0;i<MAX_INTEM;i++){
itemToStr(Buff,Item[i]);
}

где, itemToStr
Код:
char * itemToStr(unsigned char index,char * buf, const ItemType * item)
{
    index += sprintf(buf, "\"%s:\"", item->name);
switch(item->type){
//---------------------------------------------------
case ARRAY:{ // массив:
break;
}
//---------------------------------------------------
case INT16:{
//перевод числа в строку(+ копирование)
//
break;
}
case STR:{
//Копирование строки с адреса item->str
break;
}
//---------------------------------------------------
}
    return index;
}

Цитата
Кстати, откуда такое жесткое ограничение - Си? C++ куда удобнее для работы с динамическими коллекциями.
Пишу программу для микроконтроллера, хоть там и есть поддержка С++, но я с ним не работал так что ещё рано для меня.
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #10 : 26-01-2016 08:26 » 

Пишу программу для микроконтроллера

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

По возможности проверить код на совместимость с требованиями MISRA (тут аккуратнее, без фанатизма, ибо часть из них явно устарели), прогнать через статический анализатор (например, lint или его клон) и устранить все его предупреждения. Например, в функции itemToStr нарушено обязательное правило 15.3 MISRA 2004, которое лично я считаю весьма полезным:

Цитата
Rule 15.3 (required): The final clause of a switch statement shall be the default clause.

The requirement for a final default clause is defensive programming. This clause shall either take appropriate action or contain a suitable comment as to why no action is taken.

Ну и, разумеется, с void * следует быть поакккуратнее и не использовать без совершенно крайней необходимости, которая реально наступает крайне редко. Не такая уж это безобидная конструкция.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #11 : 26-01-2016 09:34 » 

С JSON есть еще засада. Например, ждем {"a": <int>, "b": <string>}, а приходит {"a": <string>, "b": <string>}. JSON это допускает. И динамические языки легко переводят int <-> string, а жестко типизированным языкам приходится выбирать: либо делать принудительную конверсию (т.е. надо заранее знать, какой должен быть тип поля), либо считать такие данные невалидными.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines