From 23e9712597661285603978c4d185ee641f6dc956 Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Tue, 13 May 2025 10:00:02 -0700 Subject: [PATCH 01/16] Root XML element name comes from component name Clarifies that the name of the root XML element comes from the component name, which was shown in an example but was unclear due to the use of the obsolete OAS 2.0 terminology "model." This does not change the restriction (in the `xml` field of the Schema Object) that the `xml` field only applies to property schemas (and not root schemas). --- src/oas.md | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/oas.md b/src/oas.md index 67b36f814c..76d169ad6c 100644 --- a/src/oas.md +++ b/src/oas.md @@ -3253,22 +3253,25 @@ animals: ###### XML Attribute, Prefix and Namespace -In this example, a full model definition is shown. +In this example, a full [schema component](#components-schemas) definition is shown. +Note that the name of the root XML element comes from the component name. ```yaml -Person: - type: object - properties: - id: - type: integer - format: int32 - xml: - attribute: true - name: - type: string - xml: - namespace: https://example.com/schema/sample - prefix: sample +components: + schemas: + Person: + type: object + properties: + id: + type: integer + format: int32 + xml: + attribute: true + name: + type: string + xml: + namespace: https://example.com/schema/sample + prefix: sample ``` ```xml From 00fe2ed175b90aa6847a1bc2af98e0713eafc81f Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Thu, 15 May 2025 10:05:50 -0700 Subject: [PATCH 02/16] Align wording with components rather than "root" This avoids reinforcing the "root schema" vs "property schema" restriction that we plan to relax. --- src/oas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/oas.md b/src/oas.md index 76d169ad6c..b3694d26c0 100644 --- a/src/oas.md +++ b/src/oas.md @@ -3192,7 +3192,7 @@ See examples for expected behavior. | Field Name | Type | Description | | ---- | :----: | ---- | -| name | `string` | Replaces the name of the element/attribute used for the described schema property. When defined within `items`, it will affect the name of the individual XML elements within the list. When defined alongside `type` being `"array"` (outside the `items`), it will affect the wrapping element if and only if `wrapped` is `true`. If `wrapped` is `false`, it will be ignored. | +| name | `string` | Replaces the inferred name of the element/attribute used for the described schema property. For the root schema object of a [schema component](#components-schemas), the inferred name is the name of the component; for other schemas the name is inferred from the parent property name. When defined within `items`, it will affect the name of the individual XML elements within the list. When defined alongside `type` being `"array"` (outside the `items`), it will affect the wrapping element if and only if `wrapped` is `true`. If `wrapped` is `false`, it will be ignored. | | namespace | `string` | The IRI ([[RFC3987]]) of the namespace definition. Value MUST be in the form of a non-relative IRI. | | prefix | `string` | The prefix to be used for the [name](#xml-name). | | attribute | `boolean` | Declares whether the property definition translates to an attribute instead of an element. Default value is `false`. | From 6850e16e5d5e6f666cd1781f5ec884abe9eb66a5 Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Wed, 14 May 2025 11:10:40 -0700 Subject: [PATCH 03/16] Support all common XML node types This change adds a nodeType field to support the four most commonly used XML node types: element, attribute, text, and cdata. A fifth nodetype, none, is used to prevent a Schema Object from producing a node. This also removes the restriction on where the xml field and XML Object can appear, as the nodeType system is more flexible than the old system. This deprecates two existing fields: * attribute, replaced by nodeType: attribute * wrapped, replaced by nodeType: none --- src/oas.md | 280 +++++++++++++++++++++++-------- src/schemas/validation/meta.yaml | 17 +- 2 files changed, 227 insertions(+), 70 deletions(-) diff --git a/src/oas.md b/src/oas.md index b3694d26c0..c05c2e886e 100644 --- a/src/oas.md +++ b/src/oas.md @@ -2582,7 +2582,7 @@ JSON Schema implementations MAY choose to treat keywords defined by the OpenAPI | Field Name | Type | Description | | ---- | :----: | ---- | | discriminator | [Discriminator Object](#discriminator-object) | The discriminator provides a "hint" for which of a set of schemas a payload is expected to satisfy. See [Composition and Inheritance](#composition-and-inheritance-polymorphism) for more details. | -| xml | [XML Object](#xml-object) | This MAY be used only on property schemas. It has no effect on root schemas. Adds additional metadata to describe the XML representation of this property. | +| xml | [XML Object](#xml-object) | Adds additional metadata to describe the XML representation of this schema. | | externalDocs | [External Documentation Object](#external-documentation-object) | Additional external documentation for this schema. | | example | Any | A free-form field to include an example of an instance for this schema. To represent examples that cannot be naturally represented in JSON or YAML, a string value can be used to contain the example with escaping where necessary.

