поддержка std::map‹ std::string, T › в схеме json

Существует ли стандартный подход к указанию свойства как словаря или карты с ключом строки с типом значения T, указанным где-то еще в схеме?

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

Я предполагаю, что вы могли бы сначала смоделировать MovieDataPair как тип со свойством name и свойством value, содержащим нужные атрибуты. Тогда карта будет массивом из них. Но тогда вам потребуется специальное уникальное ограничение, которое гарантирует, что любое название фильма появится только один раз.

Есть ли что-то в схеме json для поддержки этого или стандартный шаблон, используемый для этого? Если нет встроенной поддержки в схеме json, как насчет других решений схемы?


person user1338952    schedule 30.07.2013    source источник
comment
Спасибо, что задали (и ответили!) на этот вопрос, это именно то, что я искал.   -  person T.W.R. Cole    schedule 13.06.2014


Ответы (3)


После некоторого изучения я пришел к следующему ответу:

Лучший способ увидеть это в действии — найти несколько примеров. Бывает, что в самой схеме draft04 есть несколько примеров этого (определения, свойства, patternProperties,...), и они обычно следуют тот же узор.

Например, свойство definitions схемы draft04 определяет, что должно отображаться в схеме в свойстве definitions. Вот подсхема, связанная со свойством definitions:

"definitions": {
    "type": "object",
    "additionalProperties": { "$ref": "#" },
    "default": {}
},

Это говорит о том, что запись в "#/definitions/" должна быть объектом. Тот факт, что это объект json, означает, что он сам будет иметь уникальные ключи. Теперь, что касается значений в объекте, это то, что описывает additionalProperties. В данном случае это говорит о том, что значение каждого свойства само должно соответствовать корню схемы "#". Это означает, что каждое значение в объекте свойства definitions допустимого объекта схемы json также должно быть схемой. Если бы это было набрано как C++, это могло бы выглядеть так:

std::map< std::string, Schema > definitions;

По сути, карту со строковым ключом можно рассматривать как объект json со структурированным типом значения. Итак, для создания собственного:

