Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.78/32: Рейтинг темы: голосов - 32, средняя оценка - 4.78
В астрале
Эксперт С++
8035 / 4792 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
1

SAX json парсер

05.07.2013, 22:46. Показов 5775. Ответов 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
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
05.07.2013, 22:46
Ответы с готовыми решениями:

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

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

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

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

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

Не по теме:

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

0
В астрале
Эксперт С++
8035 / 4792 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
05.07.2013, 23:56  [ТС] 4
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
Эксперт С++
5026 / 2605 / 241
Регистрация: 07.10.2009
Сообщений: 4,310
Записей в блоге: 1
15.07.2013, 09:02 5
Лучший ответ Сообщение было отмечено как решение

Решение

Можно взглянуть на библиотеку cereal, правда в глубине там тот же rapidjson. Подробностей, к сожалению, не знаю и прошу прощения, если совсем не в тему, но на первый взгляд весьма похоже на то, что требуется.
3
В астрале
Эксперт С++
8035 / 4792 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
16.07.2013, 12:26  [ТС] 6
fasked, Интересно. Посмотрел. Но... Есть множество вещей, которые меня не устраивают на данном этапе (как минимум использование С++11, хотя с этим еще как-то можно смириться), а вот то что имена в объекте json-а должны идти в том же порядке, как указано в serialize - это очень и очень грустно.
0
Эксперт С++
5026 / 2605 / 241
Регистрация: 07.10.2009
Сообщений: 4,310
Записей в блоге: 1
16.07.2013, 21:46 7
Цитата Сообщение от ForEveR Посмотреть сообщение
а вот то что имена в объекте json-а должны идти в том же порядке, как указано в serialize - это очень и очень грустно
В документации об этом сказано "At this time", так что можно надеяться на исправление ситуации.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
16.07.2013, 21:46

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

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

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

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

парсер Json
Добрый день есть json...

Парсер JSON
Привет всем. Есть структура в формате json, которая записывается в ассоциативный массив: $obj =...


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

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.