С Новым годом! Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/37: Рейтинг темы: голосов - 37, средняя оценка - 5.00
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562

SAX json парсер

05.07.2013, 22:46. Показов 7177. Ответов 6
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Вечер добрый.
Есть задача реализовать SAX-парсер JSON-a (парсинг не во временные переменные, а сразу в текущие, на которые указатели/ссылки сохранены в некий контекст в классе). Задача парсить не просто примитивные типы и контейнеры, но и сложные/составные типы.

Нечто вроде такого

C++
1
2
3
4
5
6
struct A
{
   int a;
   std::vector<int> b;
   std::string c;
};
Должно переводиться в json и обратно
C++
1
2
3
4
5
const std::string json = "{\"A\":{\"a\":1,\"b\":{1,2},\"c\":\"string\"}}";
A a;
statement stmt;
stmt.use(a);
stmt.deserialize(json);
Я сделал данный кейс через fusion (сделано по аналогу SOCI, но там нет парсинга СРАЗУ в сложные типы). Капитально приходится испытывать сложности с составными объектами, я выбрал вариант, когда просто биндятся simple/container/conversion типы, который находятся в структуре (страдает время компиляции, для каждого объекта приходится создавать новый statement, причем динамически, ибо хранятся указатели (это проще, постольку поскольку, конструктор копирования реализовывать несколько сложнее), уходит довольно много памяти (допустим для примера из сериализации/десериализации двух структур + массива интов + boost::gregorian::date уходит примерно 271к байт, терпимо, но не слишком круто)).
Пример:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct other
{
   std::string name;
   unsigned int age;
   bool flag;
   double number;
 
   struct name_key { static const char* name() { return "name"; }};
   struct age_key { static const char* name() { return "age"; }};
   struct flag_key { static const char* name() { return "flag"; }};
   struct number_key { static const char* name() { return "number"; }};
};
 
BOOST_FUSION_ADAPT_ASSOC_STRUCT(
      other,
      (std::string, name, other::name_key)
      (unsigned int, age, other::age_key)
      (bool, flag, other::flag_key)
      (double, number, other::number_key)
);
структура становится fusion_sequence и через код вроде этого ее можно обойти

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
template<typename Next, typename Last>
struct traverse_types
{
   template<typename Object>
   static void traverse_helper(statement& stmt, Object& object, const std::string& name)
   {
      typedef typename get_exchange_type<Object>::type type;
      stmt.add_field(name, new type(object, name));
   }
   template<typename Object>
   static void apply(statement& stmt, Object& object)
   {
      typedef typename boost::fusion::result_of::key_of<Next>::type key_t;
      typedef typename boost::fusion::result_of::next<Next>::type next_t;
      typedef typename boost::fusion::result_of::at_key<Object, key_t>::type value_ref_t;
      typedef typename boost::remove_reference<value_ref_t>::type value_t;
      traverse_helper(stmt, boost::fusion::at_key<key_t>(object), key_t::name());
      traverse_types<next_t, Last>::apply(stmt, object);
   }
};
 
template<typename Last>
struct traverse_types<Last, Last>
{
   template<typename Object>
   static void apply(statement&, Object&)
   {
   }
};
// в конкретном классе use/into
 static void traverse(statement& stmt, T& object)
 {
    traverse_types<typename boost::fusion::result_of::begin<T>::type,
      typename boost::fusion::result_of::end<T>::type>::
      apply(stmt, object);
};
Где get_exchange_type некий шаблон, который просто typedef-ит нужный into/use тип.

C++
1
2
3
4
5
6
7
8
9
template<typename T>
struct get_exchange_type
{
   typedef typename exchange_traits<T>::type_tag tag;
   typedef typename boost::mpl::if_<typename boost::is_same<tag, basic_tag>::type, into_type<T>,
           typename boost::mpl::if_<typename boost::is_same<tag, container_tag>::type, container_into_type<T>,
           typename boost::mpl::if_<typename boost::is_same<tag, conversion_tag>::type, conversion_into_type<T>,
           user_into_type<T>>::type>::type>::type type;
};
C++
1
2
3
4
5
6
7
8
9
template<typename T>
struct get_exchange_type<const T>
{
   typedef typename exchange_traits<T>::type_tag tag;
   typedef typename boost::mpl::if_<typename boost::is_same<tag, basic_tag>::type, use_type<T>,
           typename boost::mpl::if_<typename boost::is_same<tag, container_tag>::type, container_use_type<T>,
           typename boost::mpl::if_<typename boost::is_same<tag, conversion_tag>::type, conversion_use_type<T>,
           user_use_type<T>>::type>::type>::type type;
};
Перегрузка для statement/writer реализована на тегах
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
template<typename T>
struct type_conversion;
 
struct basic_tag {};
struct user_tag {};
struct container_tag {};
struct conversion_tag {};
 
template<typename T>
struct has_type_conversion
{
   typedef char no;
   typedef char yes[2];
 
   template<typename U>
   static yes& test(typename type_conversion<U>::base_type*);
   template<typename>
   static no& test(...);
 
   static const bool value = sizeof(test<T>(0)) == sizeof(yes);
   typedef boost::mpl::bool_<value> type;
};
 
