Чтение json-файла c
Обновлено: 21.11.2024
Обозначение объектов JavaScript, или JSON, — это широко используемый удобочитаемый формат для передачи объектов данных в виде пар ключ-значение. Первоначально разработанный для связи между сервером и браузером, использование JSON с тех пор расширилось до универсального формата обмена данными. В этом руководстве представлено простое введение в синтаксический анализ строк JSON на языке программирования C с использованием библиотеки microjson. Более сложные примеры можно найти в официальной документации. Однако этого руководства должно быть достаточно, чтобы вы сразу начали анализировать простые объекты.
Как это обычно бывает при работе со строками в C, синтаксический анализ JSON — это нетривиальная задача, которую лучше оставить для уже существующих библиотек. Библиотека microjson была разработана для преобразования большого подмножества JSON в статические структуры C с использованием только хранилища с фиксированным объемом. Библиотека небольшая и занимает мало места — идеально подходит для использования во встроенных системах.
Пример компиляции
Чтобы скомпилировать примеры программ в Linux или Linux-подобной среде, просто используйте включенный Makefile:
Вы также можете импортировать исходные файлы в проект Eclipse или Xcode и позволить IDE скомпилировать их для вас, если вы боитесь командной строки.
Разбор простых объектов
В контексте этого руководства простые объекты будут относиться к объектам JSON, которые не являются вложенными. В этом руководстве предполагается, что форма объекта JSON известна.
В этом разделе показано, как использовать microjson для анализа объекта JSON в следующем формате:
Этот объект содержит строку text , логический флаг и целочисленное значение count . В этом примере объект будет преобразован в статическую структуру C вида:
Функция json_obj_read использует структуру C json_attr_t для сопоставления соответствующих полей объекта JSON со структурой объекта C. t_ и .aadr. вместе используются библиотекой для определения типа данных, ожидаемых в объекте JSON, и соответствующего типа члена структуры. Обратите внимание, что в случае строки text мы также должны указать длину .len символьного буфера.
Мы будем использовать следующую программу для тестирования нашего кода:
Эта программа принимает единственный аргумент, представляющий собой строковое представление JSON объекта, который мы хотим проанализировать. Программа напечатает каждый из членов нашей структуры объекта C после разбора в ней входного JSON:
Анализ составных объектов
Одной из особенностей JSON является возможность вложения объектов в другие объекты. Одним из распространенных примеров является наличие массива объектов JSON в качестве значения внутри другого объекта JSON, например, в следующем примере:
Здесь у нас есть два экземпляра нашего предыдущего объекта my_object в массиве с именем my_objects. Чтобы справиться с этим, мы должны указать, что входящий JSON имеет массив и что каждый из элементов в массиве имеет форму my_object. Мы хотим сохранить этот массив my_object в другой структуре контейнера следующим образом:
Затем мы пишем объектную функцию синтаксического анализа для структуры контейнера, используя два определения json_attr_t ; один для описания объекта-контейнера и один для описания каждого из объектов в массиве:
Мы можем протестировать эту функцию с помощью следующей программы:
Эта программа принимает единственный аргумент, представляющий собой строковое представление JSON списка объектов, которые мы хотим проанализировать. Программа распечатает элементы каждой структуры my_object, проанализированной из входных данных:
jsmn (произносится как «жасмин») — это минималистичный синтаксический анализатор JSON на C. Его можно легко интегрировать в проекты с ограниченными ресурсами или встроенные системы.
Философия
Обычно синтаксические анализаторы JSON преобразуют строку JSON во внутреннее представление объекта. Но если вы используете C, это становится сложно, так как нет хэш-таблиц, отражения и т. д. Вот почему большинство парсеров JSON, написанных на C, пытаются заново изобрести колесо и либо изобретать пользовательские объекты, подобные JSON, пользовательские хэш-карты, либо использовать обратные вызовы. как это делают синтаксические анализаторы SAX.
В jsmn отсутствуют все эти функции, но вместо этого он спроектирован таким образом, чтобы быть надежным (он должен нормально работать даже с ошибочными данными), быстрым (он анализирует данные на лету и допускает повторный вход), переносимым (без лишних зависимостей или -стандартные расширения C). И, конечно же, ключевой особенностью является простота.
Возможности
- простой
- высокая переносимость (протестировано на платформах x86/amd64, ARM, AVR)
- совместим с C89
- никаких зависимостей (даже libc!)
- без динамического выделения памяти
- чрезвычайно малый объем кода — всего около 200 LOC
- API имеет только две функции
- инкрементный однопроходный синтаксический анализ
- код библиотеки покрыт тестами
Дизайн
jsmn разбивает строку JSON на токены. Рассмотрим строку JSON:
jsmn разделит его на следующие токены:
- Объект: < "name" : "Jack", "age" : 27>(весь объект)
- Строки: "имя" , "Джек" , "возраст" (ключи и некоторые значения)
- Число: 27
Ключевым моментом является то, что токены jsmn не содержат никаких данных, а вместо этого просто указывают на границы токена в строке JSON. В приведенном выше примере jsmn создает такие токены, как:
- Объект [0..31]
- Строка [3..7], Строка [12..16], Строка [20..23]
- Число [27..29].
Каждый токен jsmn имеет один из следующих типов:
- Объект — контейнер пар "ключ-значение", например:
- Массив – последовательность значений, например: [ 1, 2, 3 ]
- Строка — последовательность символов в кавычках, например: "foo"
- Примитив — число, логическое значение ( true , false ) или null
Помимо начальной/конечной позиции, токены jsmn для сложных типов (таких как массивы или объекты) также содержат ряд дочерних элементов, поэтому вы можете легко отслеживать иерархию объектов.
Этот подход предоставляет достаточно информации для анализа любых данных JSON и позволяет использовать методы нулевого копирования.
Установить
Чтобы клонировать репозиторий, у вас должен быть установлен mercurial. Просто беги:
Схема репозитория проста: jsmn.c и jsmn.h — это библиотечные файлы; demo.c — пример использования jsmn (он также используется в модульных тестах); test.sh — тестовый скрипт. Внутри вы также найдете файлы README, LICENSE и Makefile.
Чтобы собрать библиотеку, запустите make . Также рекомендуется запустить make test . Дайте мне знать, если некоторые тесты не пройдут.
Если сборка прошла успешно, вы должны получить библиотеку libjsmn.a. Файл заголовка, который вы должны включить, называется "jsmn.h" .
Типы токенов описываются jsmntype_t :
Примечание. В отличие от типов данных JSON, токены-примитивы не делятся на числа, логические значения и нулевые значения, поскольку по первому символу легко определить тип:
- ’t’, ‘f’ — логическое значение
- 'n' — ноль
- '-', ‘0’..‘9’ - число
Токен — это объект типа jsmntok_t:
Примечание: строковые токены указывают на первый символ после открывающей кавычки и предыдущий символ перед последней кавычкой. Это сделано для упрощения извлечения строк из данных JSON.
Вся работа выполняется объектом jsmn_parser. Вы можете инициализировать новый парсер, используя:
Это инициализирует (или сбрасывает) синтаксический анализатор.
Позже вы можете использовать функцию jsmn_parse() для обработки строки JSON с помощью синтаксического анализатора:
Неотрицательное возвращаемое значение jsmn_parse — это количество токенов, фактически используемых синтаксическим анализатором.
Передача NULL вместо массива маркеров не приведет к сохранению результатов синтаксического анализа, вместо этого функция вернет значение маркеров, необходимых для анализа данной строки. Это может быть полезно, если вы еще не знаете, сколько токенов нужно выделить.
Если что-то пойдет не так, jsmn_parse() вернет отрицательную ошибку. Возвращаемое значение будет одним из следующих:
- JSMN_ERROR_INVAL — неверный токен, повреждена строка JSON
- JSMN_ERROR_NOMEM – недостаточно токенов, слишком большая строка JSON
- JSMN_ERROR_PART: строка JSON слишком короткая, ожидаются дополнительные данные JSON
Если вы получаете JSON_ERROR_NOMEM , вам следует перераспределить больше токенов и снова вызвать jsmn_parse. Если вы читаете данные JSON из потока, вы можете периодически вызывать jsmn_parse и проверять, не является ли возвращаемое значение JSON_ERROR_PART — это будет указывать на конец данных JSON.
jsmn хранит смещения внутри структуры парсера, а не указатели. Это означает, что вы можете использовать realloc() для получения большего количества токенов или перераспределить строку js при поступлении дополнительных данных.
Нестрогий режим
По умолчанию jsmn работает в нестрогом режиме. Это позволяет вам использовать его для других полезных форматов, таких как JSON. В нестрогом режиме jsmn принимает:
- значения примитивов без кавычек, отличные от true/false/null/numbers
- только примитивные значения без корневого объекта
Это означает, что для jsmn допустим следующий текст:
Похоже на файл конфигурации, верно? Вот как вы можете использовать jsmn для разбора кода JavaScript:
Для переключения в строгий режим необходимо определить переменную препроцессора JSMN_STRICT.
Родительские ссылки
В тесте jsmn показал довольно хорошие результаты для небольших объектов (~4 КБ). Но для больших объектов это было ужасно медленно. Это можно исправить, сохранив ссылки на родительские узлы. Вы потеряете около 4 байт на токен, но скорость будет намного выше (кстати, после этого небольшого хака jsmn кажется самым быстрым парсером в этом тесте).
Чтобы включить родительские ссылки, вы должны определить JSMN_PARENT_LINKS перед компиляцией jsmn.
Ссылки
В Интернете есть несколько сообщений о jsmn:
Другая информация
Это программное обеспечение распространяется по лицензии MIT, поэтому не стесняйтесь интегрировать его в свои коммерческие продукты.
Целью этого руководства является понимание данных JSON и анализ данных JSON в C++.Мы обсудим данные JSON, объекты, массивы, синтаксис JSON, а затем рассмотрим несколько рабочих примеров, чтобы понять механизм синтаксического анализа данных JSON в C++.
Что такое JSON?
JSON – это упрощенное текстовое представление для организованного хранения и передачи структурированных данных. Данные JSON представлены в виде упорядоченных списков и пар ключ-значение. JSON означает нотацию объектов JavaScript. Как видно из полного названия, он получен из JavaScript. Однако данные JSON поддерживаются большинством популярных языков программирования.
Он часто используется для передачи данных с сервера на веб-страницу. Структурированные данные гораздо проще и чище представлять в формате JSON, чем в формате XML.
Синтаксическое правило JSON
Вот правила синтаксиса JSON:
- Данные JSON всегда должны быть представлены в виде пар "ключ-значение".
- Данные JSON разделяются запятыми.
- Фигура используется для представления объекта JSON.
- Квадратная скобка используется для представления массива JSON.
Что такое данные JSON?
Данные JSON представлены в виде пар "ключ-значение". Это похоже на словарь или хэш в других языках программирования.
Это пример простых данных JSON. Ключ здесь — «Имя», а «Дрейк» — соответствующее значение. Ключ, т. е. «Имя», и значение, т. е. «Дрейк», разделены двоеточием.
Расширение файла JSON
Данные JSON обычно хранятся в файле с расширением «.json». Например, чтобы сохранить данные сотрудника, вы можете просто назвать файл «employee.json». Это будет простой текстовый файл. Затем вы можете открыть этот файл JSON в любом из ваших любимых текстовых редакторов.
Объект JSON
Объект JSON — это не что иное, как данные JSON, заключенные в фигурные скобки. Вот пример объекта JSON:
Объект JSON может содержать несколько данных JSON. Все данные JSON разделяются запятой. Данные JSON представлены в виде пар ключ-значение. Ключ, т. е. «Имя», и значение, т. е. «Дрейк», разделены двоеточием. В приведенном выше примере есть четыре пары ключ-значение. Первый ключ — «Имя»; «Дрейк» — соответствующее значение для него. Точно так же «EmployeeID», «Телефон» и «Отдел» — это три других ключа.
Массив JSON
Массив JSON может содержать несколько объектов JSON, разделенных запятыми. Массив JSON заключен в квадратную скобку. Давайте рассмотрим пример массива JSON:
Это пример массива JSON. Здесь «Студенты» заключены в квадратную скобку, то есть массив, и он содержит четыре объекта JSON. Каждый из этих объектов представлен в виде пар ключ-значение и разделен запятой.
Пример файла JSON
Теперь, когда мы поняли данные JSON, объекты JSON, массив JSON, давайте рассмотрим пример файла JSON:
<
«имя» : «Шон» ,
«фамилия» : «Браун»,
«ID студента» : 21453 ,
«Отдел» : «Компьютерная наука ». ,
«Предметы»: [ «Математика», «Физика», «Химия»]
>
Синтаксический анализ библиотек в C++:
В C++ нет встроенного решения для анализа данных JSON. Однако существует несколько библиотек для анализа данных JSON в C++. В этой статье мы рассмотрим две самые популярные библиотеки для анализа данных JSON в C++. Вот ссылки GitHub для анализа данных JSON:
Вы можете загрузить эти библиотеки, чтобы выполнить приведенные ниже примеры.
Примеры
Теперь у нас есть общее представление о данных JSON, объектах, массивах и доступных библиотеках синтаксического анализа. Теперь давайте рассмотрим пару примеров анализа данных JSON в C++:
- Пример 1. Анализ JSON в C++
- Пример 2. Анализ и сериализация JSON в C++
- Пример 3. Анализ JSON в C++
Для примеров 1 и 2 мы будем использовать библиотеку «nlohmann». В случае примера 3 мы будем использовать библиотеку «RapidJSON».
Пример 1: Анализ JSON в C++
В этом примере программы мы покажем, как получить доступ к значениям данных JSON в C++.
используя json = nlohmann :: json ;
// Доступ к значениям
std :: string fName = jdEmployees. значение("firstName", "oops");
std :: string lName = jdEmployees. значение("фамилия", "упс");
int sID = jdEmployees. значение ("Код студента", 0);
std :: string dept = jdEmployees. значение ("Отдел" , "упс" ) ;
// Выводим значения
std::cout "Имя:" fName std::endl;
std::cout "Фамилия:" lName std::endl;
std::cout "ID студента:" sID std::endl;
std :: cout "Отдел: " dept std :: endl ;
Пример 2: Анализ и сериализация JSON в C++
В этом примере программы мы увидим, как анализировать и сериализовать JSON в C++. Мы используем «json::parse()» для анализа данных JSON.
используя json = nlohmann :: json ;
int main()
<
// Вот текст в формате JSON
char text [ ] = R "(
"Book": "Width": 450, < br />"Высота": 30,
"Заголовок": "Hello World",
"isBiography": false,
"NumOfCopies": 4,
"LibraryIDs": [2319, 1406, 3854, 987]
>
>
)" ;
// Разбираем и сериализуем JSON
json j_complete = json :: parse(text) ;
std::cout std::setw(4) j_complete std::endl;
>
Пример 3: Анализ JSON в C++
Теперь мы покажем, как анализировать строку JSON с помощью библиотеки RapidJSON. Первоначально RapidJSON был вдохновлен RapidXML. В этом примере программы мы анализируем строку JSON в DOM. Мы объявили «mydoc» типа «Документ», а затем использовали метод «mydoc.parse()» для анализа строки JSON.
используя пространство имен rapidjson ;
// Разбираем строку JSON в DOM
Document mydoc ;
мойдок. Разобрать (json);
// DOM в строку
StringBuffer buffer ;
Запись StringBuffer > запись ( буфер ) ;
мой док. Принять ( писатель ) ;
// Печатаем вывод
std::cout buffer. GetString() std::endl;
Заключение
В этой статье мы кратко обсудили данные JSON, объект, массив и синтаксис. Как мы знаем, в C++ нет нативного решения для парсинга данных JSON; мы использовали две разные библиотеки для анализа данных JSON в C++. Мы рассмотрели три разных примера, чтобы продемонстрировать механизм разбора данных JSON в C++. По сравнению с библиотекой nlohmann RapidJSON компактнее, быстрее и не требует памяти.
JSON-C — реализация JSON на языке C
JSON-C реализует объектную модель подсчета ссылок, которая позволяет легко создавать объекты JSON на C, выводить их в виде строк в формате JSON и анализировать строки в формате JSON обратно в C-представление объектов JSON. Он направлен на соответствие RFC 7159.
Перейдите к разделу Использование json-c или ознакомьтесь с документацией по API, если json-c уже установлен и готов к использованию.
Сборка на Unix с помощью git , gcc и cmake
Если у вас уже установлен json-c, см. раздел Связывание с libjson-c, чтобы узнать, как собрать и связать с ним вашу программу.
gcc , clang или другой компилятор C
cmake>=2.8 , >=3.16 рекомендуется, cmake=>3.1 для тестов
Для создания документов вам также потребуется:
Если вы используете относительно современную систему, вы, скорее всего, сможете установить необходимые компоненты, используя систему пакетов вашей ОС.
Установите с помощью apt (например, Ubuntu 16.04.2 LTS)
Примечание: также можно поместить каталог сборки в исходный каталог json-c или вообще не использовать отдельный каталог сборки, но некоторые вещи могут работать не совсем правильно (в частности, make distcheck )
Создание документации с помощью Doxygen:
Документацию библиотеки можно создать непосредственно из исходного кода с помощью инструмента Doxygen:
Библиотека json-c создана с помощью CMake, который может иметь несколько параметров.
Переменная | Тип | Описание |
---|---|---|
CMAKE_INSTALL_PREFIX | String | Расположение установки. |
CMAKE_BUILD_TYPE | String | По умолчанию "отладка". |
BUILD_SHARED_LIBS | Bool | Сборка по умолчанию создает динамическую (dll/so) библиотеку. Установите значение OFF, чтобы создать только статическую библиотеку. |
BUILD_STATIC_LIBS | Bool | Сборка по умолчанию создает статическую (lib/ библиотека. Установите для этого параметра значение OFF, чтобы создать только общую библиотеку. |
DISABLE_STATIC_FPIC | Bool | По умолчанию код создается независимо от позиции. Установите для этого параметра значение OFF, чтобы создать только общую библиотеку. |
DISABLE_BSYMBOLIC | Bool | Отключить использование -Bsymbolic-функций.< /td> |
DISABLE_THREAD_LOCAL_STORAGE | Bool | Отключить использование локального хранилища потока (HAVE___THREAD). |
DISABLE_WERROR | Bool | Отключить использование -Werror. |
ENABLE_RDRAND | Bool< /td> | Включить аппаратное семя RNG RDRAND. |
ENABLE_THREADING | Bool | Включить поддержку частичной потоковой передачи. |
OVERRIDE_GET_RANDOM_SEED | String | Блок кода для использования вместо реализации json_c_get_random_seed() по умолчанию, например на встроенных платформах, где не работает даже откат к time(). Должна быть одной строкой. |
Передайте эти параметры как -D в командной строке CMake.
Построение с частичной поддержкой потоков
Хотя json-c не поддерживает полностью многопоточный доступ к деревьям объектов, в нем есть некоторый код, который помогает сделать его использование в многопоточных программах более безопасным. В настоящее время это ограничено использованием атомарных операций для json_object_get() и json_object_put().
Отдельно, хеш-функция по умолчанию, используемая для ключей полей объекта, lh_char_hash, использует операцию сравнения и замены, чтобы гарантировать, что случайное начальное число генерируется только один раз. Поскольку это однократная операция, она всегда компилируется, когда доступна операция сравнения и замены.
скрипт оболочки cmake-configure
Для тех, кто знаком со старым методом autoconf/autogen.sh/configure, есть скрипт-оболочка cmake-configure, упрощающий переход на cmake.
cmake-configure может принимать несколько параметров.
параметры | Описание |
---|---|
prefix=PREFIX | < td>установить независимые от архитектуры файлы в PREFIX|
enable-threading | Включить код для частичной поддержки многопоточного использования |
enable-rdrand | Включить генерацию аппаратного RNG Hash Seed RDRAND на поддерживаемых платформах x86/x64. |
enable-shared | создать общие библиотеки [default=yes] |
enable-static | создать статические библиотеки [default=yes] | tr>
disable-Bsymbolic | Избегайте связывания с -Bsymbolic-function |
disable-werror | Избегайте обработка предупреждений компилятора как фатальных ошибок |
По умолчанию, если доступен valgrind, запущенные тесты используют его. Это может значительно замедлить тесты, поэтому для его отключения используйте:
Для запуска тестов рекомендуется использовать отдельный каталог сборки:
Если тест не пройден, проверьте Testing/Temporary/LastTest.log ,tests/testSubDir/$/$.vg.out и другие подобные файлы. Если выходных данных недостаточно, попробуйте:
и снова проверьте файлы журнала.
Сборка на Unix и Windows с помощью vcpkg
Вы можете загрузить и установить JSON-C с помощью диспетчера зависимостей vcpkg:
Перенос JSON-C в vcpkg обновляется членами команды Microsoft и участниками сообщества. Если версия устарела, создайте проблему или запрос на включение в репозиторий vcpkg.
Ссылка на libjson-c
Если в вашей системе есть pkgconfig , вы можете просто добавить его в свой make-файл:
Без pkgconfig вы могли бы сделать что-то вроде этого:
Если в вашем проекте используется cmake:
Чтобы использовать json-c, вы можете включить json.h или, что предпочтительнее, один из следующих более конкретных файлов заголовков:
- json_object.h — основные типы и методы.
- json_tokener.h — методы анализа и сериализации деревьев объектов json-c.
- json_pointer.h — реализация указателя JSON (RFC 6901) для извлечения объектов из дерева объектов json-c.
- json_object_iterator.h — методы для повторения отдельных экземпляров json_object. (См. также json_object_object_foreach() в json_object.h)
- json_visit.h — методы обхода дерева объектов json-c.
- json_util.h — различные служебные функции.
Основным типом в json-c является json_object. Он описывает дерево объектов json с подсчетом ссылок, которые создаются либо синтаксическим анализом текста с помощью json_tokener (т. е. json_tokener_parse_ex()), либо путем создания (с помощью json_object_new_object(), json_object_new_int() и т. д.) и добавления (с помощью json_object_object_add(), json_object_array_add() и т. д.) их по отдельности. Как правило, каждый объект в дереве будет иметь одну ссылку от своего родителя. Когда вы закончите с деревом объектов, вы вызываете json_object_put() только для корневого объекта, чтобы освободить его, который рекурсивно проходит через все дочерние объекты, вызывая json_object_put() для каждого из них по очереди.
Вы можете получить ссылку на один дочерний объект ( json_object_object_get() или json_object_array_get_idx() ) и использовать этот объект до тех пор, пока его родитель действителен.
Если вам нужно, чтобы дочерний объект жил дольше, чем его родитель, вы можете увеличить счетчик ссылок дочернего элемента ( json_object_get() ), чтобы позволить ему пережить освобождение родителя или его удаление из родительского ( json_object_object_del() или json_object_array_del_idx () )
При синтаксическом анализе текста объект json_tokener не зависит от возвращаемого им объекта json_object. Его можно выделить ( json_tokener_new() ), использовать один или несколько раз ( json_tokener_parse_ex() ) и освободить ( json_tokener_free() ), пока объекты json_object продолжают жить.
Дерево json_object можно сериализовать обратно в строку с помощью json_object_to_json_string_ext() . Возвращаемая строка действительна только до следующего вызова to_json_string для того же объекта. Кроме того, он освобождается при освобождении json_object.
Читайте также: