Giter Club home page Giter Club logo

Comments (3)

tnc1997 avatar tnc1997 commented on June 25, 2024

Hi @Matej-Hlatky, I would be interested in your opinion on an XmlConverter annotation vs fromXml... and toXml... fields on the existing annotations. I am not entirely sure that XmlConverter would be able to work quite like JsonConverter. The field being serialized could be an XmlAttribute or an XmlElement to name a few, and whilst the developer is likely only interested in the value of the XmlAttribute, they might be interested in the entire XmlElement instead of just its text, especially if the XmlElement contains nested children. Here are some of the different proposals that I have considered so far:

@annotation.XmlSerializable()
class One {
  @annotation.XmlAttribute(fromXmlAttribute: base64BinaryFromXmlAttribute, toXmlAttribute: base64BinaryToXmlAttribute)
  Uint8List attribute;

  @annotation.XmlElement(fromXmlElement: base64BinaryFromXmlElement, toXmlElement: base64BinaryToXmlElement)
  Uint8List element;

  ...
}

Uint8List base64BinaryFromXmlAttribute(XmlAttribute attribute) {
  return base64.decode(attribute.value);
}

XmlAttribute base64BinaryToXmlAttribute(Uint8List value) {
  return XmlAttribute(XmlName('???'), base64.encode(value));
}

Uint8List base64BinaryFromXmlElement(XmlElement element) {
  final text = element.getText()!;

  return base64.decode(text);
}

XmlElement base64BinaryToXmlElement(Uint8List value) {
  final text = base64.encode(value);

  return XmlElement(XmlName('???'), [], [XmlText(text)]);
}
@annotation.XmlSerializable()
class Two {
  @annotation.XmlAttribute(fromXml: base64BinaryFromXml, toXml: base64BinaryToXml)
  Uint8List attribute;

  @annotation.XmlElement(fromXml: base64BinaryFromXml, toXml: base64BinaryToXml)
  Uint8List element;

  ...
}

Uint8List base64BinaryFromXml(String value) => base64.decode(value);

String base64BinaryToXml(Uint8List value) => base64.encode(value);
// xml_annotation/lib/src/annotations/xml_attribute_converter.dart
abstract class XmlAttributeConverter<T> {
  const XmlAttributeConverter();

  T fromXmlAttribute(XmlAttribute attribute);

  XmlAttribute toXmlAttribute(T object);
}

// xml_annotation/lib/src/annotations/xml_element_converter.dart
abstract class XmlElementConverter<T> {
  const XmlElementConverter();

  T fromXmlElement(XmlElement element);

  XmlElement toXmlElement(T object);
}

@annotation.XmlSerializable()
class Three {
  @annotation.XmlAttribute()
  @Base64BinaryConverter()
  Uint8List attribute;

  @annotation.XmlElement()
  @Base64BinaryConverter()
  Uint8List element;

  ...
}

class Base64BinaryConverter implements annotation.XmlAttributeConverter<Uint8List>, annotation.XmlElementConverter<Uint8List> {
  const Base64BinaryConverter();

  @override
  Uint8List fromXmlAttribute(XmlAttribute attribute) {
    return base64.decode(attribute.value);
  }

  @override
  XmlAttribute toXmlAttribute(Uint8List object) {
    return XmlAttribute(XmlName('???'), base64.encode(object));
  }

  @override
  Uint8List fromXmlElement(XmlElement element) {
    final text = element.getText()!;

    return base64.decode(text);
  }

  @override
  XmlElement toXmlElement(Uint8List object) {
    final text = base64.encode(object);

    return XmlElement(XmlName('???'), [], [XmlText(text)]);
  }
}
// xml_annotation/lib/src/annotations/xml_converter.dart
abstract class XmlConverter<T> {
  const XmlConverter();

  T fromXml(String value);

  String toXml(T object);
}

@annotation.XmlSerializable()
class Four {
  @annotation.XmlAttribute()
  @Base64BinaryConverter()
  Uint8List attribute;

  @annotation.XmlElement()
  @Base64BinaryConverter()
  Uint8List element;

  ...
}

class Base64BinaryConverter implements annotation.XmlConverter<Uint8List> {
  const Base64BinaryConverter();

