C++ парсер JSON и легкое извлечение данных

Представляю вам маленькую библиотеку для парсинга структуры JSON документа и легкого извлечения данных, написанную на C++.

Репозиторий vCjson на GitHub.

git clone https://github.com/as-yuschenko/vCjson.git

Парсинг

Во время парсинга структуры документа JSON данные разбиваются на узлы. Каждый узел представляет собой тип данных в соответствии с https://www.json.org/ и может являться объектом, массивом, строкой, числом, парой ключ — значение, TRUE, FALSE, NULL.
Все узлы выстраиваются иерархически, в соответствии с глубиной вложенности.
Для парсинга документа JSON используется метод:

    /** Makes parsing of json data.
    * ATTENTION!!!
    * When data parsing complete, cursor located on root position.
    * Use go_next_sibling() to move to the first sibling.
    *
    * @param str - pointer to zero terminated c-string.
    * @return VCJSON_OK or  VCJSON_ERR_EMPTY_JSON_DATA, or
                            VCJSON_ERR_INCORRECT_DATA_QT, or
                            VCJSON_ERR_INCORRECT_DATA_BR, or
                            VCJSON_ERR_INCORRECT_VALUE, or
                            VCJSON_ERR_BUFF_IS_EMPTY.
    */
    int parse(char* jsonData);

Внимание! После парсинга курсор занимает позицию root и не указывает ни на один узел.

Информация о узлах

Каждый узел обладает следующими свойствами:

  • Тип (объект, массив, строка, число, пара ключ — значение, правда, ложь, нуль);
  • Собственный ID;
  • ID Родителя;
  • Позиция начала данных узла;
  • Позиция окончания данных узла;
  • Указатель на имя узла (если существует);
  • Размер имени узла (если существует);
  • Указатель на значение узла (если существует);
  • Размер значения узла (если существует);

Для получения количества узлов документа JSON используется метод:

    /** Returns number of nodes.
    * @return number of nodes
    */
    int get_num_nodes();

Для получения типа текущего узла используется метод:

    /** Returns type of current node.
    * @return
    * VCJSON_NT_STR,
    * VCJSON_NT_NUM,
    * VCJSON_NT_OBJ,
    * VCJSON_NT_ARR,
    * VCJSON_NT_PNV,
    * VCJSON_NT_TRUE,
    * VCJSON_NT_FALSE,
    * VCJSON_NT_NUL
    */
    int get_node_type();

Для получения типа узла, переданного по имени используется метод:

    /** Returns type of node that name specified.
    * @return 
    * VCJSON_NT_STR,
    * VCJSON_NT_NUM,
    * VCJSON_NT_OBJ,
    * VCJSON_NT_ARR,
    * VCJSON_NT_PNV,
    * VCJSON_NT_TRUE,
    * VCJSON_NT_FALSE,
    * VCJSON_NT_NUL
    * or [-1] if error.
    */
    int get_node_type_by_name(const char* name);

Навигация по узлам

В библиотеке реализовано два способа навигации по документу:

  • Курсор;
  • По имени узла (если существует).

Навигация с помощью курсора

После парсинга курсор занимает позицию root и не указывает ни на один узел.
Для получения количества узлов на текущем уровне вложенности используется метод:

    /** Returns number of siblings.
    * @return number of siblings on current layer.
    */
    int get_sibling_num();

Для перемещения между узлами на текущем уровне вложенности используются методы:

    /** Moves cursor to next (or first) sibling of current layer.
    * @return [0] - success, [-1] - current node is the last or error.
    */
    int go_next_sibling();
 
    /** Moves cursor to previos sibling of current layer.
    * @return [0] - success, [-1] - current node is the first or error.
    */
    int go_prev_sibling();

Узел может быть родительским по отношению к другим узлам, входящим в его состав. Для того, чтобы перейти к дочерним узлам текущего узла (опуститься на уровень ниже) используется метод:

    /** Moves cursor to childs of the current node.
    * ATTENTION!!!
    * Cursor located on current layer root position.
    * @use go_next_sibling() to move to the first sibling.
    * @use get_sibling_num() to know how much siblings.
    * @return [0] - success, [-1] - no childs for current node or error.
    */
    int go_node_child();

