XML

To use this module, include the following line in your project file:

require engine.format.xml_core // or require engine.core

Deserialize XML strings into typed Daslang values.

Use from_xml to parse an XML string into a typed Daslang value. The module is parse-only: there is no to_xml, because a struct field can map to an XML attribute, a child element or the element’s text, so there is no single unambiguous serialize direction (unlike JSON’s to_json).

Usage example:

struct Player {
    name : string
    score : int
}

// <player name="Alice" score="42"/>
var loaded : Player
from_xml("<player name=\"Alice\" score=\"42\"/>", loaded)
// loaded.name == "Alice", loaded.score == 42

from_xml walks from the document’s single root element, so the destination struct maps to that root (the way a JSON object root maps to a struct for from_json).

Mapping convention

One convention decides where each field’s value comes from - no per-field configuration is needed beyond the two annotations below:

  • a flat field (bool, int, uint, int64, uint64, float, double, string, enum, bitfield) reads the same-named attribute of the struct’s element;

  • a struct field reads a single same-named child element;

  • an array<T> field reads the repeated same-named child elements, in document order;

  • a field marked @xml_inner_text reads the element’s text content.

Unknown attributes and child elements are ignored, exactly as extra JSON keys are ignored by from_json. Fields whose attribute/element is absent keep the value the destination already has (its field initializer default on a freshly constructed value).

Field annotations

@rename = "key"

Use key as the attribute/element name instead of the field name. The same annotation from_json uses, so one struct reads from both formats. Also needed when the XML name is a Daslang reserved word (e.g. type, template):

struct Object {
    @rename = "type"
    type_ : string
}

// reads the "type" attribute: <object type="hero"/>
@xml_inner_text

Read the field from the element’s text content (PCDATA and CDATA) rather than an attribute or child. Element text has no name, so it cannot follow the same-named rule and needs this marker:

struct Data {
    @rename = "encoding"
    encoding : string       // <data encoding="csv"> attribute
    @xml_inner_text
    text : string           // the text between <data> and </data>
}

CDATA

Text read via @xml_inner_text includes CDATA sections verbatim, so characters that would otherwise need escaping (<, &) pass through unchanged:

struct Note {
    @xml_inner_text
    text : string
}

var note : Note
from_xml("<note><![CDATA[a<b & c]]></note>", note)
// note.text == "a<b & c"

Supported types

  • Primitives: bool, int, uint, int64, uint64, float, double, string

  • Enums and bitfields (enums matched by member name; bitfields parsed from a numeric string)

  • Structs (non-class, non-lambda)

  • array<T> (element type must be serializable)

Numeric/bool/string values are parsed from their attribute or text string; a value that fails to parse leaves the field at its current value (its default), so malformed input never corrupts a field. Tables and tuples are not supported.

File loading

The engine imports .xml files as text assets (alongside .txt and .json); read a file’s contents with request_text and pass the string to from_xml.

Functions

from_xml(xml_str: string; value: any)

Deserializes an XML string into a typed Daslang value.

Supports structs, arrays and primitive types, parsing from the document’s root element. There is no to_xml - unlike JSON, a struct field can map to an attribute, a child element or the element’s text, so there is no unambiguous serialize direction; XML is parse-only.

One mapping convention decides where each field’s value comes from (no per-field DSL):

  • a flat field (int/float/bool/string/enum/bitfield) reads the same-named attribute of the struct’s element;

  • a struct field reads a single same-named child element;

  • an array<T> field reads the repeated same-named child elements, in document order;

  • a field annotated @xml_inner_text reads the element’s text content (PCDATA and CDATA).

@rename = "key" overrides the attribute/element name (the same annotation from_json honors), so a struct annotated for JSON reads from XML unchanged. Unknown attributes and child elements are ignored, exactly as from_json ignores extra JSON keys.

Fields missing in the XML keep the value the destination variable already has. Array elements are created by the deserializer and initialized with the struct’s field initializers (by running its generated zero-argument constructor), so attributes absent on an element read as the declared defaults.

Note

The generated constructor of a struct that is never constructed explicitly in script code can be removed by dead code elimination - array elements of such a struct then stay zero-initialized and the field initializers are lost. Add options always_export_initializer to the module declaring the struct to keep its constructor alive.

Arguments:
  • xml_str : string implicit - XML string to parse

  • value : any - variable to deserialize into (must be var, non-const)

Usage example:

options always_export_initializer // keep struct ctors for from_xml defaults

struct Tile {
    id : int
    @rename = "type"
    type_ : string
    visible : bool = true      // absent attribute -> keeps this default
}

struct Layer {
    name : string
    @rename = "tile"
    tile : array<Tile>         // repeated <tile> children
}

var layer : Layer
from_xml("<layer name=\"ground\"><tile id=\"1\" type=\"grass\"/><tile id=\"2\"/></layer>", layer)
// layer.name == "ground"
// layer.tile[0].id == 1, layer.tile[0].type_ == "grass", layer.tile[0].visible == true
// layer.tile[1].id == 2, layer.tile[1].visible == true (default kept)

// @xml_inner_text reads the element body (CDATA passes '<' and '&' through verbatim)
struct Note {
    @xml_inner_text
    text : string
}
var note : Note
from_xml("<note><![CDATA[a<b & c]]></note>", note)
// note.text == "a<b & c"