  @override
  Uint8List fromXml(String value) => base64.decode(value);

  @override
  String toXml(Uint8List object) => base64.encode(object);
}

Two is simpler than One but it doesn't support creating an instance of the custom type using nested children.

Four is the equivalent of Two using a custom XmlConverter annotation instead of fromXml and toXml fields.

from dart-xml-serializable.

Matej-Hlatky avatar Matej-Hlatky commented on June 25, 2024

Hi @tnc1997 ,
personally, I couldn't find any real use case for XML element conversion, but only attribute (aka scalar type) --
String to base64binary, time, ...

Of course, sometimes you need to map whole XML document (or JSON Object, GraphQL Fragment) to your specific model,
however this shoudl be dealt with in Domain layer.

Also usage of types of converted types instead of "raw" XML elements from XSD schema or other documentation could make it not only harder to write and validate, but then also harder to debug just by comparing the structure "optically" and also writing tests.

So let's stick to the attribute (scalar) mapping; same as in json_convert for JSON and GraphQL does it.

from dart-xml-serializable.

tnc1997 avatar tnc1997 commented on June 25, 2024

I couldn't find any real use case for XML element conversion.

It looks like JsonConvert allows conversion to/from Map<String, dynamic>, which would allow converting a nested object (e.g. {"date": "2023-10-08", "time": "12:00:00"}) to/from a type (e.g. DateTime). In theory a Map<String, dynamic> is somewhat synonymous with an XmlElement. That being said, I do agree that opting for just scalar mapping is easier and simpler.

{
  "a": { "year": 2023, "month": 10, "day": 8 },
  "b": 1696793104943
}
@JsonSerializable()
class Example {
  @_CustomDateTimeConverter()
  final DateTime a;

  @_EpochDateTimeConverter()
  final DateTime b;

  ...
}

class _CustomDateTimeConverter implements JsonConverter<DateTime, Map<String, dynamic>> {
  const _CustomDateTimeConverter();

  @override
  DateTime fromJson(Map<String, dynamic> json) => DateTime(json['year'] as int, json['month'] as int, json['day'] as int);

  @override
  Map<String, dynamic> toJson(DateTime object) => {'year': object.year, 'month': object.month, 'day': object.day};
}

class _EpochDateTimeConverter implements JsonConverter<DateTime, int> {
  const _EpochDateTimeConverter();

  @override
  DateTime fromJson(int json) => DateTime.fromMillisecondsSinceEpoch(json);

  @override
  int toJson(DateTime object) => object.millisecondsSinceEpoch;
}
<?xml version="1.0" encoding="UTF-8"?>
<example b="1696793104943">
    <a>
        <year>2023</year>
        <month>10</month>
        <day>8</day>
    </a>
</example>
@annotation.XmlSerializable()
class Example {
  @annotation.XmlElement()
  @_CustomDateTimeConverter()
  final DateTime a;

  @annotation.XmlAttribute()
  @_EpochDateTimeConverter()
  final DateTime b;

  ...
}

class _CustomDateTimeConverter implements annotation.XmlElementConverter<DateTime> {
  const _CustomDateTimeConverter();

  @override
  DateTime fromXmlElement(XmlElement element) => DateTime(
    int.parse(element.getElement('year')!.getText()!),
    int.parse(element.getElement('month')!.getText()!),
    int.parse(element.getElement('day')!.getText()!),
  );

  @override
  XmlElement toXmlElement(DateTime object) => XmlElement(
    XmlName('???'),
    [],
    [
      XmlElement(XmlName('year'), [], [XmlText(object.year.toString())]),
      XmlElement(XmlName('month'), [], [XmlText(object.month.toString())]),
      XmlElement(XmlName('day'), [], [XmlText(object.day.toString())]),
    ],
  );
}

class _EpochDateTimeConverter implements annotation.XmlAttributeConverter<DateTime> {
  const _EpochDateTimeConverter();

  @override
  DateTime fromXmlAttribute(XmlAttribute attribute) => DateTime.fromMillisecondsSinceEpoch(int.parse(attribute.value));

  @override
  XmlAttribute toXmlAttribute(DateTime object) => XmlAttribute(XmlName('???'), object.millisecondsSinceEpoch.toString());
}

from dart-xml-serializable.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.