После применения метода, курсор занимает позицию root текущего уровня и не указывает ни на один узел.
Для перемещения по узлам текущего уровня используйте методы go_next_sibling, go_prev_sibling и get_sibling_num для определения количества узлов на этом уровне. Если на текущем уровне есть узел, являющийся родительским по отношению к другим узлам, то используйте тот же механизм перемещения.

Для возврата к родительскому узлу (курсор будет указывать на него) используется метод:

    /** Moves cursor to parent of current node.
    * @return [0] - success, [-1] - parent of current node is root or error.
    */
    int go_node_parent();

Для возврата курсора в root положение самого верхнего уровня используется метод:

    /** Moves cursor to the root.*/
    void go_root();

Навигация по имени узла

Для перемещения курсора к узлу, имя которого было передано, используется метод:

    /** Moves cursor position to node that name specified.
    * @param name - pointer to zero terminated c-string.
    * @return [0] - success, [-1] - error.
    */
    int go_node_name (const char* name);

Метод устанавливает курсор на первый по порядку узел имя которого передано по указателю. Поиск производится начиная с позиции root документа.

Если в документе JSON имеется несколько узлов с одинаковыми именами на разных уровнях вложенности, вы можете переместить указатель на позицию родительского узла используя go_node_name, go_next_sibling, go_prev_sibling, go_node_child или go_node_parent, далее перейти к дочерним узлам этого элемента используя go_node_child и использовать метод:

    /** Moves cursor position to node that name specified if node exists on current level.
    * @param name - pointer to zero terminated c-string.
    * @return [0] - success, [-1] - error.
    */
    int go_node_name_on_layer(const char* name);

Метод устанавливает курсор на узел, имя которого передано по указателю, на текущем уровне вложенности.

Извлечение данных

Для получения информации о длине данных имени и значения узла, а также указателей на имя и значение используются методы:

    /** Returns pointer to name of current node.
    * To get len of the name @use get_node_name_len().
    * @return pointer or nullptr if current node have no name.
    */
    char* get_node_name_ptr();
 
    /** Returns len of the name of current node.
    * To get pointer of the name @use get_node_name_ptr().
    * @return len or 0 if current node have no name.
    */
    int get_node_name_len();
 
    /** Returns pointer to the value of current node.
    * To get len of the value @use get_node_value_len().
    * @return pointer or nullptr if current node have no value.
    */
    char* get_node_value_ptr();
 
    /** Returns len of the value of current node.
    * To get pointer of the value @use get_node_value_ptr().
    * @return len  or 0 if current node has no value.
    */
    int get_node_value_len();

Следующие методы можно применять для текущего сравнения данных имен или значений узлов при принятии решений или выводе.

    /** Returns pointer to buff as zero terminated c-string contains value of current node.
    * @return pointer or nullptr if current node has no value.
    */
    char* get_node_value_str();
 
    /** Returns pointer to buff as zero terminated c-string contains name of current node.
    * @return pointer or nullptr if current node have no name.
    */
    char* get_node_name_str();

Будьте внимательны, при каждом использовании методов буферы будут содержать информацию о имени и значении текущего узла.

Для копирования имени или значения узла используются методы:

    /** Copy to buff name of current node.
    * @param buff - pointer to buff. Buffer size must be at least data size + 1 byte,
    * @use get_node_name_len() to get name len.
    * @return pointer or nullptr if error.
    */
    char* cp_node_name(char* buff);
 
    /** Copy to buff value of current node.
    * @param buff - pointer to buff. Buffer size must be at least data size + 1 byte,
    * @use get_node_value_len() to get value len.
    * @return pointer or nullptr if error.
    */
    char* cp_node_value(char* buff);

Будьте внимательны, размер буфера должен быть не менее размера данных + 1 байт. Сначала используйте get_node_name_len или get_node_value_len для определения размера буфера.

Вывод информации

Для вывода информации об узлах в консоль используются методы:

    /**Prints to console verbose information about node*/
    void show_node_info();
 
    /**Prints to console lite information about node*/
    void show_node();

Оцените пожалуйста статью:

ПечальноТак себеНе плохоХорошоОтличная статья! 2 оценок.
Загрузка...

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *