3

我需要从 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
}
4

3 回答 3

2

重读你的问题,做你想做的最简单的方法是

  1. 获取页面加载时的 Json 数据,
  2. 遍历 json 数据以删除有效值(参见示例 1),
  3. 调用 tv4.validateMultiple(data, schema),
  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;
于 2018-01-16T20:58:36.323 回答
0

We solved it by:

  1. Forking tv4 (tv4 - because it was easy to edit):

    https://github.com/mikila85/tv4

    outputting an array of "Requireds".

  2. We itereted each required field, emptying it's data and sending data+schema to AJV for validation (AJV and not tv4 because its faster at parsing).

By doing that we could know individually which required field is required for the given data.

these are the working functions we came out with (not the cleanest but will help get the idea)

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.");
}
于 2018-01-21T12:50:59.540 回答
-1

这个函数递归地抓取模式索引,所以也许你可以稍微调整一下

   // 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;
    }
于 2018-01-04T17:23:21.090 回答