Проверьте каждый узел JSON с другой схемой JSON - PullRequest
0 голосов
/ 25 ноября 2018

Я пытаюсь сделать системный монитор, который очень настраивается пользователем.Эта настройка достигается с помощью файла JSON для моделирования внешнего вида системного монитора.JSON может выглядеть следующим образом.

{
  "_": "WINDOW",
  "name": "myWindow",
  "children": [
    {
      "_": "CPU",
      "name": "cpuMonitor",
      "freq_Unit": "MHZ"
    },
    {
      "_": "NETWORK",
      "name": "network",
      "unit": "Kb/s"
    },
    {
      "_": "DISK",
      "name": "disk"
    }
  ],
  "background": "red"
}

Как видите, каждый объект соответствует этой схеме.

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "name":"Component",
    "type": "object",
    "properties":{
        "_": {
            "type": "string"
        },
        "name":{
            "type":"string"
        },
        "childern":{
            "type":"array"
        }
    },

    "required": ["_","name"]
}

Но у каждого компонента также есть свое определение схемы.Я хотел бы проанализировать весь JSON и проверить каждый узел на предмет разной схемы (сначала, если его компонент, а затем соответствующая схема).

Я посмотрел на rapidJson и другие библиотеки, но я не нашел решения для проверкиузлы для разных схем.Вы знаете какую-нибудь библиотеку, которая могла бы сделать это?Или даже можно проверить JSON таким способом?

Все отзывы о том, как решить эту проблему, будут оценены.

Редактировать: Исправленная схема :(

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

В дополнение к ответу Ульриха , вот пример того, что я бы сделал:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Component",
  "type": "object",
  "definitions": {
    "base": {
      "properties": {
        "name": { "type": "string" },
        "children": {
          "type": "array",
          "items": { "$ref": "#" }
        }
      },
      "required": [ "_", "name" ]
    },
    "cpu": {
      "properties": {
        "_": { "const": "CPU" },
        "freq_Unit": "MHZ"
      }
    },
    "network": {
      "properties": {
        "_": { "const": "NETWORK" },
        "unit": "Kb/s"
      }
    },
    "disk": {
      "properties": {
        "_": { "const": "DISK" }
      }
    },
    "window": {
      "properties": {
        "_": { "const": "WINDOW" },
        "background": { "enum": [ "red", "orange", "yellow", ... ] }
      }
    }
  },
  "allOf": [
    { "$ref": "#/definitions/base" },
    {
      "oneOf": [
        { "$ref": "#/definitions/cpu" },
        { "$ref": "#/definitions/network" },
        { "$ref": "#/definitions/disk" },
        { "$ref": "#/definitions/window" }
      ]
    }
  ]
}

Во-первых, мы требуем, чтобы любой экземпляр ДОЛЖЕН придерживаться base, который объявляет _ и name как обязательные свойства.Кроме того, мы объявляем свойство массива children, которое требует, чтобы все элементы также соответствовали этой схеме (что дает нам рекурсивное поведение).Это на самом деле мало что дает, за исключением того, что позволяет нам объявлять эти вещи в одном месте вместо того, чтобы объявлять их в трех других определениях.

(Обратите внимание, что мы не объявляем _ всписок свойств. Это означает, что любое значение будет передано для этой части схемы. Мы очистим его в следующей части. Если вы хотите, чтобы будущие компоненты были объявлены со строками, то вы можете добавить"type": "string" требование к этому свойству, но я не думаю, что оно необходимо, если другие не создают эти компоненты.)

Во-вторых, мы объявляем каждый из наших конкретных типов как отдельные определения, используя ключевое слово const дляизолировать тот, который мы хотим.Эта конструкция аналогична инструкции switch (или case).Если экземпляр не соответствует ни одному из этих явных параметров, произойдет сбой.Если в нем отсутствует одно из обязательных базовых свойств, оно завершается неудачей.

Это приведет вас туда, где вы хотите быть.

Чтобы продвинуться дальше, есть еще две вещи, которые вы можете сделать:

  1. Добавьте required к другим определениям, чтобы сказать, что также необходимы определенные свойства (например, freq_Unit для определения cpu).
  2. Объявите каждое из определений вотдельные файлы.Это позволит вам добавить новое определение, просто добавив новый файл и ссылаясь на него в основной схеме.На мой взгляд, это немного чище.Однако некоторые люди предпочитают хранить все это в одном файле.
0 голосов
/ 25 ноября 2018

С этим связан простой подход: используйте объявление шаблона oneOf, чтобы указать расположение элементов массива.Внутри этих вложенных объявлений вы указываете фиксированный идентификатор (возможно, содержимое вашего поля _) в качестве константы, поэтому существует только одна вложенная схема, соответствующая каждому из ваших типов панелей.

Примечания:

  • Мне пришлось указать идентификатор типа константы, используя спецификатор enum, потому что обычный спецификатор constant не работал с библиотекой, которую я использовал.Это также могло быть упущением при пересмотре спецификации, на которой она была основана.
  • Другой подход заключается в разделении шагов проверки.Вы просто проверяете, что элементы массива являются объектами и имеют строковое поле _, содержащее один из поддерживаемых типов.При выполнении итерации по массиву вы затем проверяете каждое поле индивидуально в соответствии с его полем _.
...