Модуль сделан для преобразования json-логов в "плоский" табличный вид. Также в библиотеке содежится консольная утилита для быстрой трансформации json файлов.
test.json
{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
}Результат
{"store_book_category":"reference","store_book_author":"Nigel Rees","store_book_title":"Sayings of the Century","store_book_price":8.95,"store_bicycle_color":"red","store_bicycle_price":19.95,"expensive":10}
{"store_book_category":"fiction","store_book_author":"Evelyn Waugh","store_book_title":"Sword of Honour","store_book_price":12.99,"store_bicycle_color":"red","store_bicycle_price":19.95,"expensive":10}
{"store_book_category":"fiction","store_book_author":"Herman Melville","store_book_title":"Moby Dick","store_book_price":8.99,"store_book_isbn":"0-553-21311-3","store_bicycle_color":"red","store_bicycle_price":19.95,"expensive":10}
{"store_book_category":"fiction","store_book_author":"J. R. R. Tolkien","store_book_title":"The Lord of the Rings","store_book_price":22.99,"store_book_isbn":"0-395-19395-8","store_bicycle_color":"red","store_bicycle_price":19.95,"expensive":10}Репозиторий maven http://dpnexus.ftc.ru/repository/libs-release-local/:
// добавление в gradle
repositories {
maven{
url = 'http://dpnexus.ftc.ru/repository/libs-release-local/'
}
}
dependencies {
compile 'ru.ftc.utils:jsonflat:version'
}
Transformer - можно использовать для встраивания в любое java приложение.
Метод transform принимает json-документ в виде строки и в ответ возвращает список "плоских" JSON строк. Для работы ему потребуется схема разбора документа.
Схема определяет какие данне из документа требуется вывести в результат, а также она предоставляет возможность задать параметры обработки конкретных узлов. Есть несколько способов определения схемы, самый простой из них: задать схему в виде списка путей имен требующихся в результате. При этом, вложенные пути нужно будет описать составными именами через символ подчеркивания '_'. Также при описании имен поддерживается wildcard при помощи символов '*' и '?''. При парсинге вложенных массивов порядок следованя элементов сохраняется. Например, если для документа выше задать схему вида:
- store_book_title
- store_book_price
- store_bicycle*
то результатом работы парсера будут документы:
{"store_book_title":"Sayings of the Century","store_book_price":8.95,"store_bicycle_color":"red","store_bicycle_price":19.95}
{"store_book_title":"Sword of Honour","store_book_price":12.99,"store_bicycle_color":"red","store_bicycle_price":19.95}
{"store_book_title":"Moby Dick","store_book_price":8.99,"store_bicycle_color":"red","store_bicycle_price":19.95}
{"store_book_title":"The Lord of the Rings","store_book_price":22.99,"store_bicycle_color":"red","store_bicycle_price":19.95}Java код реализующий такое преобразование:
Schema schema = AutoSchemaFactory.builder()
.columnStringFilters(Arrays.asList("store_book_title", "store_book_price", "store_bicycle*"))
.build()
.generate(jsonText);
Transformer transformer = new Transformer(schema);
List<String> result = transformer.transform(jsonText);AutoSchemaFactory строит схему обработку документа автоматически, на основании входящего документа.
Кроме того, AutoSchemaFactory позволяет определить:
- JsonPath для фильтрации json строк которые следует обрабатывать (по умолчанию фильтрация выключена)
- разделитель, при помощи которого будут формироваться имена полей (по умолчанию '_')
- политику группировки массивов примитивных типов (по умолчанию ARRAY)
- политику группировик массивов структур (по умолчанию NO_GROUP)
Реализованы следующие политики обработки вложенных json массивов:
- CONCAT – конкатенация значений в строку через запятую ',';
- ARRAY – оставить как массив в результате
- COLUMNS – каждый элемент массива будет преобразован в отдельное поле в результирующем json c именем индекса массива
- NO_GROUP – не группировать элементы массива, каждому элементу будет соответвовать отдельный документ в результирующем массиве
Например, если задать политику обработки массивов структур как COLUMNS
Schema schema = AutoSchemaFactory.builder()
.columnStringFilters(Arrays.asList("store_book_title", "store_book_price", "store_bicycle*"))
.complexArraysGroup(Schema.GroupPolicy.COLUMNS)
.build()
.generate(jsonText);
Transformer transformer = new Transformer(schema);
List<String> result = transformer.transform(jsonText);то результатом будет:
{"store_book_0_title":"Sayings of the Century","store_book_0_price":8.95,"store_book_1_title":"Sword of Honour","store_book_1_price":12.99,"store_book_2_title":"Moby Dick","store_book_2_price":8.99,"store_book_3_title":"The Lord of the Rings","store_book_3_price":22.99,"store_bicycle_color":"red","store_bicycle_price":19.95}С другими примерами задания схем через внешний JSON файл можно ознакомиться в тестовых классах: AutoSchemaTest и AutoSchemaEveryLineTest
JsonSchemaFactory задает схему разбора документа на основе внешнего json файла. В описании схемы необходимо будет описать вложенность структур исходного json файла и есть возможность описать правила преобразования каждого узла.
В схеме определюятся:
name– строка, название схемы, не влияет разбор документаversion– строка, версия схемы, не влияет разбор документаfilter– объект для фильтрации json строк которые следует обрабатывать (по умолчанию фильтрация выключена)path- JsonPath, на основании которого входящий документ будет или не будет обрабатыватьсяclass- класс фильтрации, должен наследовать интерфейсFilterExist- если описанный JsonPath сущетвует, то документ будет обработанNotExist- если описанный JsonPath сущетвует, то документ будет пропущен
columnResults- массив объектов, список колонок. Колонки имеют иерархическую структуру. В итоговую таблицу будут выведены только листовые колонкиname- строка имя колонки, используется для именования полей в результирующем документеpath- строка JsonPath для получения значение колонки из документа. Путь всегда указывается относительно родительской ноды. Необязательное поле, если отсутствует, то в качестве пути будет использовано значение из поля name. Важное замечание: если элемент содержит массив объектов, то следует указать явно через JsonPath (например, выбор всех объектов массива '[*]')fullname- boolean, определяет правило именования колонки в итоговой таблице.false– имя колонки будет сформировано конкатенацией имён всех родительских columnResults, в естественном порядке (используется по умолчанию)true, имя колонки будет совпадат со значением в name.
skipJsonIfEmpty- boolean, позволяет пропустить преобразование документа, если в нем нет такого поля.true– пропущенный документ не будет выведен в итоговую таблицу.false– при отсутвии поля документ будет присутвовать в итоговой таблице без указаного поля (используется по умолчанию)
skipRowIfEmpty- boolean, пропустить данную строку итоговой таблицы, если после конвертации поля его значиние принимает значение null. По сути гарантирует, что все строки в результате будут содержать указанную колонку.true– если в итоговой таблице поле имеет значение null, то не выводить строку в итоговую таблицуfalse– если в итоговой таблице поле имеет значение null, то вывести строку в итоговую таблицу без этого поля (используется по умолчанию)
group- enum, политика объединения значений поля, если их несколько (см. политики обработки массивов). По умолчанию NO_GROUP.converter- объект, правило конвертации значения json при записи в таблицу, если требуется. Необязательное поле, по умолчанию тип колонки в итоговой таблице совпадет с типом значения в json.class- строка, класс осуществляющий конвертацию, должен наследовать интерфейсConverterToDatetime– преобразование в формат yyyy-MM-dd'T'HH:mm:ss из формата UNIX millisecondspattern- паттерн даты
ToLong- преобразование в Long числоToString– преобразование в String
columnResults- массив объектов column, список вложенных колонок.
Ниже приведена схема, которая выводит в результат только те строки у которых есть поле "isbn", а также переопределяет наименование цен книг с полного пути "store_book_price" на просто "price", причем значение поля преобразовано в строку.
{
"name": "Example schema",
"version": "1.0",
"columnResults": [
{
"name": "store",
"columnResults": [
{
"name": "book",
"columnResults": [
{"name": "type", "path": "category"},
{"name": "author"},
{"name": "title"},
{"name": "isbn", "skipRowIfEmpty": true},
{
"name": "price",
"fullname": true,
"converter": {
"class": "ToString"
}
}
]
}
]
},
{
"name": "expensive"
}
]
}Результатом работы парсера будет список строк:
{"store_book_type":"fiction","store_book_author":"Herman Melville","store_book_title":"Moby Dick","store_book_isbn":"0-553-21311-3","price":"8.99","expensive":10}
{"store_book_type":"fiction","store_book_author":"J. R. R. Tolkien","store_book_title":"The Lord of the Rings","store_book_isbn":"0-395-19395-8","price":"22.99","expensive":10}С другими примерами задания схем через внешний JSON файл можно ознакомиться в тестовом классе: JsonSchemaTest
Схему, описанную в параграфе выше, можно определить при помощи кода:
Schema schema = new Schema();
schema.setColumns(
Arrays.asList(
new Schema.Column("store", "store", Arrays.asList(
new Schema.Column("book", "book[*]",
Arrays.asList(
new Schema.Column("type", "category", Collections.emptyList(), schema),
new Schema.Column("author", "author", Collections.emptyList(), schema),
new Schema.Column("title", "title", Collections.emptyList(), schema),
new Schema.Column("isbn", "isbn", Collections.emptyList(), Schema.GroupPolicy.NO_GROUP, false, false, true, Converter.DEFAULT, schema),
new Schema.Column("price", "price", Collections.emptyList(), Schema.GroupPolicy.NO_GROUP, true, false, false, new ToString(), schema)
),
Schema.GroupPolicy.NO_GROUP, schema
),
new Schema.Column("expensive", "expensive", Collections.emptyList(), schema)
), schema)
)
);
Transformer transformer = new Transformer(schema);
List<String> result = transformer.transform(jsonText);Результатом работы парсера будет список строк:
{"store_book_type":"fiction","store_book_author":"Herman Melville","store_book_title":"Moby Dick","store_book_isbn":"0-553-21311-3","price":"8.99","expensive":10}
{"store_book_type":"fiction","store_book_author":"J. R. R. Tolkien","store_book_title":"The Lord of the Rings","store_book_isbn":"0-395-19395-8","price":"22.99","expensive":10}За работу с командной строкой отвечает класс App
Для его использования необходимо создать bash файл
java -jar "$( dirname -- "${BASH_SOURCE[0]}" )"/jsonflat.jar "$@"Утилита поддерживает прием и передачу данных через стандартный input/output потоки.
Также поддерживается работа с log файлами, каждая линяя которых будет обрезаться до первого символа [ или {.
Поддерживается преобразование файла в csv формат
Аргументы:
-iПуть до input файла, по умолчанию стандартный ввод-oПуть до output файла, по умолчанию стандартный вывод-fJSONPath для фильтрации документов перед процессингом, работает только если не задан параметр-s-sПуть до JSON файла со схемой парсинга. По умолчанию, схема будет сгенерирована на основании входящего JSON файла-dРазделитель для именования колонок файла, по умолчанию используется_-eКодировка входного файла, по умолчаниюutf-8-nЕсли не задан параметр-s, генерирует схему только на основе первой строки файла-aРазворачивает вложенные массивы из простых типов в строки. По умолчанию оставляет без изменений-cРазворачивает вложенные массивы структур в колонки. По умолчанию разворачивает в строки-csvПишет результат в CSV формате. Разделитель;. Всегда генерирует схему по первому документу в файле, если не указан параметр-s-hПомощь
Все остальные параметры задают схему разбора документа, перечислением через пробел необходимых в результате колонок. Поддерживаются символы * и ?. По умолчанию, схема будет сгенерирована на основании входящего JSON файла
Пример использования:
cat example.json > jsonflat store_book_title store_book_price store_bicycle*
{"store_book_title":"Sayings of the Century","store_book_price":8.95,"store_bicycle_color":"red","store_bicycle_price":19.95}
{"store_book_title":"Sword of Honour","store_book_price":12.99,"store_bicycle_color":"red","store_bicycle_price":19.95}, {"store_book_title":"Moby Dick","store_book_price":8.99,"store_bicycle_color":"red","store_bicycle_price":19.95}
{"store_book_title":"The Lord of the Rings","store_book_price":22.99,"store_bicycle_color":"red","store_bicycle_price":19.95}