**Deprecated:** The `example` field has been deprecated in favor of the JSON Schema `examples` keyword. Use of `example` is discouraged, and later versions of this specification may remove it. | @@ -3184,22 +3184,68 @@ will map to `#/components/schemas/Dog` because the `dog` entry in the `mapping` #### XML Object A metadata object that allows for more fine-tuned XML model definitions. - -When using arrays, XML element names are _not_ inferred (for singular/plural forms) and the `name` field SHOULD be used to add that information. -See examples for expected behavior. +When using a Schema Object with XML, if no XML Object is present, the behavior is determined by the XML Object's default field values. ##### Fixed Fields | Field Name | Type | Description | | ---- | :----: | ---- | -| name | `string` | Replaces the inferred name of the element/attribute used for the described schema property. For the root schema object of a [schema component](#components-schemas), the inferred name is the name of the component; for other schemas the name is inferred from the parent property name. When defined within `items`, it will affect the name of the individual XML elements within the list. When defined alongside `type` being `"array"` (outside the `items`), it will affect the wrapping element if and only if `wrapped` is `true`. If `wrapped` is `false`, it will be ignored. | +| nodeType | `string` | One of `element`, `attribute`, `text`, `cdata`, or `none`, as explained under [XML Node Types](#xml-node-types). The default value is `none` if `$ref`, `$dynamicRef`, or `type: array` is present in the [Schema Object](#schema-object) containing the XML Object, and `element` otherwise. | +| name | `string` | Sets the name of the element/attribute used for the described schema property, replacing name that was inferred as described under [XML Node Names](#xml-node-names). This field SHALL be ignored if the `nodeType` is `text`, `cdata`, or `none`. | | namespace | `string` | The IRI ([[RFC3987]]) of the namespace definition. Value MUST be in the form of a non-relative IRI. | | prefix | `string` | The prefix to be used for the [name](#xml-name). | -| attribute | `boolean` | Declares whether the property definition translates to an attribute instead of an element. Default value is `false`. | -| wrapped | `boolean` | MAY be used only for an array definition. Signifies whether the array is wrapped (for example, ``) or unwrapped (``). Default value is `false`. The definition takes effect only when defined alongside `type` being `"array"` (outside the `items`). | +| attribute | `boolean` | Declares whether the property definition translates to an attribute instead of an element. Default value is `false`. If `nodeType` is present, this field MUST NOT be present.

**Deprecated:** Use `nodeType: attribute` in place of `attribute: true` | +| wrapped | `boolean` | MAY be used only for an array definition. Signifies whether the array is wrapped (for example, ``) or unwrapped (``). Default value is `false`. The definition takes effect only when defined alongside `type` being `"array"` (outside the `items`). If `nodeType` is present, this field MUST NOT be present.

