В одном из проектов возникла необходимость перевести процессы импорта данных сторонних систем на микросервисную архитектуру. В качестве инструмента выбран Apache NiFi. В качестве первого подопытного выбран импорт ЕГРЮЛ ФНС.
В предыдущей статье был описан способ преобразования XML в JSON с использованием AVRO schema.
В данной статье описан способ преобразования JSON с помощью JOLT спецификации.
Используемые процессоры и контроллеры
Деление JSON на части
FlowFile, полученный на предыдущем этапе, содержит JSON с массивом выписок ЕГРЮЛ по разным организациям. Для начала разделим его на части, чтобы каждый FlowFile содержал одну выписку.
Для этого используем процессор SplitJson. Из настроек - требуется указать выражение JsonPath для разделения json на части. В данном случае $.*
Документация по JsonPath здесь
Потренироваться можно здесь
Преобразование JSON
Полученный JSON имеет излишне сложную структуру для того, чтобы в дальнейшем хранить и обрабатывать его. Адрес и ФИО лучше объединить в одну строку, некоторые элементы перенести выше по иерархии.
JSON перед трансформацией
{
"reportDate" : "2020-05-20",
"ogrn" : "1234567890123",
"ogrnDate" : "2002-12-30",
"inn" : "1234567890",
"kpp" : "123456789",
"opfCode" : "12300",
"opfName" : "Общества с ограниченной ответственностью",
"name" : {
"fullName" : "ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ",
"shortName" : "ООО"
},
"address" : {
"addressRF" : {
"region" : {
"type" : "ОБЛАСТЬ",
"name" : "МОСКОВСКАЯ"
},
"district" : null,
"town" : {
"type" : "ГОРОД",
"name" : "ИСТРА"
},
"settlement" : null,
"street" : {
"type" : "ПЕРЕУЛОК",
"name" : "ВОЛОКОЛАМСКИЙ"
},
"index" : "143500",
"regionCode" : "50",
"kladr" : "500000570000011",
"house" : null,
"building" : null,
"apartment" : null
}
},
"termination" : null,
"capital" : null,
"manageOrg" : null,
"director" : [ {
"fl" : {
"lastName" : "ИВАНОВ",
"firstName" : "ИВАН",
"patronymic" : "ИВАНОВИЧ",
"inn" : "123456789012"
},
"position" : {
"ogrnip" : null,
"typeCode" : "02",
"typeName" : "Руководитель юридического лица",
"name" : "ГЕНЕРАЛЬНЫЙ ДИРЕКТОР"
},
"disqualification" : null
} ],
"founders" : {
"founderULRF" : null,
"founderULForeign" : null,
"founderFL" : [ {
"fl" : {
"lastName" : "ИВАНОВ",
"firstName" : "ИВАН",
"patronymic" : "ИВАНОВИЧ",
"inn" : "123456789012"
},
"capitalPart" : {
"nominal" : 20000.0,
"size" : {
"percent" : 50.0,
"decimalPart" : null,
"simplePart" : null
}
}
}, {
"fl" : {
"lastName" : "ПЕТРОВ",
"firstName" : "ПЕТР",
"patronymic" : "ПЕТРОВИЧ",
"inn" : "123456789021"
},
"capitalPart" : {
"nominal" : 20000.0,
"size" : {
"percent" : 50.0,
"decimalPart" : null,
"simplePart" : null
}
}
} ],
"founderGov" : null,
"founderPIF" : null
},
"capitalPart" : null,
"holderReestrAO" : null,
"okved" : {
"mainOkved" : {
"code" : "47.11",
"name" : "Торговля розничная преимущественно пищевыми продуктами, включая напитки, и табачными изделиями в неспециализированных магазинах"
},
"addOkved" : null
}
}
Для трансформации JSON используется процессор JoltTransformJSON.
Настройки:
Jolt Transformation DSL - тип трансформации. В данном случае Chain - цепочка из нескольких трансформаций
Jolt Specification - собственно сама спецификация. Ее разбор ниже
JOLT спецификация
Собственно, сам субъект - ссылка на исходники и документацию.
Потренироваться можно здесь.
Меня интересовали операции сдвига элементов по иерархии - операция shift и преобразование самих данных - операция modify-overwrite-beta. По последней доки как таковой и нет. Исходники операции в Modifier.java, там можно посмотреть список доступных функций. Но на jolt-demo.appspot.com внизу есть примеры для этой операции. Так что методом научного тыка есть возможность прийти к решению.
JOLT спецификация
[
{
"operation": "modify-overwrite-beta",
"spec": {
"address": {
"addressRF": {
"region": "=concat(@(type), ' ', @(name))",
"district": "=concat(@(type), ' ', @(name))",
"town": "=concat(@(type), ' ', @(name))",
"settlement": "=concat(@(type), ' ', @(name))",
"street": "=concat(@(type), ' ', @(name))"
}
},
"director": {
"*": {
"fl": {
"fio": "=concat(@(1,lastName), ' ', @(1,firstName), ' ', @(1,patronymic))"
}
}
},
"founders": {
"founderFL": {
"*": {
"fl": {
"fio": "=concat(@(1,lastName), ' ', @(1,firstName), ' ', @(1,patronymic))"
}
}
},
"founderGov": {
"*": {
"founderImplFL": {
"fl": {
"fio": "=concat(@(1,lastName), ' ', @(1,firstName), ' ', @(1,patronymic))"
}
}
}
}
}
}
},
{
"operation": "modify-overwrite-beta",
"spec": {
"address": {
"addressRF": {
"value": "=concat(@(1,index), ', ', @(1,region), ', ', @(1,district), ', ', @(1,town), ', ', @(1,settlement), ', ', @(1,street), ', ', @(1,house), ', ', @(1,building), ', ', @(1,apartment))",
"fias": null
}
}
}
},
{
"operation": "shift",
"spec": {
"reportDate|ogrn|ogrnDate|inn|kpp|opfCode|opfName": "&",
"name": {
"*": "&"
},
"address": {
"addressRF": {
"kladr|regionCode|value|fias": "&2.&"
}
},
"termination": {
"method": {
"*": "&2.&"
},
"*": "&1.&"
},
"capital": "&",
"manageOrg": {
"egrulData": {
"*": "&2.&"
}
},
"director": {
"*": {
"fl": {
"fio|inn": "&3[&2].&"
},
"position": {
"name": "&3[&2].&1",
"*": "&3[&2].&"
},
"disqualification": "&2[&1].&"
}
},
"founders": {
"founderULRF|founderULForeign": {
"*": {
"egrulData|foreignReg": {
"*": "&4.&3[&2].&"
},
"*": "&3.&2[&1].&"
}
},
"founderFL": {
"*": {
"fl": {
"fio|inn": "&4.&3[&2].&"
},
"*": "&3.&2[&1].&"
}
},
"founderGov": {
"*": {
"govOrg": {
"*": "&4.&3[&2].&"
},
"capitalPart": "&3.&2[&1].&",
"founderImplUL": {
"egrulData": {
"*": "&5.&4[&3].&2.&"
}
},
"founderImplFL": {
"fl": {
"fio|inn": "&5.&4[&3].&2.&"
}
}
}
},
"founderPIF": {
"*": {
"PIFName": {
"name": "&4.&3[&2].&1"
},
"manageOrg": {
"egrulData": {
"*": "&5.&4[&3].&"
}
},
"capitalPart": "&3.&2[&1].&"
}
}
},
"capitalPart": "&",
"holderReestrAO": {
"egrulData": {
"*": "&2.&"
}
},
"okved": "&"
}
}
]
Операцию modify-overwrite-beta пришлось делать два раза, т.к. по другому собрать адрес в одну строку у меня не получилось.
Как видно, вся спецификация представляет собой массив из трех операций: две - modify-overwrite-beta и одна - shift. Описание каждой операции содержит ее тип - элемент operation и спецификацию - элемент spec.
Преобразование выполняется по цепочке от первого к последнему блоку таким образом, что выходные данные каждого блока служат входными данными для следующего.
Операция modify-overwrite-beta
Спецификация операции содержит левую и правую часть. В левой части требуется указать путь к элементу, который должен быть получен на выходе. В правой части указывается, каким образом должно быть получено содержимое элемента.
Преобразование адреса
Разберем преобразование адреса.
Первый этап (см. первый блок modify-overwrite-beta) - объединить type и name для region, district, town, settlement и street. Для этого прописываем путь к элементам и в правой части для каждого пишем "=concat(@(type), ' ', @(name))"
.
"address": {
"addressRF": {
"region": "=concat(@(type), ' ', @(name))",
"district": "=concat(@(type), ' ', @(name))",
"town": "=concat(@(type), ' ', @(name))",
"settlement": "=concat(@(type), ' ', @(name))",
"street": "=concat(@(type), ' ', @(name))"
}
}
Что это означает. Например, "region": "=concat(@(type), ' ', @(name))",
означает: на выходе требуется получить элемент region, а в качестве его содержимого требуется получить конкатенацию содержимого элементов type и name. Причем искать эти элементы необходимо непосредственно внутри существующего элемента region, о чем говорит конструкция @(type)
.
Второй этап (см. второй блок modify-overwrite-beta) - объединить составляющие адреса в одну строку и записать в элемент value.
"address": {
"addressRF": {
"value": "=concat(@(1,index), ', ', @(1,region), ', ', @(1,district), ', ', @(1,town), ', ', @(1,settlement), ', ', @(1,street), ', ', @(1,house), ', ', @(1,building), ', ', @(1,apartment))",
"fias": null
}
}
Здесь примерно то же самое, но теперь используется конструкция вида @(1,index)
. Она означает, что для поиска элемента index необходимо подняться на один уровень вверх от текущего и искать его там. Т.е. от уровня value необходимо перейти к уровню addressRF, и в пределах addressRF найти элемент index.
Следует обратить внимание, что не должно быть пробелов между =
и concat
, а также в @(1,index)
.
Элемент fias был добавлен в надежде в дальнейшем осуществить поиск кода ФИАС по адресу в каком-нибудь стороннем сервисе.
На этом преобразование адреса завершено. Про операцию shift будет ниже.
Объединение ФИО для физических лиц
Объединение ФИО для физических лиц осуществляется аналогичным образом. Здесь обращает на себя внимание только наличие селектора "*"
в левой части. Он используется, т.к. содержимое элемента director представляет собой массив, а это отдельный уровень иерархии.
"director": {
"*": {
"fl": {
"fio": "=concat(@(1,lastName), ' ', @(1,firstName), ' ', @(1,patronymic))"
}
}
}
Операция shift
В блок shift на вход поступает следующий JSON.
Промежуточный JSON
{
"reportDate" : "2020-05-20",
"ogrn" : "1234567890123",
"ogrnDate" : "2002-12-30",
"inn" : "1234567890",
"kpp" : "123456789",
"opfCode" : "12300",
"opfName" : "Общества с ограниченной ответственностью",
"name" : {
"fullName" : "ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ",
"shortName" : "ООО"
},
"address" : {
"addressRF" : {
"region" : "ОБЛАСТЬ МОСКОВСКАЯ",
"district" : " ",
"town" : "ГОРОД ИСТРА",
"settlement" : " ",
"street" : "ПЕРЕУЛОК ВОЛОКОЛАМСКИЙ",
"index" : "143500",
"regionCode" : "50",
"kladr" : "500000570000011",
"house" : null,
"building" : null,
"apartment" : null,
"value" : "143500, ОБЛАСТЬ МОСКОВСКАЯ, , ГОРОД ИСТРА, , ПЕРЕУЛОК ВОЛОКОЛАМСКИЙ, , , ",
"fias" : null
}
},
"termination" : null,
"capital" : null,
"manageOrg" : null,
"director" : [ {
"fl" : {
"lastName" : "ИВАНОВ",
"firstName" : "ИВАН",
"patronymic" : "ИВАНОВИЧ",
"inn" : "123456789012",
"fio" : "ИВАНОВ ИВАН ИВАНОВИЧ"
},
"position" : {
"ogrnip" : null,
"typeCode" : "02",
"typeName" : "Руководитель юридического лица",
"name" : "ГЕНЕРАЛЬНЫЙ ДИРЕКТОР"
},
"disqualification" : null
} ],
"founders" : {
"founderULRF" : null,
"founderULForeign" : null,
"founderFL" : [ {
"fl" : {
"lastName" : "ИВАНОВ",
"firstName" : "ИВАН",
"patronymic" : "ИВАНОВИЧ",
"inn" : "123456789012",
"fio" : "ИВАНОВ ИВАН ИВАНОВИЧ"
},
"capitalPart" : {
"nominal" : 20000,
"size" : {
"percent" : 50,
"decimalPart" : null,
"simplePart" : null
}
}
}, {
"fl" : {
"lastName" : "ПЕТРОВ",
"firstName" : "ПЕТР",
"patronymic" : "ПЕТРОВИЧ",
"inn" : "123456789021",
"fio" : "ПЕТРОВ ПЕТР ПЕТРОВИЧ"
},
"capitalPart" : {
"nominal" : 20000,
"size" : {
"percent" : 50,
"decimalPart" : null,
"simplePart" : null
}
}
} ],
"founderGov" : null,
"founderPIF" : null
},
"capitalPart" : null,
"holderReestrAO" : null,
"okved" : {
"mainOkved" : {
"code" : "47.11",
"name" : "Торговля розничная преимущественно пищевыми продуктами, включая напитки, и табачными изделиями в неспециализированных магазинах"
},
"addOkved" : null
}
}
Как видно, остались лишние элементы - например, данные адреса, фамилия, имя отчество. Стоит отметить, что если в операции modify-overwrite-beta не указано преобразование для элемента, то он переносится в неизменном виде. В отличие от этого, в операции shift - если преобразование для элемента не указано, то он будет удален.
Описание операции shift
{
"operation": "shift",
"spec": {
"reportDate|ogrn|ogrnDate|inn|kpp|opfCode|opfName": "&",
"name": {
"*": "&"
},
"address": {
"addressRF": {
"kladr|regionCode|value|fias": "&2.&"
}
},
"termination": {
"method": {
"*": "&2.&"
},
"*": "&1.&"
},
"capital": "&",
"manageOrg": {
"egrulData": {
"*": "&2.&"
}
},
"director": {
"*": {
"fl": {
"fio|inn": "&3[&2].&"
},
"position": {
"name": "&3[&2].&1",
"*": "&3[&2].&"
},
"disqualification": "&2[&1].&"
}
},
"founders": {
"founderULRF|founderULForeign": {
"*": {
"egrulData|foreignReg": {
"*": "&4.&3[&2].&"
},
"*": "&3.&2[&1].&"
}
},
"founderFL": {
"*": {
"fl": {
"fio|inn": "&4.&3[&2].&"
},
"*": "&3.&2[&1].&"
}
},
"founderGov": {
"*": {
"govOrg": {
"*": "&4.&3[&2].&"
},
"capitalPart": "&3.&2[&1].&",
"founderImplUL": {
"egrulData": {
"*": "&5.&4[&3].&2.&"
}
},
"founderImplFL": {
"fl": {
"fio|inn": "&5.&4[&3].&2.&"
}
}
}
},
"founderPIF": {
"*": {
"PIFName": {
"name": "&4.&3[&2].&1"
},
"manageOrg": {
"egrulData": {
"*": "&5.&4[&3].&"
}
},
"capitalPart": "&3.&2[&1].&"
}
}
},
"capitalPart": "&",
"holderReestrAO": {
"egrulData": {
"*": "&2.&"
}
},
"okved": "&"
}
}
В операции shift присутствуют левая и правая часть инструкции. Левая часть указывает, где брать данные, а правая указывает путь, куда их разместить. Путь представляет собой цепочку наименований элементов, разделенных точкой. С помощью знака &
осуществляется подстановка наименований существующих элементов. Исчисление начинается с того элемента, который указан в левой части, ему соответствует &0
. Ноль при этом можно опустить. Выше него по иерархии будет &1
, и т.д. К знакам &
можно добавлять префиксы и суффиксы - например, pre-&-post
. Т.е. если &
соответствует элементу name, то на выходе получим pre-name-post. Результирующая цепочка элементов размещается в корне иерархии. Рассмотрим на примерах.
Самое простое - "reportDate|ogrn|ogrnDate|inn|kpp|opfCode|opfName": "&"
. Будет взят каждый из перечисленных элементов, и они будут размещены в корне. Перечисление осуществляется с помощью |
.
Далее переносим fullName и shortName на один уровень вверх с помощью инструкции "name": { "*": "&" }
."*"
означает, что требуется выбрать содержимое всех элементов, вложенных в name
."&"
означает, что их требуется разместить в корне иерархии.
Следующее - перенос данных адреса.
"address": {
"addressRF": {
"kladr|regionCode|value|fias": "&2.&"
}
}
Здесь мы указываем нужные элементы. Ненужные не указываем. Инструкция для размещения - "&2.&"
. Она означает, что требуется составить цепочки из нулевого и второго уровня, минуя первый. &2
соответствует элементу address, а &
- элементам из перечисления. &1
соответствует элементу addressRF, он будет удален из иерархии. Т.обр. будут составлены четыре цепочки: address.kladr, address.regionCode, address.value и address.fias. И все они буду размещены в корне результирующего JSON.
Массивы разберем на примере данных о директоре
"director" : [ {
"fl" : {
"lastName" : "ИВАНОВ",
"firstName" : "ИВАН",
"patronymic" : "ИВАНОВИЧ",
"inn" : "123456789012",
"fio" : "ИВАНОВ ИВАН ИВАНОВИЧ"
},
"position" : {
"ogrnip" : null,
"typeCode" : "02",
"typeName" : "Руководитель юридического лица",
"name" : "ГЕНЕРАЛЬНЫЙ ДИРЕКТОР"
},
"disqualification" : null
} ]
Нужно убрать lastName, firstName и patronymic.
inn и fio перенести на один уровень выше.
ogrnip, typeCode и typeName также перенести на один уровень выше.
Значение name установить в качестве значения position.
disqualification оставить без изменений.
В общем-то алгоритм действий тот же самый, но следуют помнить, что массив - это отдельный уровень иерархии. Когда работаем с массивом, то в цепочке иерархии соответствующий ему &
должен быть помещен в квадратные скобки - [&]
.
"director": {
"*": {
"fl": {
"fio|inn": "&3[&2].&"
},
"position": {
"name": "&3[&2].&1",
"*": "&3[&2].&"
},
"disqualification": "&2[&1].&"
}
}
Например, fio и inn. Для них цепочка &3[&2].&
. Точку перед открывающей квадратной скобкой можно опустить. Получаем: &3
- соответствует элементу director, [&2]
- соответствует уровню элементов массива, &
- сами fio и inn.
Элемент name в position. &3
- соответствует элементу director, [&2]
- соответствует уровню элементов массива, &1
- соответствует элементу position. &
, соответствующий самому элементу name отсутствует, значит его содержимое будет перенесено в position.
Остальные элементы в position просто переносятся на один уровень вверх. disqualification остается без изменений.
Далее используются аналогичные конструкции.
Пример
Ну и напоследок продублирую исходный JSON, JOLT спецификацию и результирующий JSON
Исходный JSON
{
"reportDate": "2020-05-20",
"ogrn": "1234567890123",
"ogrnDate": "2002-12-30",
"inn": "1234567890",
"kpp": "123456789",
"opfCode": "12300",
"opfName": "Общества с ограниченной ответственностью",
"name": {
"fullName": "ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ",
"shortName": "ООО"
},
"address": {
"addressRF": {
"region": {
"type": "ОБЛАСТЬ",
"name": "МОСКОВСКАЯ"
},
"district": null,
"town": {
"type": "ГОРОД",
"name": "ИСТРА"
},
"settlement": null,
"street": {
"type": "ПЕРЕУЛОК",
"name": "ВОЛОКОЛАМСКИЙ"
},
"index": "143500",
"regionCode": "50",
"kladr": "500000570000011",
"house": null,
"building": null,
"apartment": null
}
},
"termination": null,
"capital": null,
"manageOrg": null,
"director": [
{
"fl": {
"lastName": "ИВАНОВ",
"firstName": "ИВАН",
"patronymic": "ИВАНОВИЧ",
"inn": "123456789012"
},
"position": {
"ogrnip": null,
"typeCode": "02",
"typeName": "Руководитель юридического лица",
"name": "ГЕНЕРАЛЬНЫЙ ДИРЕКТОР"
},
"disqualification": null
}
],
"founders": {
"founderULRF": null,
"founderULForeign": null,
"founderFL": [
{
"fl": {
"lastName": "ИВАНОВ",
"firstName": "ИВАН",
"patronymic": "ИВАНОВИЧ",
"inn": "123456789012"
},
"capitalPart": {
"nominal": 20000,
"size": {
"percent": 50,
"decimalPart": null,
"simplePart": null
}
}
},
{
"fl": {
"lastName": "ПЕТРОВ",
"firstName": "ПЕТР",
"patronymic": "ПЕТРОВИЧ",
"inn": "123456789021"
},
"capitalPart": {
"nominal": 20000,
"size": {
"percent": 50,
"decimalPart": null,
"simplePart": null
}
}
}
],
"founderGov": null,
"founderPIF": null
},
"capitalPart": null,
"holderReestrAO": null,
"okved": {
"mainOkved": {
"code": "47.11",
"name": "Торговля розничная преимущественно пищевыми продуктами, включая напитки, и табачными изделиями в неспециализированных магазинах"
},
"addOkved": null
}
}
JOLT спецификация
[
{
"operation": "modify-overwrite-beta",
"spec": {
"address": {
"addressRF": {
"region": "=concat(@(type), ' ', @(name))",
"district": "=concat(@(type), ' ', @(name))",
"town": "=concat(@(type), ' ', @(name))",
"settlement": "=concat(@(type), ' ', @(name))",
"street": "=concat(@(type), ' ', @(name))"
}
},
"director": {
"*": {
"fl": {
"fio": "=concat(@(1,lastName), ' ', @(1,firstName), ' ', @(1,patronymic))"
}
}
},
"founders": {
"founderFL": {
"*": {
"fl": {
"fio": "=concat(@(1,lastName), ' ', @(1,firstName), ' ', @(1,patronymic))"
}
}
},
"founderGov": {
"*": {
"founderImplFL": {
"fl": {
"fio": "=concat(@(1,lastName), ' ', @(1,firstName), ' ', @(1,patronymic))"
}
}
}
}
}
}
},
{
"operation": "modify-overwrite-beta",
"spec": {
"address": {
"addressRF": {
"value": "=concat(@(1,index), ', ', @(1,region), ', ', @(1,district), ', ', @(1,town), ', ', @(1,settlement), ', ', @(1,street), ', ', @(1,house), ', ', @(1,building), ', ', @(1,apartment))",
"fias": null
}
}
}
},
{
"operation": "shift",
"spec": {
"reportDate|ogrn|ogrnDate|inn|kpp|opfCode|opfName": "&",
"name": {
"*": "&"
},
"address": {
"addressRF": {
"kladr|regionCode|value|fias": "&2.&"
}
},
"termination": {
"method": {
"*": "&2.&"
},
"*": "&1.&"
},
"capital": "&",
"manageOrg": {
"egrulData": {
"*": "&2.&"
}
},
"director": {
"*": {
"fl": {
"fio|inn": "&3[&2].&"
},
"position": {
"name": "&3[&2].&1",
"*": "&3[&2].&"
},
"disqualification": "&2[&1].&"
}
},
"founders": {
"founderULRF|founderULForeign": {
"*": {
"egrulData|foreignReg": {
"*": "&4.&3[&2].&"
},
"*": "&3.&2[&1].&"
}
},
"founderFL": {
"*": {
"fl": {
"fio|inn": "&4.&3[&2].&"
},
"*": "&3.&2[&1].&"
}
},
"founderGov": {
"*": {
"govOrg": {
"*": "&4.&3[&2].&"
},
"capitalPart": "&3.&2[&1].&",
"founderImplUL": {
"egrulData": {
"*": "&5.&4[&3].&2.&"
}
},
"founderImplFL": {
"fl": {
"fio|inn": "&5.&4[&3].&2.&"
}
}
}
},
"founderPIF": {
"*": {
"PIFName": {
"name": "&4.&3[&2].&1"
},
"manageOrg": {
"egrulData": {
"*": "&5.&4[&3].&"
}
},
"capitalPart": "&3.&2[&1].&"
}
}
},
"capitalPart": "&",
"holderReestrAO": {
"egrulData": {
"*": "&2.&"
}
},
"okved": "&"
}
}
]
Результирующий JSON
{
"reportDate" : "2020-05-20",
"ogrn" : "1234567890123",
"ogrnDate" : "2002-12-30",
"inn" : "1234567890",
"kpp" : "123456789",
"opfCode" : "12300",
"opfName" : "Общества с ограниченной ответственностью",
"fullName" : "ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ",
"shortName" : "ООО",
"address" : {
"kladr" : "500000570000011",
"regionCode" : "50",
"value" : "143500, ОБЛАСТЬ МОСКОВСКАЯ, , ГОРОД ИСТРА, , ПЕРЕУЛОК ВОЛОКОЛАМСКИЙ, , , ",
"fias" : null
},
"capital" : null,
"director" : [ {
"fio" : "ИВАНОВ ИВАН ИВАНОВИЧ",
"inn" : "123456789012",
"ogrnip" : null,
"typeCode" : "02",
"typeName" : "Руководитель юридического лица",
"position" : "ГЕНЕРАЛЬНЫЙ ДИРЕКТОР",
"disqualification" : null
} ],
"founders" : {
"founderFL" : [ {
"fio" : "ИВАНОВ ИВАН ИВАНОВИЧ",
"inn" : "123456789012",
"capitalPart" : {
"nominal" : 20000,
"size" : {
"percent" : 50,
"decimalPart" : null,
"simplePart" : null
}
}
}, {
"fio" : "ПЕТРОВ ПЕТР ПЕТРОВИЧ",
"inn" : "123456789021",
"capitalPart" : {
"nominal" : 20000,
"size" : {
"percent" : 50,
"decimalPart" : null,
"simplePart" : null
}
}
} ]
},
"capitalPart" : null,
"okved" : {
"mainOkved" : {
"code" : "47.11",
"name" : "Торговля розничная преимущественно пищевыми продуктами, включая напитки, и табачными изделиями в неспециализированных магазинах"
},
"addOkved" : null
}
}
Далее
Далее получившийся JSON следует куда-то разместить для хранения и дальнейшего использования. Но это выходит за рамки повествования. Тут уж кому что удобно.
babylon
За такие структуры данных надо немедленно увольнять!
Maximario Автор
Не затруднит ли Вас изложить подробнее свою мысль?