Парсинг JSON

+5 голосов
newbie в категории Как сделать...

Добрый день, коллеги!

Получаем ответ веб-сервиса в формате JSON со множественными вложенными сущностями.

Подскажите, каким лучше образом можно распарсить такой ответ в выходную таблицу.

Спасибо!

Ответ: 1 шт.

+2 голосов
vitaliy.tatarskih
 
Лучший ответ

Решение этой задачи удобно реализовать при помощи компонента JavaScript. Создадим узел, перетащив компонент JavaScript из палитры инструментов на рабочую область сценария. В табличном входном порту определим поле txtJSON, принимающее текст JSON:

Во входном порту переменных создадим переменную JSON с текстовым типом данных:

Такой узел сможет принимать входные данные с текстом JSON как на табличный входной порт, так и на порт переменных. 

Если структура JSON заранее не известна, то в выходном наборе узла JavaScript она может быть представлена в формате key-value. Зададим ее в настройке выходной таблицы:

В выходном наборе поле кеу содержит ключ элемента JSON, а value - его значение. Дополнительные поля: id (индекс строки входного набора, содержащей JSON), parent (путь к элементу в иерархии JSON), type (тип данных элемента). В редакторе кода узла создается следующий скрипт:


import {InputTable, InputVariables, OutputTable} from "builtIn/Data";

let txtJSON;

let obj;

// Проверяем наличие данных во входной наборе. 

// Если табличный порт задействован, то обрабатываем данные этого порта. 

// В противном случае обрабатываем данные порта входных переменных.

if (InputTable){

 for (let j=0, c = InputTable.RowCount; j < c; j++){  // Цикл по строкам входного набора.

        txtJSON = InputTable.Get(j, 'txtJSON');    // Переменная txtJSON принимает текст JSON из поля 'txtJSON' входного набора.

        obj = JSON.parse(txtJSON);       // Переменная obj принимает объект JSON

        get_elements(j, obj);        // и далее передается в функцию обработки объекта JSON 'get_elements(id, o, p = 'root')'.

 }

}else{

 console.log("Табличный порт не задействован");

    txtJSON = InputVariables.Items.JSON.Value;    // Переменная txtJSON принимает текст JSON из переменной 'JSON' входного порта.

    if (txtJSON){           // Если txtJSON содержит значение,

     obj = JSON.parse(txtJSON);       // то obj принимает объект JSON

     get_elements('Порт переменных', obj);    // и далее передается в функцию обработки объекта JSON.

    }else{console.log('Переменная <JSON> входного порта не задана')}

}

// Функция обработки объекта JSON.

// Принимает параметры:

// id - идентификатор строки входного набора;

// o - объект JSON;

// p - parent элемента JSON (по умолчанию = 'root').

function get_elements(id, o, p = 'root') {

  let i;

  for (let k in o) {          // Цикл по элементам JSON.

    i = o[k];            // Переменная i принимает текущий элемент JSON.

    if (typeof i != 'object') {        // Если элемент не имеет подчиненных,

        append(id, p, k, typeof i, i);      // то просто выводиться в выходной набор данных функцией 'append(id, parent, key, type, value)'.

    } else {            // В противном случае:

        append(id, p, k, typeof i);       // выводится в выходной набор

        get_elements(id, i, p + ':' + k);     // и передается на обработку подчиненных элементов рекурсивным вызовом данной функции.

    }

  }

}

// Функция вывода элемента JSON в выходной набор данных.

// Принимает параметры:

// id - идентификатор строки входного набора;

// parent - parent элемента JSON;

// key - идентификатор элемента JSON;

// type - тип элемента JSON;

// value - значение элемента JSON.

function append(id, parent = null, key = null, type = null, value = null) {

 OutputTable.Append();         // Добавление новой строки в выходной набор.

    OutputTable.Set('id', id);        // Установка значения заданного поля в добавленной строке.

    OutputTable.Set('parent', parent);

    OutputTable.Set('key', key);

    OutputTable.Set('type', type);

    OutputTable.Set('value', value);

}


 Созданный узел парсит JSON произвольной структуры. Выходной набор в формате key-value фактически является таблицей со свернутыми столбцами. Развернуть такую таблицу в обычное представление можно при помощи компонента Кросс-таблица, предварительно выделив из нее при помощи фильтра только необходимые данные. 

Пример в архиве: ParseJSONcomponent.zip

Илья Сильянов
Коллеги, есть ли какие либо ограничения по длине входной строки? на вход может подаваться достаточно длинная строка (более 1млн. символов), не будет ли наблюдаться при этом проблем с работой компоненты и всего сервера?
vitaliy.tatarskih

Теоретически ограничение на длину входной строки ~ 1 млрд. символов. Ограничения со стороны производительности для больших строк необходимо определять эмпирически, поскольку присутствуют зависимости от многих факторов. Для кода, приведенного в примере, так же есть ограничение на количество рекурсивных вызовов (~ 600) функции get_elements(), которое определяется уровнем вложенности элементов JSON. При большем уровне вложенности можно, как вариант, применять асинхронный вызов этой функции.

Ravil

Пользуюсь вашим скриптом и выходит такая ошибка, в чем может быть причина?

parseJSON #1: SyntaxError: JSON.parse Error: Invalid character at position:1
at Anonymous function (<main>:12:9)
at module (<main>:1:1)

vitaliy.tatarskih

Проверьте пожалуйста корректность JSON, который поступает на вход узла JS. Как вариант: перед текстом JSON присутствуют лишние символы.

...