Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generated JSON Schemas do not correctly serialize choice #105

Open
aj-stein-nist opened this issue Feb 28, 2024 · 5 comments
Open

Generated JSON Schemas do not correctly serialize choice #105

aj-stein-nist opened this issue Feb 28, 2024 · 5 comments
Labels
bug Something isn't working scope: schema generation

Comments

@aj-stein-nist
Copy link
Contributor

aj-stein-nist commented Feb 28, 2024

Describe the bug

When using metaschema-xslt as of 7d9fbfa84e78e4ba4dd950ad39c65738b7b66697 and also tested off of current develop (at ), Metaschema modules that define a <choice/> are not correctly serializing the choice options correctly as one or N choices, but allowing any defined.

Who is the bug affecting?

Tool developers relying on generated JSON schemas from this tool.

What is affected by this bug?

JSON Schema generation with models using <choice/>.

When does this occur?

Consistently.

How do we replicate the issue?

Example model, current output, and desired outputs to follow in upcoming edits to this issue.

  1. Checkout metaschema-xslt from the develop branch at current commit.
  2. Run the following command on the sample schema below.
  3. Attempt to validate the JSON schema with oXygen XML Editor, ajv, or any other JSON Schema validator tool.
  4. Confirm the following data is valid even though it is not valid given the Metaschema module definition.
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://raw.githubusercontent.com/usnistgov/metaschema/develop/schema/xml/metaschema.xsd" type="application/xml" schematypens="http://www.w3.org/2001/XMLSchema"?>
<METASCHEMA xmlns="http://csrc.nist.gov/ns/oscal/metaschema/1.0">
    <schema-name>Model for Testing usnistgov/metaschema-xslt#105</schema-name>
    <schema-version>0.1.0</schema-version>
    <short-name>choice-bug-issue-105</short-name>
    <namespace>https://github.com/usnistgov/metaschema-xslt/issues/105</namespace>
    <json-base-uri>https://github.com/usnistgov/metaschema-xslt/issues/105</json-base-uri>
    <define-assembly name="root">
        <formal-name>Root Assembly for Choice</formal-name>
        <description>This root assembly should only an instance to have a field of a or b, but not both.</description>
        <root-name>root</root-name>
        <model>
            <choice>
                <define-field name="a" as-type="positiveInteger" min-occurs="1" max-occurs="1"/>
                <define-field name="b" as-type="positiveInteger" min-occurs="1" max-occurs="1"/>
            </choice>
        </model>
    </define-assembly>
</METASCHEMA>

JSON document instance:

{
    "root": {
        "a": 1,
        "b": 1
    }
}

Current JSON Schema:

 { "$schema" : "http://json-schema.org/draft-07/schema#",
  "$id" : "https://github.com/usnistgov/metaschema-xslt/issues/105/0.1.0/choice-bug-issue-105-schema.json",
  "$comment" : "Model for Testing usnistgov/metaschema-xslt#105: JSON Schema",
  "type" : "object",
  "definitions" : 
  { "json-schema-directive" : 
   { "title" : "Schema Directive",
    "description" : "A JSON Schema directive to bind a specific schema to its document instance.",
    "$id" : "#/definitions/json-schema-directive",
    "$ref" : "#/definitions/URIReferenceDatatype" },
   "choice-bug-issue-105-choice-bug-issue-105:root" : 
   { "title" : "Root Assembly for Choice",
    "description" : "This root assembly should only an instance to have a field of a or b, but not both.",
    "$id" : "#/definitions/choice-bug-issue-105-choice-bug-issue-105:root",
    "type" : "object",
    "properties" : 
    { "a" : 
     { "$ref" : "#/definitions/PositiveIntegerDatatype" },
     "b" : 
     { "$ref" : "#/definitions/PositiveIntegerDatatype" } },
    "additionalProperties" : false },
   "IntegerDatatype" : 
   { "description" : "A whole number value.",
    "type" : "integer" },
   "PositiveIntegerDatatype" : 
   { "description" : "An integer value that is greater than 0.",
    "allOf" : 
    [ 
     { "$ref" : "#/definitions/IntegerDatatype" },
     
     { "type" : "number",
      "minimum" : 1 } ] },
   "URIReferenceDatatype" : 
   { "description" : "A URI Reference, either a URI or a relative-reference, formatted according to section 4.1 of RFC3986.",
    "type" : "string",
    "format" : "uri-reference" } },
  "properties" : 
  { "$schema" : 
   { "$ref" : "#/definitions/json-schema-directive" },
   "root" : 
   { "$ref" : "#/definitions/choice-bug-issue-105-choice-bug-issue-105:root" } },
  "required" : 
  [ "root" ],
  "additionalProperties" : false }

Expected behavior (i.e. solution)

The generated JSON Schemas serialize <choice/> into a selection with JSON Schema's oneOf syntax, not anyOf.

