Xml Basic Support Proposal
To get basic support for xml we should get parity with OpenAPI
- Swagger/OAS 2.0: https://swagger.io/specification/v2/#xml-object
- OAS 3.0: https://swagger.io/specification/v3/#xml-object\
- OAS 3.1: https://spec.openapis.org/oas/latest.html#xml-modeling
This means we need to have ways of specifying the following:
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 and only if wrapped is true. If wrapped is false, it will be ignored. |
namespace | string | The URI of the namespace definition. This MUST be in the form of an absolute URI. |
prefix | string | The prefix to be used for the 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, |
x-ms-text | boolean | Autorest doc | OpenAPI Issue |
Attributes coverage
1. name
Name is something we can already provide with @encodedName("application/xml", "newname")
1.b Add @Xml.name
decorator
Add an @Xml.name
decorator that would just call @encodedName("application/xml", "newname")
for you.
It should not be saving any extra state. It should really just be a shorthand for @encodedName("application/xml", "newname")
and in no way using @xml.name("newname")
achieve different functionality from @encodedName("application/xml", "newname")
.
2. attribute
Decorator would specify that this property should be serialized as an attribute instead.
extern dec attribute(target: ModelProperty);
Restrictions:
@attribute
can only be applied to model properties of scalar types
3. wrapped
and x-ms-text
Proposing that when dealing with arrays we always wrap them by default.
We are saying that there is always a node created for a property.
We then have a decorator @unwrapped
that allows you to not wrap the property content.
In the case of an array property this is equivalent to setting wrapped: false
in OpenAPI.
In the case of a scalar property this is equivalent to setting x-ms-text: true
in OpenAPI with Autorest extensions.
extern dec unwrapped(target: ModelProperty);
4. namespace
and prefix
Define a new namespace
decorator that can be used in two ways.
extern dec ns(target: unknown, prefix: string, namespace: string)
extern dec ns(target: unknown, namespace: EnumMember)
- Simple but more verbose as you need to keep reusing the same namespace
@ns("ns1", "https://example.com/ns1")
model Foo {
@ns("ns1", "https://example.com/ns1")
bar: string
@ns("ns2", "https://example.com/ns2")
bar: string
}
You could also use an alias to reuse
alias ns1 = "https://example.com/ns1";
alias ns2 = "https://example.com/ns2";
@ns("ns1", ns1)
model Foo {
@ns("ns1", ns1)
bar: string
@ns("ns2", ns2)
bar: string
}
- Using an enum to define the namespace:
enum Namespaces {
ns1 = "https://example.com/ns1",
ns2 = "https://example.com/ns2"
}
@Xml.ns(Namespaces.ns1)
model Foo {
@Xml.ns(Namespaces.ns1)
bar: string
@Xml.ns(Namespaces.ns2)
bar: string
}
4.a Do we need a decorator to annoate the enum?
@Xml.nsDeclarations
enum Namespaces {
ns1 = "https://example.com/ns1",
ns2 = "https://example.com/ns2"
}
@Xml.ns(Namespaces.ns1)
model Foo {
@Xml.ns(Namespaces.ns1)
bar: string
@Xml.ns(Namespaces.ns2)
bar: string
}
Default encoding of scalars
As in Json we need to have some default handling of the common scalars like utcDateTime
Scalar Type | Default Encoding | Encoding name |
---|---|---|
utcDateTime | xs:dateTime | TypeSpec.Xml.Encoding.xmlDateTime |
offsetDateTime | xs:dateTime | TypeSpec.Xml.Encoding.xmlDateTime |
plainDate | xs:date | TypeSpec.Xml.Encoding.xmlDate |
plainTime | xs:time | TypeSpec.Xml.Encoding.xmlTim |
duration | xs:duration | TypeSpec.Xml.Encoding.xmlDuration |
bytes | xs:base64Binary | TypeSpec.Xml.Encoding.xmlBase64Binary |
Changes to add
Create new @typespec/xml
library
New decorators
namespace TypeSpec.Xml
extern dec name(target: ModelProperty);
extern dec attribute(target: ModelProperty);
extern dec unwrapped(target: ModelProperty);
extern dec ns(target: unknown, namespaceOrPrefix: EnumMember | valueof string, namespace?: string);
extern dec nsDeclaration(target: Enum);
enum Encoding {
/** Maps to encoding to a value used in xs:date */
xmlDate,
/** Maps to encoding to a value used in xs:time */
xmlTime,
/** Maps to encoding to a value used in xs:dateTime */
xmlDateTime,
/** Maps to encoding to a value used in xs:duration */
xmlDuration,
/** Maps to encoding to a value used in xs:base64Binary */
xmlBase64Binary,
}
Apis to Add
To figure out if it is better to have those as fully qualifed id to the enum member name or just return the enum member directly. This most likely need a change in the compiler to
- return the fully qualified enum member name(unless they are from the compiler)
- return the enum member directly via a different api ?
export function resolveXmlEncoding(type: Scalar): XmlEncoding | string;
export type XmlEncoding =
| "TypeSpec.Xml.Encoding.xmlDate"
| "TypeSpec.Xml.Encoding.xmlDate"
| "TypeSpec.Xml.Encoding.xmlDateTime"
| "TypeSpec.Xml.Encoding.xmlDuration"
| "TypeSpec.Xml.Encoding.xmlBase64Binary"
| string;
Examples
1. Array of primitive types
Scenario | TypeSpec | Xml | OpenAPI3 |
Scenario 1.1:
|
|
|
|
Scenario 1.2:
|
|
|
|
Scenario 1.3:
|
|
|
|
Scenario 1.4:
|
|
|
|
2. Complex array types
Scenario | TypeSpec | Xml | OpenAPI3 |
Scenario 2.1:
|
|
|
|
Scenario 2.2:
|
|
|
|
Scenario 2.3:
|
|
|
|
Scenario 2.4:
|
|
|
|
3. Nested models
Scenario | TypeSpec | Xml | OpenAPI3 |
Scenario 3.1: No annotations |
|
|
|
Scenario 3.2: Nested model has xml encoded name. ⚠️ no op in serialization of Book |
|
|
|
Scenario 3.2: Property has encoded name |
|
|
|
4. Attributes
Scenario | TypeSpec | Xml | OpenAPI3 |
Scenario 4.1: Convert a property to an attribute |
|
|
|
5. Namespace and prefix (inline form)
Scenario | TypeSpec | Xml | OpenAPI3 |
Scenario 5.1: On model |
|
|
|
Scenario 5.2: On model and properties |
|
|
|
6. Namespace and prefix (normalized form)
Scenario | TypeSpec | Xml | OpenAPI3 |
Scenario 6.1: On model |
|
|
|
Scenario 6.2: On model and properties |
|
|
|
6. Property setting the text of the node
Scenario | TypeSpec | Xml | OpenAPI3 |
Scenario 6.1: |
|
|
|