跳到导航

XML-encoded types

以 Markdown 格式查看

Object types that carry XML encoding metadata are generated as XML-capable models. Each one gets a serializer, a strict parser, and fluent builder methods for its child elements, so SDK users build and read XML documents (for example, telephony markup such as TwiML) through typed code instead of hand-written strings.

Fern generates XML support in TypeScript, Python, Java, C#, Go, Ruby, and PHP SDKs. No generators.yml configuration is required: generation is driven entirely by the XML metadata in your API definition. Types without XML metadata are unchanged, and the XML runtime is only added to an SDK when an XML-encoded type references it.

Define types with XML metadata

Fern reads the OpenAPI xml object on object schemas and their properties. name sets the element or attribute name, attribute: true emits a property as an XML attribute instead of a child element, and wrapped: true wraps an array in a container element. prefix and namespace are honored as well.

components:
schemas:
Garden:
type: object
xml:
name: Garden
properties:
climate:
type: string
xml:
attribute: true
plants:
type: array
items:
$ref: "#/components/schemas/Plant"
xml:
name: Plants
wrapped: true
Plant:
type: object
xml:
name: Plant
properties:
sunlight:
type: string
enum: [full, partial, shade]
xml:
attribute: true
name:
type: string

This definition describes documents like:

<?xml version="1.0" encoding="UTF-8"?>
<Garden climate="temperate">
<Plants>
<Plant sunlight="full">Fern</Plant>
</Plants>
</Garden>

Element names, attributes, text bodies, nested and union children, repeated children, wrapped lists, list separators on attributes and text, namespaces, prefixes, and escaping are all honored.

Generated methods

Every XML-encoded type gets three capabilities, named idiomatically per language:

  • Serialize: toXml() (to_xml in Python and Ruby, ToXml() in C# and Go) returns the element as an XML string. Root types (types never nested inside another XML type) include the <?xml version="1.0" encoding="UTF-8"?> declaration.
  • Parse: fromXml(xml) (from_xml in Python and Ruby, FromXml() in C#, <Type>FromXml() in Go) parses an XML string back into the model. Parsing is strict: it validates the root element name and scalar and enum values, and rejects malformed input and DOCTYPE declarations.
  • Build: one fluent method per child element type, named after the XML tag (for example, garden.plant(...)). Each method constructs the child, appends it, and returns it so children can be chained. A child method gets an add prefix (addPlant, add_plant, AddPlant) when its tag collides with a property or method of the parent, or when the name is a reserved word (addBreak in TypeScript, break_ in Python and Ruby).
const garden = SeedApi.Garden.builder({ climate: "temperate" });
garden.plant("Fern", { sunlight: "full" });
const xml = garden.toXml();
const parsed = SeedApi.Garden.fromXml(xml); // immutable model
const rebuilt = SeedApi.Garden.Builder.fromXml(xml).build(); // populated builder

C#, Go, Ruby, and PHP also expose element-level variants (ToXElement()/FromXElement(), ToXmlElement()/<Type>FromXmlElement(), to_xml_element/from_xml_element, toXmlElement()/fromXmlElement()) for composing documents without re-parsing strings.

Round-tripping unknown content

Attributes and child elements that the schema doesn’t declare aren’t dropped. Parsing preserves them (additionalAttributes/additionalChildren in TypeScript, C#, Ruby, and PHP; ExtraAttributes/ExtraChildren in Go; getAdditionalChildren() in Java; extra attributes and XmlElement children in Python) and serialization re-emits them, so fromXml(model.toXml()) reproduces the original document. An addChild method (add_child in Python and Ruby, AddChild in C# and Go) appends an arbitrary element when building. Undeclared children are emitted after declared ones, so mixed-content ordering isn’t preserved.