Arrays with indefinite length, each item can have one of many schemas in random order

65 views
Skip to first unread message

Philipp Kewisch

unread,
Oct 23, 2012, 10:08:42 AM10/23/12
to json-...@googlegroups.com
I have an array that can have any amount of elements. The schema for each element is not only of one kind, but of multiple. I couldn't find a way to do this with the -03 draft. Maybe you can help me, or consider this for a future draft. Example:

Data:
[
   [ "foo", {}, "bar"],
   [ "baz", {}, [1,2,3]],
   [ "foo", {}, "quux"],
   ...
]

Requirements:
* those arrays with first member "foo" must have a string value at the last element.
* those arrays with the first member "bar" must have an array with its own format as the last element.
* Lots of similar requirements with data not mentioned

I've tried something like this:

{ id: "#main", type: "array", items: { "$ref": "#basecomponent" } }

{ id: "#basecomponent", type: "array", items: [{ type: "string" }, { type: "object" } }, additionalItems: { type: "any" } }
{ id: "#foocomponent", "extends": { "$ref": "#basecomponent" }, items: [{ type: "string", enum: ["foo"]}, { type: "object" }, { type: "string" }], additionalItems: false }

This is not ideal, since anything that follows #basecomponent will work, and I don't even know if the extends mechanism will allow passing in such items

And this obviously won't work, since the array is reservered for tuple typing, not for any kind:

{ id: "#main", type: "array", items: [{ "$ref": "#barcomponent" }, { "$ref": "#foocomponent" }}

So, how would I allow any type from a list of types to be valid for an array with indefinite length?

Philipp


Philipp Kewisch

unread,
Oct 23, 2012, 10:47:25 AM10/23/12
to json-...@googlegroups.com
Hmm reading some other posts I found this from draft 04. Would this work?

{ id: "#main", type: "array", items: { "anyOf": [ { "$ref": "#foocomponent" }, { "$ref": "#barcomponent" } ] } }

{ id: "#barcomponent", type: "array", items: [{ type: "string", enum: ["bar"] }, { type: "object" } }, { type: "array", items: { "type": "number" } } ] }
{ id: "#foocomponent", type: "array", items: [{ type: "string", enum: ["foo"]}, { type: "object" }, { type: "string" }], additionalItems: false }

If so, I'd love to see JSV updated to the upcoming 04 draft :)


Also, if I may piggyback a question: Is there a way to define multiple unrelated objects in one file? i.e put all the above definitions into one file, without removing the use of $ref ?

Philipp

Andrei Neculau

unread,
Oct 23, 2012, 10:59:00 AM10/23/12
to json-...@googlegroups.com
not entirely sure, but here's a shot in the dark

{
 "type": "array",
 "additionalItems": { // no matter the position, each item can be of type foo or bar
  "type": [{          // where foo is an array 'foo', some_object, some_string
   "type": "array",
   "items": [{
    "type": "string",
    "enum": "foo"
   }, {
    "type": "object"
   }, {
    "type": "string"
   }],
   "additionalItems": false
  }, {                // and where bar is an array 'bar', some_object, some_array_with_numbers
   "type": "array",
   "items": [{
    "type": "string",
    "enum": "bar"
   }, {
    "type": "object"
   }, {
    "type": "array",
    "additionalItems": {
     "type": "number"
    }
   }],
   "additionalItems": false
  }]
 }
}

On Tuesday, October 23, 2012 4:08:42 PM UTC+2, Philipp Kewisch wrote:

Francis Galiegue

unread,
Oct 23, 2012, 12:16:47 PM10/23/12
to json-...@googlegroups.com
On 10/23/2012 04:08 PM, Philipp Kewisch wrote:
> I have an array that can have any amount of elements. The schema for
> each element is not only of one kind, but of multiple. I couldn't find a
> way to do this with the -03 draft. Maybe you can help me, or consider
> this for a future draft. Example:
>
> Data:
> [
> [ "foo", {}, "bar"],
> [ "baz", {}, [1,2,3]],
> [ "foo", {}, "quux"],
> ...
> ]
>
> Requirements:
> * those arrays with first member "foo" must have a string value at the
> last element.
> * those arrays with the first member "bar" must have an array with its
> own format as the last element.

[ I don't understand that one ]

> * Lots of similar requirements with data not mentioned
>

And no constraints on the middle elements?

If it were on the first and then other elements then that would be easy
enough:

{
"case1": {
"items": [ { "enum": [ "foo" ] } ],
"additionalItems": { "type": "string" }
},
"case2": {
"items": [ { "enum": [ "bar" ] } ],
"additionalItems": { "type": "array" }
},
"type": "array",
"extends": {
"type": [ { "$ref": "#/case1" }, { "$ref": "#/case2" } ]
}
}


Geraint (David)

unread,
Oct 23, 2012, 12:25:59 PM10/23/12
to json-...@googlegroups.com
Philipp: That is absolutely correct, although it would be clearer to use "oneOf" instead of "anyOf" (because the sub-schemas you define are exclusive).

This is also possible in draft version 3 - you simply replace "oneOf" with "type".

As for your second question: there is nothing to stop you from declaring other properties in your schema object, and then referencing them using JSON Pointer.  It would look a bit like this:

{
    "title": "Main schema",
    "type": "array",
    "items": {
        "oneOf": [
            {"$ref": "#/fooComponent"},
            {"$ref", "#/barComponent"}
        ]
    },
    "fooComponent": {
        "title": "Foo component",
        ...
    },
    "barComponent": {
        "title": "Bar component",
        ...

Philipp Kewisch

unread,
Oct 23, 2012, 3:44:52 PM10/23/12
to json-...@googlegroups.com
Thank you all for the input! This does take me one step further. Looks like I misread the 03 spec, it sounded like "type" could only have simple types as the value.


Geraint, from the looks of your code it seems I can use the top level object as a container for all of my schema items? I've tried this but am having trouble resolving refs. Here is a simplified version of my updated schema, this is the top level object, the URI I set for it is "urn:ietf:mystuff":

{

    "type": "array",
    "items": [
        { "type": "string", "enum": ["foo"] }
    ], 
    "additionalItems": { "$ref": "#/bar" },

    "bar": { "type": "object" }
}

The data I'd like to parse is something like this:

["foo", {}]

The error I get is:

Problem with urn:ietf:mystuff#/additionalItems:
  Unknown schema reference
Reported by http://json-schema.org/draft-03/hyper-schema#
Attribute '{full}'
  "urn:ietf:mystuff#/bar"

Not sure if this is something with my JSV setup, or if the 03 draft just doesn't support json pointers yet?

Thanks,
Philipp
--
 
 

Geraint (David)

unread,
Oct 23, 2012, 5:24:03 PM10/23/12
to json-...@googlegroups.com
Yes, you can indeed use the top-level object to hold your other schemas.

I'm not an expert on JSV, so I'm just guessing here, but if it doesn't support JSON Pointer, then you could try giving it some help by explicitly setting the URL using a fragment "id":

{
    "id": "urn:whatever:mystuff",

    "items": [
        { "type": "string", "enum": ["foo"] }
    ],  
    "additionalItems": { "$ref": "#/bar" },
    "bar": {
        "id": "#/bar",
        "type": "object"
    }
}

The goal used to be that you could use "id" to associate particular sub-schemas with particular fragments for the document.  However, JSON Pointer is clearer and more flexible, so that's what I would recommend using if you can.

Francis Galiegue

unread,
Oct 23, 2012, 5:45:03 PM10/23/12
to json-...@googlegroups.com
On Tue, Oct 23, 2012 at 9:44 PM, Philipp Kewisch <kew...@gmail.com> wrote:
[...]
> { "type": "string", "enum": ["foo"] }

If you use enum, you have no need to specify "type" here. "enum"
elements are discrete values. It is up to the validator afterwards to
ensure value equivalence, and that is defined by the specification
(even v3).

--
Francis Galiegue, fgal...@gmail.com
"It seems obvious [...] that at least some 'business intelligence'
tools invest so much intelligence on the business side that they have
nothing left for generating SQL queries" (Stéphane Faroult, in "The
Art of SQL", ISBN 0-596-00894-5)
Reply all
Reply to author
Forward
0 new messages