**Deprecated:** Set `nodeType: element` explicitly in place of `wrapped: true` | + +Note that when generating an XML document from object data, the order of the nodes is undefined. +Use `prefixItems` to control node ordering. + +See [Appendix B](#appendix-b-data-type-conversion) for a discussion of converting values of various types to string representations. This object MAY be extended with [Specification Extensions](#specification-extensions). +##### XML Node Types + +Each Schema Object describes a particular type of XML [node](https://dom.spec.whatwg.org/#interface-node) which is specified by the `nodeType` field, which has the following possible values. +Except for the special value `none`, these values have numeric equivalents in the DOM [specification](https://dom.spec.whatwg.org/#interface-node) which are given in parentheses after the name: + +* `element` (1): The schema represents an element and describes its contents +* `attribute` (2): The schema represents an attribute and describes its value +* `text` (3): The schema represents a text node (parsed character data) +* `cdata` (4): The schema represents a CDATA section +* `none`: The schema does not correspond to any node in the XML document, and its contents are included directly under the parent schema's node + +The `none` type is useful for JSON Schema constructs that require more Schema Objects than XML nodes, such as a schema containing only `$ref` that exists to facilitate re-use rather than imply any structure. + +###### Modeling Element Lists + +For historical compatibility, schemas of `type: array` default to `nodeType: none`, placing the nodes for each array item directly under the parent node. +This also aligns with the inferred naming behavior defined under [XML Node Names](#xml-node-names). + +To produce an element wrapping the list, set an explicit `nodeType: element` on the `type: array` schema. +When doing so, it is advisable to set an explicit name on either the wrapping element or the item elements to avoid them having the same inferred name. +See examples for expected behavior. + +###### Implicit and Explicit `text` Nodes + +If an `element` node has a primitive type, then the schema also produces an implicit `text` node described by the schema for the contents of the `element` node named by the property name (or `name` field). + +Explicit `text` nodes are necessary if an element has both attributes and content. + +Note that placing two `text` nodes adjacent to each other is ambiguous for parsing, and the resulting behavior is implementation-defined. + +##### XML Node Names + +The `element` and `attribute` node types require a name, which MUST be inferred from the schema as follows, unless overridden by the `name` field: + +* For schemas directly under the [Components Object's](#components-object) `schemas` field, the component name is the inferred name. +* For property schemas, and for array item schemas under a property schema, the property name is the inferred name +* In all other cases, such as an inline schema under a [Media Type Object's](#media-type-object) `schema` field, no name can be inferred and an XML Object with a `name` field MUST be present + +Note that when using arrays, singular vs plural forms are _not_ inferred, and must be set explicitly. + +##### Namespace Limitations + The `namespace` field is intended to match the syntax of [XML namespaces](https://www.w3.org/TR/xml-names11/), although there are a few caveats: * Versions 3.1.0, 3.0.3, and earlier of this specification erroneously used the term "absolute URI" instead of "non-relative URI" ("non-relative IRI" as of OAS v3.2.0), so authors using namespaces that include a fragment should check tooling support carefully. @@ -3207,29 +3253,31 @@ The `namespace` field is intended to match the syntax of [XML namespaces](https: ##### XML Object Examples -Each of the following examples represent the value of the `properties` keyword in a [Schema Object](#schema-object) that is omitted for brevity. -The JSON and YAML representations of the `properties` value are followed by an example XML representation produced for the single property shown. +The Schema Objects are followed by an example XML representation produced for the schema shown. +For examples using `attribute` or `wrapped`, please see version 3.1 of the OpenAPI Specification. -###### No XML Element +###### No XML Object -Basic string property: +Basic string property (`nodeType` is `element` by default): ```yaml -animals: - type: string +properties: + animals: + type: string ``` ```xml ... ``` -Basic string array property ([`wrapped`](#xml-wrapped) is `false` by default): +Basic string array property (`nodeType` is `none` by default): ```yaml -animals: - type: array - items: - type: string +properties: + animals: + type: array + items: + type: string ``` ```xml @@ -3241,10 +3289,11 @@ animals: ###### XML Name Replacement ```yaml -animals: - type: string - xml: - name: animal +properties: + animals: + type: string + xml: + name: animal ``` ```xml @@ -3253,7 +3302,6 @@ animals: ###### XML Attribute, Prefix and Namespace -In this example, a full [schema component](#components-schemas) definition is shown. Note that the name of the root XML element comes from the component name. ```yaml @@ -3285,12 +3333,13 @@ components: Changing the element names: ```yaml -animals: - type: array - items: - type: string - xml: - name: animal +properties: + animals: + type: array + items: + type: string + xml: + name: animal ``` ```xml @@ -3298,17 +3347,18 @@ animals: value ``` -The external `name` field has no effect on the XML: +The `name` field for the `type: array` schema has no effect because the default `nodeType` for that object is `none`: ```yaml -animals: - type: array - items: - type: string +properties: + animals: + type: array + items: + type: string + xml: + name: animal xml: - name: animal - xml: - name: aliens + name: aliens ``` ```xml @@ -3316,15 +3366,16 @@ animals: value ``` -Even when the array is wrapped, if a name is not explicitly defined, the same name will be used both internally and externally: +Even when a wrapping element is explicitly created by setting `nodeType` to `element`, if a name is not explicitly defined, the same name will be used for both the wrapping element and the list item elements: ```yaml -animals: - type: array - items: - type: string - xml: - wrapped: true +properties: + animals: + type: array + items: + type: string + xml: + nodeType: element ``` ```xml @@ -3337,14 +3388,15 @@ animals: To overcome the naming problem in the example above, the following definition can be used: ```yaml -animals: - type: array - items: - type: string +properties: + animals: + type: array + items: + type: string + xml: + name: animal xml: - name: animal - xml: - wrapped: true + nodeType: element ``` ```xml @@ -3354,18 +3406,19 @@ animals: ``` -Affecting both internal and external names: +Affecting both wrapping element and item element names: ```yaml -animals: - type: array - items: - type: string +properties: + animals: + type: array + items: + type: string + xml: + name: animal xml: - name: animal - xml: - name: aliens - wrapped: true + name: aliens + nodeType: element ``` ```xml @@ -3375,16 +3428,17 @@ animals: ``` -If we change the external element but not the internal ones: +If we change the wrapping element name but not the item element names: ```yaml -animals: - type: array - items: - type: string - xml: - name: aliens - wrapped: true +properties: + animals: + type: array + items: + type: string + xml: + name: aliens + nodeType: element ``` ```xml @@ -3394,6 +3448,96 @@ animals: ``` +###### Elements With Attributes And Text + +```yaml +properties: + animals: + type: array + xml: + nodeType: element + name: animals + items: + properties: + kind: + type: string + xml: + nodeType: attribute + name: animal + content: + type: string + xml: + nodeType: text +``` + +```xml + + Fluffy + Fido + +``` + +###### Referenced Element With CDATA + +In this example, no element is created for the Schema Object that contains only the `$ref`, as its `nodeType` defaults to `none`. +It is necessary to create a subschema for the CDATA section as otherwise the content would be treated as an implicit node of type `text`. + +```yaml +paths: + /docs: + get: + responses: + "200": + content: + application/xml: + $ref: "#/components/schemas/Documentation" +components: + schemas: + Documentation: + type: object + properties: + content: + type: string + contentMediaType: text/html + xml: + nodeType: cdata +``` + +```xml + + Awesome Docs]]> + +``` + +###### Element With Text Before and After a Child Element + +In this example, `prefixItems` is used to control the ordering. +Since `prefixItems` works with arrays, we need to explicitly set the `nodeType` to `element`. +Within `prefixItems`, we need to explicitly set the `nodeType` of the `text` nodes, but do not need a name, while the data node's default `nodeType` of `element` is correct, but it needs an explicit `name`: + +```yaml +components: + schemas: + Report: + type: array + xml: + nodeType: element + prefixItems: + - type: string + xml: + nodeType: text + - type: number + xml: + name: data + - type: string + xml: + nodeType: text +``` + +```xml +Some preamble text.42Some postamble text. +``` + #### Security Scheme Object Defines a security scheme that can be used by the operations. diff --git a/src/schemas/validation/meta.yaml b/src/schemas/validation/meta.yaml index 491190a221..52f5ea2ed0 100644 --- a/src/schemas/validation/meta.yaml +++ b/src/schemas/validation/meta.yaml @@ -55,8 +55,14 @@ $defs: xml: $ref: '#/$defs/extensible' properties: - attribute: - type: boolean + nodeType: + type: string + enum: + - element + - attribute + - text + - cdata + - none name: type: string namespace: @@ -64,7 +70,14 @@ $defs: type: string prefix: type: string + attribute: + type: boolean wrapped: type: boolean type: object + dependentSchemas: + nodeType: + properties: + attribute: false + wrapped: false unevaluatedProperties: false From 63ba3e3f9fc0e10c594c2d5465d4ad01fc52e22e Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Thu, 15 May 2025 19:39:07 -0700 Subject: [PATCH 04/16] Better wording and formatting --- src/oas.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/oas.md b/src/oas.md index c05c2e886e..d24738d56f 100644 --- a/src/oas.md +++ b/src/oas.md @@ -3191,11 +3191,11 @@ When using a Schema Object with XML, if no XML Object is present, the behavior i | Field Name | Type | Description | | ---- | :----: | ---- | | nodeType | `string` | One of `element`, `attribute`, `text`, `cdata`, or `none`, as explained under [XML Node Types](#xml-node-types). The default value is `none` if `$ref`, `$dynamicRef`, or `type: array` is present in the [Schema Object](#schema-object) containing the XML Object, and `element` otherwise. | -| name | `string` | Sets the name of the element/attribute used for the described schema property, replacing name that was inferred as described under [XML Node Names](#xml-node-names). This field SHALL be ignored if the `nodeType` is `text`, `cdata`, or `none`. | +| name | `string` | Sets the name of the element/attribute corresponding to the schema, replacing name that was inferred as described under [XML Node Names](#xml-node-names). This field SHALL be ignored if the `nodeType` is `text`, `cdata`, or `none`. | | namespace | `string` | The IRI ([[RFC3987]]) of the namespace definition. Value MUST be in the form of a non-relative IRI. | | prefix | `string` | The prefix to be used for the [name](#xml-name). | -| attribute | `boolean` | Declares whether the property definition translates to an attribute instead of an element. Default value is `false`. If `nodeType` is present, this field MUST NOT be present.

**Deprecated:** Use `nodeType: attribute` in place of `attribute: true` | -| wrapped | `boolean` | MAY be used only for an array definition. Signifies whether the array is wrapped (for example, ``) or unwrapped (``). Default value is `false`. The definition takes effect only when defined alongside `type` being `"array"` (outside the `items`). If `nodeType` is present, this field MUST NOT be present.

**Deprecated:** Set `nodeType: element` explicitly in place of `wrapped: true` | +| attribute | `boolean` | Declares whether the property definition translates to an attribute instead of an element. Default value is `false`. If `nodeType` is present, this field MUST NOT be present.

**Deprecated:** Use `nodeType: "attribute"` in place of `attribute: true` | +| wrapped | `boolean` | MAY be used only for an array definition. Signifies whether the array is wrapped (for example, ``) or unwrapped (``). Default value is `false`. The definition takes effect only when defined alongside `type` being `"array"` (outside the `items`). If `nodeType` is present, this field MUST NOT be present.

**Deprecated:** Set `nodeType: "element"` explicitly in place of `wrapped: true` | Note that when generating an XML document from object data, the order of the nodes is undefined. Use `prefixItems` to control node ordering. @@ -3219,10 +3219,10 @@ The `none` type is useful for JSON Schema constructs that require more Schema Ob ###### Modeling Element Lists -For historical compatibility, schemas of `type: array` default to `nodeType: none`, placing the nodes for each array item directly under the parent node. +For historical compatibility, schemas of `type: array` default to `nodeType: "none"`, placing the nodes for each array item directly under the parent node. This also aligns with the inferred naming behavior defined under [XML Node Names](#xml-node-names). -To produce an element wrapping the list, set an explicit `nodeType: element` on the `type: array` schema. +To produce an element wrapping the list, set an explicit `nodeType: "element"` on the `type: array` schema. When doing so, it is advisable to set an explicit name on either the wrapping element or the item elements to avoid them having the same inferred name. See examples for expected behavior. From e2e2d7b457b413c381f400c17fcf3f73ac9cda65 Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Thu, 15 May 2025 19:42:28 -0700 Subject: [PATCH 05/16] A bit more formatting improvements --- src/oas.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/oas.md b/src/oas.md index d24738d56f..87b1e72cf7 100644 --- a/src/oas.md +++ b/src/oas.md @@ -3190,7 +3190,7 @@ When using a Schema Object with XML, if no XML Object is present, the behavior i | Field Name | Type | Description | | ---- | :----: | ---- | -| nodeType | `string` | One of `element`, `attribute`, `text`, `cdata`, or `none`, as explained under [XML Node Types](#xml-node-types). The default value is `none` if `$ref`, `$dynamicRef`, or `type: array` is present in the [Schema Object](#schema-object) containing the XML Object, and `element` otherwise. | +| nodeType | `string` | One of `element`, `attribute`, `text`, `cdata`, or `none`, as explained under [XML Node Types](#xml-node-types). The default value is `none` if `$ref`, `$dynamicRef`, or `type: "array"` is present in the [Schema Object](#schema-object) containing the XML Object, and `element` otherwise. | | name | `string` | Sets the name of the element/attribute corresponding to the schema, replacing name that was inferred as described under [XML Node Names](#xml-node-names). This field SHALL be ignored if the `nodeType` is `text`, `cdata`, or `none`. | | namespace | `string` | The IRI ([[RFC3987]]) of the namespace definition. Value MUST be in the form of a non-relative IRI. | | prefix | `string` | The prefix to be used for the [name](#xml-name). | @@ -3219,10 +3219,10 @@ The `none` type is useful for JSON Schema constructs that require more Schema Ob ###### Modeling Element Lists -For historical compatibility, schemas of `type: array` default to `nodeType: "none"`, placing the nodes for each array item directly under the parent node. +For historical compatibility, schemas of `type: "array"` default to `nodeType: "none"`, placing the nodes for each array item directly under the parent node. This also aligns with the inferred naming behavior defined under [XML Node Names](#xml-node-names). -To produce an element wrapping the list, set an explicit `nodeType: "element"` on the `type: array` schema. +To produce an element wrapping the list, set an explicit `nodeType: "element"` on the `type: "array"` schema. When doing so, it is advisable to set an explicit name on either the wrapping element or the item elements to avoid them having the same inferred name. See examples for expected behavior. @@ -3347,7 +3347,7 @@ properties: value ``` -The `name` field for the `type: array` schema has no effect because the default `nodeType` for that object is `none`: +The `name` field for the `type: "array"` schema has no effect because the default `nodeType` for that object is `none`: ```yaml properties: From d775e9bc64db33fcbba5fdd8a6996ae0d81c5f9f Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Fri, 16 May 2025 11:34:38 -0700 Subject: [PATCH 06/16] Fix missing word Co-authored-by: Ralf Handl --- src/oas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/oas.md b/src/oas.md index 87b1e72cf7..f42d3c3ff6 100644 --- a/src/oas.md +++ b/src/oas.md @@ -3191,7 +3191,7 @@ When using a Schema Object with XML, if no XML Object is present, the behavior i | Field Name | Type | Description | | ---- | :----: | ---- | | nodeType | `string` | One of `element`, `attribute`, `text`, `cdata`, or `none`, as explained under [XML Node Types](#xml-node-types). The default value is `none` if `$ref`, `$dynamicRef`, or `type: "array"` is present in the [Schema Object](#schema-object) containing the XML Object, and `element` otherwise. | -| name | `string` | Sets the name of the element/attribute corresponding to the schema, replacing name that was inferred as described under [XML Node Names](#xml-node-names). This field SHALL be ignored if the `nodeType` is `text`, `cdata`, or `none`. | +| name | `string` | Sets the name of the element/attribute corresponding to the schema, replacing the name that was inferred as described under [XML Node Names](#xml-node-names). This field SHALL be ignored if the `nodeType` is `text`, `cdata`, or `none`. | | namespace | `string` | The IRI ([[RFC3987]]) of the namespace definition. Value MUST be in the form of a non-relative IRI. | | prefix | `string` | The prefix to be used for the [name](#xml-name). | | attribute | `boolean` | Declares whether the property definition translates to an attribute instead of an element. Default value is `false`. If `nodeType` is present, this field MUST NOT be present.

**Deprecated:** Use `nodeType: "attribute"` in place of `attribute: true` | From 957738916cea616b4d803e99e8720766059072e8 Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Fri, 16 May 2025 11:55:19 -0700 Subject: [PATCH 07/16] Make the DOM reference normative --- src/oas.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/oas.md b/src/oas.md index f42d3c3ff6..23044ec45d 100644 --- a/src/oas.md +++ b/src/oas.md @@ -3206,8 +3206,8 @@ This object MAY be extended with [Specification Extensions](#specification-exten ##### XML Node Types -Each Schema Object describes a particular type of XML [node](https://dom.spec.whatwg.org/#interface-node) which is specified by the `nodeType` field, which has the following possible values. -Except for the special value `none`, these values have numeric equivalents in the DOM [specification](https://dom.spec.whatwg.org/#interface-node) which are given in parentheses after the name: +Each Schema Object describes a particular type of XML [[!DOM]] [node](https://dom.spec.whatwg.org/#interface-node) which is specified by the `nodeType` field, which has the following possible values. +Except for the special value `none`, these values have numeric equivalents in the DOM specification which are given in parentheses after the name: * `element` (1): The schema represents an element and describes its contents * `attribute` (2): The schema represents an attribute and describes its value From 564b2ce20b4a53373fa0cda5acf6785aa09acceb Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Fri, 16 May 2025 11:56:22 -0700 Subject: [PATCH 08/16] Improved wording around nodeType: none --- src/oas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/oas.md b/src/oas.md index 23044ec45d..ab596434ac 100644 --- a/src/oas.md +++ b/src/oas.md @@ -3213,7 +3213,7 @@ Except for the special value `none`, these values have numeric equivalents in th * `attribute` (2): The schema represents an attribute and describes its value * `text` (3): The schema represents a text node (parsed character data) * `cdata` (4): The schema represents a CDATA section -* `none`: The schema does not correspond to any node in the XML document, and its contents are included directly under the parent schema's node +* `none`: The schema does not correspond to any node in the XML document, and the nodes corresponding to its subschema(s) are included directly under its parent schema's node The `none` type is useful for JSON Schema constructs that require more Schema Objects than XML nodes, such as a schema containing only `$ref` that exists to facilitate re-use rather than imply any structure. From 970953708e6758ebbfdcec459047550e74fad010 Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Mon, 19 May 2025 09:32:55 -0700 Subject: [PATCH 09/16] Expand examples, link from field description. --- src/oas.md | 157 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 145 insertions(+), 12 deletions(-) diff --git a/src/oas.md b/src/oas.md index ab596434ac..ac48a395a3 100644 --- a/src/oas.md +++ b/src/oas.md @@ -3198,7 +3198,7 @@ When using a Schema Object with XML, if no XML Object is present, the behavior i | wrapped | `boolean` | MAY be used only for an array definition. Signifies whether the array is wrapped (for example, ``) or unwrapped (``). Default value is `false`. The definition takes effect only when defined alongside `type` being `"array"` (outside the `items`). If `nodeType` is present, this field MUST NOT be present.

**Deprecated:** Set `nodeType: "element"` explicitly in place of `wrapped: true` | Note that when generating an XML document from object data, the order of the nodes is undefined. -Use `prefixItems` to control node ordering. +Use `prefixItems` to control node ordering as shown under [Ordered Elements and Text](#ordered-elements-and-text). See [Appendix B](#appendix-b-data-type-conversion) for a discussion of converting values of various types to string representations. @@ -3509,35 +3509,168 @@ components: ``` -###### Element With Text Before and After a Child Element +Alternatively, the named root element could be set at the point of use and the root element disabled on the component: -In this example, `prefixItems` is used to control the ordering. -Since `prefixItems` works with arrays, we need to explicitly set the `nodeType` to `element`. -Within `prefixItems`, we need to explicitly set the `nodeType` of the `text` nodes, but do not need a name, while the data node's default `nodeType` of `element` is correct, but it needs an explicit `name`: +```yaml +paths: + /docs: + get: + responses: + "200": + content: + application/xml: + xml: + nodeType: element + name: StoredDocument + $ref: "#/components/schemas/Documentation" + put: + requestBody: + required: true + content: + application/xml: + xml: + nodeType: element + name: UpdatedDocument + $ref: "#/components/schemas/Documentation" + responses: + "201": {} +components: + schemas: + Documentation: + xml: + nodeType: none + type: object + properties: + content: + type: string + contentMediaType: text/html + xml: + nodeType: cdata +``` + +The GET response XML: + +```xml + + Awesome Docs]]> + +``` + +The PUT request XML: + +```xml + + Awesome Docs]]> + +``` + +The in-memory instance data for all three of the above XML documents: + +```json +{ + "content": "Awesome Docs" +} +``` + +###### Ordered Elements and Text + +To control the exact order of elements, use the `prefixItems` keyword. +With this approach, it is necessary to set the element names using the XML Object as they would otherwise all inherit the parent's name despite being different elements in a specific order. +It is also necessary to set `nodeType: "element"` explicitly on the array in order to get an element containing the sequence. + +This first ordered example shows a sequence of elements, as well as the recommended serialization of `null` for elements: ```yaml components: schemas: - Report: + OneTwoThree: + xml: + nodeType: element type: array + minLength: 3 + maxLength: 3 + prefixItems: + - xml: + name: One + type: string + - xml: + name: Two + type: object + required: + - unit + - value + properties: + unit: + type: string + xml: + nodeType: attribute + value: + type: number + xml: + nodeType: text + - xml: + name: Three + type: + - boolean + - "null" +``` + +```xml + + Some text + 42 + + +``` + +The in-memory instance data that would produce the above XML snippet with the preceding schema would be: + +```json +[ + "Some Text", + { + "unit": "cubits", + "value": 42 + }, + null +] +``` + +In this next example, the `name` needs to be set for the element, while the `nodeType` needs to be set for the text nodes. + +```yaml +components: + schemas: + Report: xml: nodeType: element + type: array prefixItems: - - type: string - xml: + - xml: nodeType: text - - type: number - xml: + type: string + - xml: name: data - - type: string - xml: + type: number + - xml: nodeType: text + type: string ``` ```xml Some preamble text.42Some postamble text. ``` +The in-memory instance data structure for the above example would be: + +```json +[ + "Some preamble text." + 42, + "Some postamble text." +] +``` + #### Security Scheme Object Defines a security scheme that can be used by the operations. From 792efcca08c048ffd8647b65ae02bf857c9baf35 Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Sat, 17 May 2025 20:46:36 -0700 Subject: [PATCH 10/16] Provide guidance on null in XML. There really isn't a native `null` type in XML, as both elements and attributes that are empty have an empty string value. We also need to leave the behavior implementation-defined for compatibility. However, the `xsi:nil` attribute is the closest thing to a `null` element. Attributes are harder, and the best I can come up with is letting `null` behave the same as an omitted attribute for the purpose of serialization. --- src/oas.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/oas.md b/src/oas.md index ac48a395a3..93789d1833 100644 --- a/src/oas.md +++ b/src/oas.md @@ -3251,6 +3251,21 @@ The `namespace` field is intended to match the syntax of [XML namespaces](https: * Versions 3.1.0, 3.0.3, and earlier of this specification erroneously used the term "absolute URI" instead of "non-relative URI" ("non-relative IRI" as of OAS v3.2.0), so authors using namespaces that include a fragment should check tooling support carefully. * XML allows but discourages relative IRI-references, while this specification outright forbids them. +##### Handling `null` Values + +XML does not, by default, have a concept equivalent to `null`, and to preserve compatibility with version 3.1.1 and earlier of this specification, the behavior of serializing `null` values is implementation-defined. + +However, implementations SHOULD handle `null` values as follows: + +* For elements, produce an empty element with an `xsi:nil="true"` attribute. +* For attributes, omit the attribute. + +Note that for attributes, this makes either a `null` value or a missing property serialize to an omitted attribute. +As the Schema Object validates the in-memory representation, this allows handling the combination of `null` and a required property. +However, because there is no distinct way to represent `null` as an attribute, it is RECOMMENDED to make attribute properties optional rather than use `null`. + +To ensure correct round-trip behavior, when parsing an element that omits an attribute, implementations SHOULD set the corresponding property to `null` if the schema allows for that value (e.g. `type: ["number", "null"]`), and omit the property otherwise (e.g.`type: "number"`). + ##### XML Object Examples The Schema Objects are followed by an example XML representation produced for the schema shown. @@ -3671,6 +3686,56 @@ The in-memory instance data structure for the above example would be: ] ``` +###### XML With `null` Values + +Recall that the schema validates the in-memory data, not the XML document itself. +The properties of the `"metadata"` element are omitted for brevity as it is here to show how the `null` value is represented. + +```yaml +product: + type: object + required: + - count + - description + - related + properties: + count: + type: + - number + - "null" + xml: + nodeType: attribute + rating: + type: string + xml: + nodeType: attribute + description: + type: string + related: + type: + - object + - "null" +``` + +```xml + + Thing + + +``` + +The above XML example corresponds to the following in-memory instance: + +```json +{ + "product": { + "count": null, + "description": "Thing", + "related": null + } +} +``` + #### Security Scheme Object Defines a security scheme that can be used by the operations. From e330609d7f35f5cfcaf308da5c99df517e88d6a5 Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Wed, 28 May 2025 10:47:47 -0700 Subject: [PATCH 11/16] Add `null` guidance for CDATA and text The guidance is the same as for serializing `null` and other non-text data types to text in other text-based media types such as the form media types. --- src/oas.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/oas.md b/src/oas.md index 93789d1833..23fa0796db 100644 --- a/src/oas.md +++ b/src/oas.md @@ -3259,6 +3259,7 @@ However, implementations SHOULD handle `null` values as follows: * For elements, produce an empty element with an `xsi:nil="true"` attribute. * For attributes, omit the attribute. +* For text and CDATA sections, see [Appendix B](#appendix-b-data-type-conversion) for a discussion of serializing non-text values to text Note that for attributes, this makes either a `null` value or a missing property serialize to an omitted attribute. As the Schema Object validates the in-memory representation, this allows handling the combination of `null` and a required property. From 92b3f4b0b791c1bcf5bad6cd1e38de8c1fb95ea2 Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Wed, 28 May 2025 10:55:22 -0700 Subject: [PATCH 12/16] Fix example to name the item nodes correctly Co-authored-by: Ralf Handl --- src/oas.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/oas.md b/src/oas.md index 23fa0796db..49ed498cf4 100644 --- a/src/oas.md +++ b/src/oas.md @@ -3474,12 +3474,13 @@ properties: nodeType: element name: animals items: + xml: + name: animal properties: kind: type: string xml: nodeType: attribute - name: animal content: type: string xml: From a4f6bd9962631b16406ff33ed06a63514ff9a5bc Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Thu, 12 Jun 2025 09:57:23 -0700 Subject: [PATCH 13/16] Apply suggestions from code review --- src/oas.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/oas.md b/src/oas.md index 49ed498cf4..002bce37f2 100644 --- a/src/oas.md +++ b/src/oas.md @@ -3330,7 +3330,7 @@ components: type: integer format: int32 xml: - attribute: true + nodeType: attribute name: type: string xml: @@ -3507,7 +3507,8 @@ paths: "200": content: application/xml: - $ref: "#/components/schemas/Documentation" + schema: + $ref: "#/components/schemas/Documentation" components: schemas: Documentation: @@ -3536,19 +3537,21 @@ paths: "200": content: application/xml: - xml: - nodeType: element - name: StoredDocument - $ref: "#/components/schemas/Documentation" + schema: + xml: + nodeType: element + name: StoredDocument + $ref: "#/components/schemas/Documentation" put: requestBody: required: true content: application/xml: - xml: - nodeType: element - name: UpdatedDocument - $ref: "#/components/schemas/Documentation" + schema: + xml: + nodeType: element + name: UpdatedDocument + $ref: "#/components/schemas/Documentation" responses: "201": {} components: From 373a374467ab6efe5468f88c60244611c1b923f5 Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Thu, 12 Jun 2025 10:03:06 -0700 Subject: [PATCH 14/16] Update src/oas.md --- src/oas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/oas.md b/src/oas.md index 002bce37f2..0624358d25 100644 --- a/src/oas.md +++ b/src/oas.md @@ -3694,7 +3694,7 @@ The in-memory instance data structure for the above example would be: ###### XML With `null` Values Recall that the schema validates the in-memory data, not the XML document itself. -The properties of the `"metadata"` element are omitted for brevity as it is here to show how the `null` value is represented. +The properties of the `"related"` element object are omitted for brevity as it is here to show how the `null` value is represented. ```yaml product: From c7f0c473dbce591822aa9169e07727d3b8a6e37d Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Fri, 13 Jun 2025 09:15:55 -0700 Subject: [PATCH 15/16] Add positive schema tests for XML nodeType --- tests/schema/pass/media-type-examples.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/schema/pass/media-type-examples.yaml b/tests/schema/pass/media-type-examples.yaml index 5a263f037f..2ab4e68076 100644 --- a/tests/schema/pass/media-type-examples.yaml +++ b/tests/schema/pass/media-type-examples.yaml @@ -53,6 +53,26 @@ paths: type: string xml: attribute: true + elementNode: + $ref: "#/components/schemas/Pet" + xml: + nodeType: element + attributeNode: + type: string + xml: + nodeType: attribute + textNode: + type: string + xml: + nodeType: text + cdataNode: + type: string + xml: + nodeType: cdata + noneNode: + type: object + xml: + nodeType: none application/x-www-form-urlencoded: schema: type: object From 12df956971c09f1a8f94a2b375512bbf6782207d Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Fri, 13 Jun 2025 09:16:36 -0700 Subject: [PATCH 16/16] Add negative nodeType schema tests --- tests/schema/fail/xml-attr-exclusion.yaml | 11 +++++++++++ tests/schema/fail/xml-wrapped-exclusion.yaml | 11 +++++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/schema/fail/xml-attr-exclusion.yaml create mode 100644 tests/schema/fail/xml-wrapped-exclusion.yaml diff --git a/tests/schema/fail/xml-attr-exclusion.yaml b/tests/schema/fail/xml-attr-exclusion.yaml new file mode 100644 index 0000000000..b48a02d1a5 --- /dev/null +++ b/tests/schema/fail/xml-attr-exclusion.yaml @@ -0,0 +1,11 @@ +openapi: 3.2.0 +info: + title: API + version: 1.0.0 +components: + schemas: + Attr: + type: string + xml: + attribute: true + nodeType: attribute diff --git a/tests/schema/fail/xml-wrapped-exclusion.yaml b/tests/schema/fail/xml-wrapped-exclusion.yaml new file mode 100644 index 0000000000..74f8ea512e --- /dev/null +++ b/tests/schema/fail/xml-wrapped-exclusion.yaml @@ -0,0 +1,11 @@ +openapi: 3.2.0 +info: + title: API + version: 1.0.0 +components: + schemas: + List: + type: array + xml: + wrapped: true + nodeType: element