fnogatz / xsd2json

Translate XML Schema into equivalent JSON Schema
MIT License
149 stars 28 forks source link

xs:choice and xs:sequence ignored in properties #55

Open lmichel opened 7 years ago

lmichel commented 7 years ago

The following schema element

<xs:complexType name="Resource">
  <xs:annotation><xs:documentation>
     Added in Version 1.2: INFO for diagnostics in several places
  </xs:documentation></xs:annotation>
  <xs:sequence>
    <xs:element name="DESCRIPTION" type="anyTEXT" minOccurs="0"/>
    <xs:element name="INFO" type="Info" minOccurs="0" maxOccurs="unbounded"/>
    <xs:choice minOccurs="0" maxOccurs="unbounded">
      <xs:element name="COOSYS" type="CoordinateSystem"/><!-- Deprecated in V1.2 -->
      <xs:element name="GROUP" type="Group" />
      <xs:element name="PARAM" type="Param" />
    </xs:choice>
</xs:complexType>

gives this JSON schema fragment:

   "Resource": {
      "properties": {
        "name": {
          "type": "string"
        },
        "DESCRIPTION": {
          "$ref": "#/definitions/anyTEXT"
        },
        "INFO": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/Info"
          },
          "minItems": 0
        }
}

We can see that children elements COOSYS/GROUP/PARAM are ignored. Therefore they are not validated although their schema is well defined in the schema.

fnogatz commented 7 years ago

The xs:choice has not been implemented yet. I am currently thinking about an appropriate JSON Schema translation. It is not trivial :disappointed: Consider the following small XSD snippet:

<xs:sequence>
  <xs:element name="owl" type="xs:string" />
  <xs:choice>
    <xs:element name="cat" type="xs:string" />
    <xs:element name="dog" type="xs:string" />
    <xs:element name="wolf" type="xs:string" />
  </xs:choice>
</xs:sequence>

A possible direct translation would be:

{
  "type": "object",
  "properties": {
    "owl": {
      "type": "string"
    },
    "cat": {
      "type": "string"
    },
    "dog": {
      "type": "string"
    },
    "wolf": {
      "type": "string"
    }
  },
  "oneOf": [
    {
      "required": [ "cat" ]
    },
    {
      "required": [ "dog" ]
    },
    {
      "required": [ "wolf" ]
    }
  ]
}

But what if we change one of the minOccurs to 0? This is perfectly valid in XML Schema and in some cases even useful:

<xs:sequence>
  <xs:element name="owl" type="xs:string" />
  <xs:choice>
    <xs:element name="cat" type="xs:string" />
    <xs:element name="dog" type="xs:string" minOccurs="0" />
    <xs:element name="wolf" type="xs:string" />
  </xs:choice>
</xs:sequence>

If we change the JSON Schema accordingly, the following is the result:

{
  "type": "object",
  "properties": {
    "owl": {
      "type": "string"
    },
    "cat": {
      "type": "string"
    },
    "dog": {
      "type": "string"
    },
    "wolf": {
      "type": "string"
    }
  },
  "oneOf": [
    {
      "required": [ "cat" ]
    },
    {

    },
    {
      "required": [ "wolf" ]
    }
  ]
}

But this is not the same as the given XML Schema! Although the object containing only a owl property will pass the validation, the following does not:

{
  "owl": "a",
  "cat": "b",
}

The same applies for modelling the oneOf with sub-schemas of the form { "properties": { "cat": {} } } instead of { "required": [ "cat" ] }, since the empty schema matches all objects and we can not use "additionalProperties": false in the sub-schemas.

So we have to first think of an appropriate representation of these XML Schemas.

lmichel commented 7 years ago

Following my understanding of XML schema, putting minOccurs="0" within a "choice " is an (legal) over-definition since each choice item has an implicit minOccurs="0" allowing it not to be chosen. My answer for this case would be to support the "choice" element, which is a basic feature of XSD but ignoring minOccurs="0" in this context.

mozi commented 6 years ago

@fnogatz is there an update on this issue? would appreciate a basic implementation with the first suggestion above.

SensibleWood commented 6 years ago

+1 for a first pass implementation to this (have wrapped xsd2json in my own xs:choice implementation, but it'd be good to get one from source). Great work btw - this utility propelled me about 4 weeks forward on some work I'm doing

fnogatz commented 6 years ago

have wrapped xsd2json in my own xs:choice implementation

Is this anywhere available? It might be a good inspiration for native xsd2json support.

marc1n commented 3 years ago
<xs:sequence>
  <xs:element name="owl" type="xs:string" />
  <xs:choice>
    <xs:element name="cat" type="xs:string" />
    <xs:element name="dog" type="xs:string" minOccurs="0" />
    <xs:element name="wolf" type="xs:string" />
  </xs:choice>
</xs:sequence>

could be translated to:

type: object
properties:
  owl:
    type: string
required: [owl]
oneOf:
  - properties:
      cat:
        type: string
    required: [cat]
  - properties:
      dog:
        type: string
  - properties:
      wolf:
        type: string
    required: [wolf]