template<typename T>
struct exchange_traits
{
   typedef typename has_type_conversion<T>::type conversion;
   typedef typename boost::mpl::if_<conversion, conversion_tag, user_tag>::type type_tag;
   template<typename U, typename = void>
   struct get_type
   {
      enum { x_type = x_object };
   };
   template<typename U>
   struct get_type<U, typename boost::enable_if<typename has_type_conversion<U>::type>::type>
   {
      enum { x_type = exchange_traits<typename type_conversion<U>::base_type>::x_type };
   };
   enum
   {
      x_type = get_type<T>::x_type
   };
};
Дальше идут специализации для basic типов / контейнеров.

Есть возможность сделать интроспекцию/отражение в С++ проще, чем сделано на данный момент? Если данный вопрос нужно перенести в С++ для экспертов/boost - скажите, перенесу. Спасибо.
5
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
05.07.2013, 22:46
Ответы с готовыми решениями:

XML парсер - SAX
Привет всем! подскажите ПРОСТОЙ XML SAX парсер и описание к нему для Win MSVC нужно только читать из файла Здесь все...

json парсер
Всем привет! Ни как не получается пропарсить такое дело, кусок начала: Это формат гугла, выдающий результат поиска. Пробовал куча...

JSON парсер С++
Доброго времени суток, уважаемые пользователи cyberforum! Хотелось бы уточнить каким парсером лучше всего пользоваться? (Для...

6
ComfyMobile
 Аватар для Nixy
401 / 282 / 34
Регистрация: 24.07.2012
Сообщений: 916
05.07.2013, 23:37
Вам наверное стоит все-таки тему у экспертов размещать, врятли в разделе новичков ответят.
1
05.07.2013, 23:55

Не по теме:

Цитата Сообщение от ForEveR Посмотреть сообщение
реализовать SAX-парсер JSON-a (парсинг не во временные переменные, а сразу в текущие, на которые указатели/ссылки сохранены в некий контекст в классе)
Так, между делом: готовых решений для С++ действительно нету?

0
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
05.07.2013, 23:56  [ТС]
gray_fox, Не видел. Искал. Выбрали RapidJson за то, что он позволяет использовать SAX парсинг + быстрый, но вот распих в переменные приходится делать самому.
По хорошему готовых решений-то и не найти, даже тот же SOCI, который инкапсулирует в себе взаимодействие практически со всеми СУБД не умеет работать с пользовательскими объектами напрямую, ибо без некой реализации интроспекции это сделать невозможно. SOCI работает +- так
C++
1
2
3
4
5
6
7
8
9
template<>
struct conversion_traits<compound_type>
{
   typedef values base_type;
   void from_base(const base_type& in, indicator& ind, compound_type& out)
   {
       out.field = in.get<type>("field");
   }
};
Что неприемлимо в моем случае.
1
Эксперт С++
 Аватар для fasked
5045 / 2624 / 241
Регистрация: 07.10.2009
Сообщений: 4,310
Записей в блоге: 5
15.07.2013, 09:02
Лучший ответ Сообщение было отмечено как решение

Решение

Можно взглянуть на библиотеку cereal, правда в глубине там тот же rapidjson. Подробностей, к сожалению, не знаю и прошу прощения, если совсем не в тему, но на первый взгляд весьма похоже на то, что требуется.
3
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
16.07.2013, 12:26  [ТС]
fasked, Интересно. Посмотрел. Но... Есть множество вещей, которые меня не устраивают на данном этапе (как минимум использование С++11, хотя с этим еще как-то можно смириться), а вот то что имена в объекте json-а должны идти в том же порядке, как указано в serialize - это очень и очень грустно.
0
Эксперт С++
 Аватар для fasked
5045 / 2624 / 241
Регистрация: 07.10.2009
Сообщений: 4,310
Записей в блоге: 5
16.07.2013, 21:46
Цитата Сообщение от ForEveR Посмотреть сообщение
а вот то что имена в объекте json-а должны идти в том же порядке, как указано в serialize - это очень и очень грустно
В документации об этом сказано "At this time", так что можно надеяться на исправление ситуации.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
16.07.2013, 21:46
Помогаю со студенческими работами здесь

Посоветуйте парсер с минимальным набором инстализации json, xml, ini
Всем привет, нужен парсер чего-нибудь что переводит текст в переменной string в обычные С++ переменные. Есть сервер на php, который может...

SAX парсер
Вот такой код: String thisElement = &quot;&quot;; Product prod = new Product(); List&lt;Product&gt; prodList = new ArrayList&lt;&gt;(); ...

Написать sax парсер на C#
Написать парсер sax на C# &lt;?xml version=&quot;1.0&quot;?&gt; &lt;catalog&gt; &lt;book id=&quot;bk101&quot;&gt; &lt;author&gt;Gambardella, Matthew&lt;/author&gt;...

Посоветуйте, как тестить парсер DOM, SAX
Есть XML, я её распарсил несколькими способами. Далее необходимо написать к парсерам модульные тесты. пример моего парсера: public class...

Парсер JSON
C помощью Jsoup парсю JSON страницу и кодировка не работает пишет тупо вопросики. Как исправить? Второй вопрос, как мне вытаскивать...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ * Дана цепь постоянного тока с сопротивлениями и напряжениями. Надо найти токи в ветвях. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и решает её. Последовательность действий:. . .
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
Модель микоризы: классовый агентный подход
anaschu 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение. И на уровне агентов добавится между грибами или бактериями взаимодействий. До того я пробовал подход через многомерные массивы,. . .
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru