Схема JSON извлекает обязательные поля

Мне нужно получить список обязательных полей из JSON-Schema+Data.

В настоящее время мы используем AJV для получения сообщений об ошибках в наших формах с помощью JSON Schema, и это прекрасно работает.

Мне нужен способ получить все обязательные поля (даже если они заполнены), чтобы пометить эти поля * как "обязательные". обязательные поля могут меняться в зависимости от схемы и комбинации данных.

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

Пожалуйста помоги.


Пример для такой схемы:

{
  "type": "object",
  "required": [
    "checkbox"
  ],
  "properties": {
    "checkbox": {
      "type": "boolean"
    },
    "textbox": {
      "type": "string"
    }
  },
  "oneOf": [
    {
      "required": [
        "textbox"
      ],
      "properties": {
        "checkbox": {
          "enum": [
            true
          ]
        }
      }
    },
    {
      "properties": {
        "checkbox": {
          "enum": [
            false
          ]
        }
      }
    }
  ],
  "additionalProperties": false
}

3 ответа

Решение

Перечитав свой вопрос, самый простой способ сделать то, что вы хотели бы, это

  1. получить данные Json при загрузке страницы,
  2. переберите данные json, чтобы удалить допустимые значения (см. пример 1),
  3. Вызовите tv4.validateMultiple(данные, схема),
  4. проверьте объект результата и получите необходимые поля (см. пример 2).

образец 1

for(let prop in data) {
    if(data.hasOwnProperty(prop) {
        //set value to null, -1, or some other universally bad value
        data[prop]...value = null;
    }
}

образец 2

let result = tv4.validateMultiple(data, schema);
let required = result.errors;

Мы решили это путем:

  1. Форкинг тв4 (тв4 - потому что его было легко редактировать):

    https://github.com/mikila85/tv4

    вывод массива "Requireds".

  2. Мы выполнили итерацию каждого обязательного поля, очистив его данные и отправив данные + схему в AJV для проверки (AJV, а не tv4, потому что он быстрее разбирается).

Сделав это, мы могли бы узнать индивидуально, какое обязательное поле является обязательным для данных.

это те рабочие функции, с которыми мы работали (не самые чистые, но помогут понять идею)

function getAllRequiredFields() {
    var allRequiredFields = tv4.validateMultiple($scope.formModel, $scope.formSchema).requireds;
    allRequiredFields = allRequiredFields.filter(function onlyUnique(value, index, self) {
        return self.indexOf(value) === index;
    });

    return allRequiredFields;
}

function getRequiredFields() {
    var t0 = performance.now();

    //should be called every model change because of optimization in tv4 for the data+schema.
    var allRequiredFields = getAllRequiredFields();
    angular.forEach(allRequiredFields, function (requiredPath) {
        var modelWithDeletedRequiredProperty = angular.copy($scope.formModel);

        deleteValue(modelWithDeletedRequiredProperty, requiredPath);
        if (!validateForm(modelWithDeletedRequiredProperty)) {

            var requiredError = getErrorObjectsArray(validateForm.errors).find(function (error) {
                return error.path === requiredPath;
            });

            if (requiredError) {
                localValidation[requiredError.inputName] = localValidation[requiredError.inputName] || {};
                localValidation[requiredError.inputName].isRequired = true;
                requiredFieldsPath.push(requiredError.inputName);
            }
        }
    });

    var t1 = performance.now();
    console.log("form checking took " + (t1 - t0) + " milliseconds.");
}

Эта функция рекурсивно захватывает индексы схемы, так что, возможно, вы могли бы немного ее адаптировать

   // https://github.com/pubkey/rxdb/blob/master/src/rx-schema.js
 export function getIndexes(jsonID, prePath = '') {
        let indexes = [];
        Object.entries(jsonID).forEach(entry => {
            const key = entry[0];
            const obj = entry[1];
            const path = key === 'properties' ? prePath : util.trimDots(prePath + '.' + key);

            if (obj.index)
                indexes.push([path]);

            if (typeof obj === 'object' && !Array.isArray(obj)) {
                const add = getIndexes(obj, path);
                indexes = indexes.concat(add);
            }
        });

        if (prePath === '') {
            const addCompound = jsonID.compoundIndexes || [];
            indexes = indexes.concat(addCompound);
        }

        indexes = indexes
            .filter((elem, pos, arr) => arr.indexOf(elem) === pos); // unique;
        return indexes;
    }
Другие вопросы по тегам