xml_annotator 0.1.0 copy "xml_annotator: ^0.1.0" to clipboard
xml_annotator: ^0.1.0 copied to clipboard

Annotations and runtime helpers for declarative XML (de)serialization in Dart. The runtime companion to the xml_serializer build_runner generator.

xml_annotator #

pub package license: MIT

Annotations and runtime helpers for XML serialization in Dart. The annotations describe how a class maps to XML; the runtime helpers back the parse/serialize code. Pairs with the xml_serializer generator.

Install #

dart pub add xml_annotator
dependencies:
  xml_annotator: ^0.1.0

Needs Dart SDK ^3.9.0.

Imports #

Import both libraries:

import 'package:xml_annotator/xml_annotator.dart'; // annotations
import 'package:xml_annotator/runtime.dart';         // parse/write + helpers

Example #

import 'package:xml_annotator/runtime.dart';
import 'package:xml_annotator/xml_annotator.dart';

part '../xml_annotation/reading.g.dart';

@XmlSerializer()
@XmlRoot('reading')
class Reading {
  @XmlAttribute()
  final String station;

  @XmlElement()
  final double temperature;

  Reading({required this.station, required this.temperature});

  factory Reading.fromXml(XmlElementNode e) => $ReadingFromXml(e);
  void toXml(XmlBuilder b) => $ReadingToXml(this, b);
}
final xml = writeXmlDocument(
  Reading(station: 'KSEA', temperature: 18.4).toXml,
  declaration: false,
);
// <reading station="KSEA"><temperature>18.4</temperature></reading>

final reading = Reading.fromXml(parseXmlDocument(xml));

Annotations #

Class and root #

Annotation On Purpose
@XmlSerializer(...) class / enum Marks a type as XML-serializable. Required on every mapped type.
@XmlRoot(name, ...) class The element name a type uses as a document root. Nested-only types omit it and take their name from the field that references them.

@XmlSerializer:

  • fieldRename - name style for fields with no explicit name:. Default none.
  • createFromXml / createToXml - skip the read or write side when false. Both default true.
  • namespaces - prefix -> URI map for this type's fields. '' is the default namespace.
  • declares - force prefix -> URI declarations on the root, for namespaces hidden inside raw passthrough.

@XmlRoot:

  • namespace - URI for the root element.
  • prefix - prefix to write (null = default namespace).
  • enforceOnRead - verify the root name/namespace on read, throw on mismatch. Default false.

Node kinds #

One per field. An unannotated public field is treated as @XmlElement.

Annotation Maps the field to Params
@XmlElement a child element (default) name, namespace, prefix, omitEmpty, defaultValue
@XmlAttribute an attribute name, namespace, prefix, omitEmpty, defaultValue
@XmlText the element's text omitEmpty
@XmlInnerXml raw inner XML, verbatim (String) -
@XmlAnyElement every child no other field claims -
@XmlIgnore nothing - skips the field -

@XmlElement / @XmlAttribute params:

  • name - XML name. null derives it from the field via fieldRename.
  • namespace - URI for this field. A read constraint, auto-declared on the root.
  • prefix - write-time prefix override. Needs a namespace.
  • omitEmpty - skip writing an empty/zero value. Scalars only (int / double / String / bool); a build error elsewhere, so use a nullable T? for optional fields. Derives a read-side zero fallback.
  • defaultValue - read fallback when the node is absent and the field is non-nullable. Usually unneeded; the constructor default covers it.

Enums #

@XmlEnum() // optional: unknownValue: Priority.low
enum Priority {
  @XmlValue('lo') low,
  @XmlValue('med') medium,
  @XmlValue('hi') high,
}
  • @XmlEnum({unknownValue}) - marks the enum. unknownValue is the fallback for an unknown literal on read; null (default) throws.
  • @XmlValue(literal) - the serialized form. Every constant needs one.

Converters #

For values the built-in coercions don't cover. A const instance of your converter is the annotation.

class BoolZeroOne implements XmlValueConverter<bool> {
  const BoolZeroOne();
  @override
  bool fromXmlString(String raw) => raw == '1' || raw == 'true';
  @override
  String toXmlString(bool value) => value ? '1' : '0';
}

class CellFormat {
  @XmlAttribute(name: 'val')
  @BoolZeroOne()
  final bool bold;
  CellFormat({required this.bold});
}
  • XmlValueConverter<T> - T to/from a single attribute or text string (fromXmlString / toXmlString). Annotate the type to convert every field of that type automatically.
  • XmlElementConverter<T> - T to/from a whole element body (readElement / buildElementBody), for bodies that can't be described with fields. buildElementBody keeps the runtime writeElement / writeText helpers callable inside it.

A value converter on an @XmlSerializer type is a build error.

Defaults and optionality #

When a non-nullable field is absent on read, the fallback resolves in order:

  1. defaultValue:, else
  2. the constructor parameter's default, else
  3. zero, for an omitEmpty scalar, else
  4. throw XmlDeserializationException.

Namespaces #

Bind each prefix <-> URI once on the class; fields reference the URI:

const dcUri = 'http://purl.org/dc/elements/1.1/';

@XmlSerializer(namespaces: {'dc': dcUri})
@XmlRoot('record')
class Record {
  @XmlElement(name: 'id') final String id;
  @XmlElement(name: 'title', namespace: dcUri) final String title;
}
// <record xmlns:dc="..."><id>...</id><dc:title>...</dc:title></record>

Every namespace is hoisted to one declaration on the root. Reads match by URI, not prefix. A field prefix: overrides the class map; a URI bound by neither is a build error.

License #

MIT © Kawaljeet Singh

0
likes
140
points
0
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Annotations and runtime helpers for declarative XML (de)serialization in Dart. The runtime companion to the xml_serializer build_runner generator.

Homepage
Repository (GitHub)
View/report issues

Topics

#xml #serialization #codegen #annotations

License

MIT (license)

Dependencies

meta, xml

More

Packages that depend on xml_annotator