std::map< std::string, T >
  • Сначала определите схему для T. Например:

    "definitions" : {
       "movie" : {
           "properties": {
              "title" : { "type" : "string" },
              "year_made" : { "type" : "integer" },
              "rating" : { "type" : "integer" }
           }
        }
    }
    
  • Для сохраненного типа значения T решите, хотите ли вы разрешить какие-либо свойства, если эти указанные свойства имеют тип, указанный выше. Если вам нужны только эти свойства, добавьте "additionalProperties" : false

     "definitions" : {
       "movie" : {
           "additionalProperties" : false,
           "properties": {
              "title" : { "type" : "string" },
              "year_made" : { "type" : "integer" },
              "rating" : { "type" : "integer" }
           }
        }
     }
    
  • Также решите, действительно ли вам требуется, чтобы все свойства присутствовали, чтобы фильм был действительным. Если это так, добавьте обязательную запись.

    "definitions" : {
      "movie" : {
        "additionalProperties": false,
        "required" : [ "title", "year_made", "rating" ],
        "properties": {
          "title" : { "type" : "string" },
          "year_made" : { "type" : "integer" },
          "rating" : { "type" : "integer" }
      }
    },
    
  • Теперь форма T для фильма определена. Создайте определение для коллекции или карту фильмов, ссылающихся на схему фильма, определенную, как это было сделано с помощью определений в черновике схемы. Примечание: в "movie_map" дополнительные свойства имеют другое значение, чем значение "movie". В случае "movie" это логическое значение false, указывающее на отсутствие дополнительных свойств помимо тех, что перечислены в properties. В случае "movie_map" это означает - если есть дополнительные свойства, они должны выглядеть как эта схема. Но, поскольку в movie_map не указано никаких свойств, на самом деле это означает, что все свойства в экземпляре объекта должны соответствовать #/definitions/movie. Теперь все значения в "movie_map" будут выглядеть как определенная схема movie.

    {
      "definitions" : {
        "movie" : {
          "additionalProperties": false,
          "required" : [ "title", "year_made", "rating" ],
          "properties": {
            "title" : { "type" : "string" },
            "year_made" : { "type" : "integer" },
            "rating" : { "type" : "integer" }
          }
        },
        "movie_map" : {
          "type": "object",
          "additionalProperties": { "$ref": "#/definitions/movie" },
          "default": {}
        }
      }
    }
    
  • Теперь используйте определенную схему movie_map где-нибудь внутри схемы:

    {
      "title" : "movie data",
      "additionalProperties" : false,
      "required" : [ "movies" ],
      "properties" : {
        "movies" : { "$ref" : "#/definitions/movie_map" }
      },
      "definitions" : {
        "movie" : {
          "additionalProperties": false,
          "required" : [ "title", "year_made", "rating" ],
          "properties": {
            "title" : { "type" : "string" },
            "year_made" : { "type" : "integer" },
            "rating" : { "type" : "integer" }
          }
        },
        "movie_map" : {
          "type": "object",
          "additionalProperties": { "$ref": "#/definitions/movie" },
          "default": {}
        }
      }
    }
    

Вот пример объекта, который можно рассматривать как карту фильмов, который проверяется на соответствие схеме:

{
  "movies" : {
    "the mission" : {
      "title":"The Mission",
      "year_made":1986,
      "rating":5
    },
    "troll 2" : {
      "title":"Troll 2",
      "year_made":1990,
      "rating":2
    }
  }
}

введите здесь описание изображения

person user1338952    schedule 30.08.2013
comment
Я пытаюсь решить тот же вариант использования, но в настоящее время модули Jackson 2.4.2 не получают этот тип схемы для HashMap‹String, POJO›, я вижу github.com/FasterXML/jackson-module-jsonSchema этот модуль решает схемы такого типа, но у него все еще есть проблема с самостоятельными ссылками, которая решается. будет исправлено в 2.4.1 для этого модуля. Итак, как мы должны обрабатывать такие ситуации для текущих ситуаций, используя Jackson Parser. Я не знаю, уместно ли задавать этот вопрос, но, похоже, вы провели много исследований по этому поводу. - person Piyush Jajoo; 27.09.2014

Если бы я хотел смоделировать структуру для любимых фильмов пользователей (напомним, что схема Json предназначена для проверки структуры), я бы сделал что-то вроде:

{
"description":"moviesFan",
"properties": [
    "favoriteMovies": {
        "type":"array",
        "uniqueItems":True
        "allOf": [{ "$ref": "#/definitions/movie" }]
    }
],
"definitions": {
    "movie": {
        "type": "object",
        "properties": {
            "yearMade": {}
            ...
        }
    }
}

Имеет ли это смысл для вас?

person jruizaranguren    schedule 22.08.2013
comment
Полезно, но мне нужна именно карта, где ключом является строка (заголовок), а значением является набор фиксированных свойств. Я хочу, чтобы заголовок был ключом, поскольку он уже используется в качестве индекса в коде. Изучив документацию схемы, я задаюсь вопросом, нужен ли мне patternProperty, где шаблон соответствует любой строке, а его значение - желаемые атрибуты фильма. Или, в качестве альтернативы, может быть, самый простой подход - просто определить дополнительные свойства только с желаемыми атрибутами перемещения - что может сделать это? - person user1338952; 22.08.2013
comment
Кажется, я не понял, чего вы хотите добиться. У каждого фильма своя схема, или вы хотите использовать Json-Schema для разработки каталога фильмов и обеспечения своего рода ссылочной целостности а-ля XSD? - person jruizaranguren; 22.08.2013
comment
Каждый фильм имеет одну и ту же схему. Экземпляр json будет представлять собой набор этих фильмов, хранящихся как значения в объекте (т. е. на карте). У каждого фильма есть название, и я хочу, чтобы название было ключевым. например { Унесенные ветром : {...}, Военные игры : {...} }. Здесь {...} будут атрибутами фильма, описанными схемой, скажем, #/definitions/movie, и он может снова содержать заголовок. Конечно, заголовок может быть любой строкой. Мне не нужен уникальный для этого, так как он хранится как ключ в экземпляре json. - person user1338952; 23.08.2013
comment
И почему вам нужно иметь заголовок в качестве имени свойства? Json-Schema — это структура. На мой взгляд, не имеет особого смысла иметь постоянно растущее число имен свойств. - person jruizaranguren; 23.08.2013
comment
Ну, так данные уже структурированы. Использование схемы JSON отходит на второй план постфактум. Подумайте о хорошо структурированных данных в документе монго, где идентификатор является строкой. Или представьте себе класс C++, в котором членом класса PersonFavorites является std::map‹ String, MovieDetails › _favoriteMovies; - person user1338952; 23.08.2013
comment
Хорошо структурированный документ JSON или класс ООП на любом языке может иметь свойство id/key. «Унесённые ветром» будет ценностью этого свойства. В любом случае, Json Schema не дает того, что вы намереваетесь. Я бы порекомендовал вам попробовать другой вариант (и тогда Json Schema или XSD или Avro могут соответствовать вашим потребностям). - person jruizaranguren; 23.08.2013

Вот мой способ поддержки карты. Надеюсь помочь.


    {
      "type": "object",
      "title": "map data",
      "required": [
        "map"
      ],
      "properties": {
        "sOnePurRecord": {
          "title": "map",
          "additionalProperties": false,
          "properties": {
            "mapItem": {
              "type": "object",
              "maxProperties": 10,
              "minProperties": 1,
              "patternProperties": {
                "^[a-zA-Z0-9]{5,20}$": {
                  "$ref": "#/definitions/value"
                }
              },
              "additionalProperties": {
                "$ref": "#/definitions/value"
              }
            }
          },
          "required": [
            "mapItem"
          ]
        }
      },
      "definitions": {
        "value": {
          "type": "object",
          "properties": {
            "name": {
              "type": "string"
            },
            "id": {
              "type": "integer"
            }
          }
        }
      }
    }

person user2483084    schedule 11.10.2016