The target JSON Schema should look this:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "https://github.com/usnistgov/metaschema-xslt/issues/105/0.1.0/choice-bug-issue-105-schema.json",
    "$comment": "Model for Testing usnistgov/metaschema-xslt#105: JSON Schema",
    "type": "object",
    "definitions": {
        "json-schema-directive": {
            "title": "Schema Directive",
            "description": "A JSON Schema directive to bind a specific schema to its document instance.",
            "$id": "#/definitions/json-schema-directive",
            "$ref": "#/definitions/URIReferenceDatatype"
        },
        "choice-bug-issue-105-choice-bug-issue-105:root": {
            "title": "Root Assembly for Choice",
            "description": "This root assembly should only an instance to have a field of a or b, but not both.",
            "$id": "#/definitions/choice-bug-issue-105-choice-bug-issue-105:root",
            "type": "object",
            "anyOf": [
                {
                    "properties": {
                        "a": {"$ref": "#/definitions/PositiveIntegerDatatype"}
                    },
                    "required": ["a"],
                    "additionalProperties": false
                },
                {
                    "properties": {
                        "b": {"$ref": "#/definitions/PositiveIntegerDatatype"}
                    },
                    "required": ["b"],
                    "additionalProperties": false
                }
            ]
        },
        "IntegerDatatype": {
            "description": "A whole number value.",
            "type": "integer"
        },
        "PositiveIntegerDatatype": {
            "description": "An integer value that is greater than 0.",
            "allOf": [
                {"$ref": "#/definitions/IntegerDatatype"},
                {
                    "type": "number",
                    "minimum": 1
                }
            ]
        },
        "URIReferenceDatatype": {
            "description": "A URI Reference, either a URI or a relative-reference, formatted according to section 4.1 of RFC3986.",
            "type": "string",
            "format": "uri-reference"
        }
    },
    "properties": {
        "$schema": {"$ref": "#/definitions/json-schema-directive"},
        "root": {"$ref": "#/definitions/choice-bug-issue-105-choice-bug-issue-105:root"}
    },
    "required": ["root"],
    "additionalProperties": false
}

Other Comments

N/A

@wendellpiez
Copy link
Collaborator

It is awesome to see this with such specificity.

However we aren't quite there yet to a spec - I would like to see the desired results for this:

<model>
    <define-field name="a0" as-type="positiveInteger" min-occurs="1" max-occurs="1"/>
    <choice>
        <define-field name="a" as-type="positiveInteger" min-occurs="1" max-occurs="1"/>
        <define-field name="b" as-type="positiveInteger" min-occurs="1" max-occurs="1"/>
    </choice>
    <define-field name="ax" as-type="positiveInteger" min-occurs="1" max-occurs="1"/>
</model>

? just a little closer to RL - though ph oscal-cli already does this correctly? comments, @aj-stein-nist ?

@wendellpiez
Copy link
Collaborator

Follow up question for @JustKuzya: is the "should look like" model sketch above showing the JSON schema produced by oscal-cli, by some other tool, or a correct design by 'dead reckoning'?

Any answer is fine, and aligning with oscal-cli is especially fine.

@wendellpiez
Copy link
Collaborator

@JustKuzya won't choice translate into a JSON Schema oneOf?

But I am getting ahead of us. It is not really worth discussing until we have working and breaking examples of actual JSON.

@wendellpiez
Copy link
Collaborator

Behind #108 there is WIP towards supporting choice.

It also exposes the difficulty here*, namely a combinatorial explosion of subschemas to be listed under oneOf, when choices proliferate. For each choice offered in any model, we get as many subschemas as there are choices, and sibling choices are compounded, i.e. we get the cross-product. So if a model has a choice of three followed by a choice of four, we need twelve (3x4) subschemas for it.

More research is called for. I would love extra eyes on this and suggestions are welcome: please comment or ping me.

* I was pretty sure there was a reason we did not implement this sooner.

@wendellpiez
Copy link
Collaborator

As noted, significant work towards implementing (exclusive) 'choice' in metaschema-xslt JSON Schema production is now behind PR #108. This includes analysis and a solution for the 'expand model' step that rewrites options implied by choice, as well as new and useful testing infrastructure. Work still needed:

  • finalize and test target syntax
  • stage unit test
  • implement and test

wendellpiez added a commit to wendellpiez/metaschema-xslt that referenced this issue Jun 4, 2024
…, still wanting testing; with a small testing application
wendellpiez added a commit to wendellpiez/metaschema-xslt that referenced this issue Jun 5, 2024
…, still wanting testing; with a small testing application
wendellpiez added a commit that referenced this issue Jun 7, 2024
Refactoring submodules; XProc-based testing; XSpec testing of JSON Schema generation; improvements to JSON Schema generation - addressing #105 also #2007.
wendellpiez added a commit that referenced this issue Jun 11, 2024
Includes updates to unit testing, Inspector XSLT, JSON Schema (#105) and others

Co-authored-by: A.J. Stein <alexander.stein@nist.gov>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working scope: schema generation
Projects
None yet
Development

No branches or pull requests

2 participants