Giter Club home page Giter Club logo

dart-xml-serializable's People

Contributors

marius-h avatar naipotato avatar skycoder42 avatar tnc1997 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

dart-xml-serializable's Issues

Upgrade the version constraint of analyzer

The current version of analyzer used in xml_serializable is creating issues with various other packages like custom_lint, riverpod_lint, riverpod_generator etc. Please update the library to the latest version to resolve the conflicts.

Add support for import prefixes

Describe the bug
When declaring a variable using a prefixed class name, the prefix is not used in the resulting generated file after running build_runner.

Current behavior
Steps to reproduce the behavior:

  1. create a class file that uses a prefixed class name.
import 'package:my_software/device.dart' as device;

class ServiceCapabilities {
  @annotation.XmlElement(
    name: 'Capabilities',
    namespace: 'http://www.onvif.org/ver10/device/wsdl',
  )
  final device.Capabilities? deviceCapabilities;
  1. Use build_runner to generate code.

Expected behavior
It's expected that the generated code would include the device prefix.

ServiceCapabilities _$ServiceCapabilitiesFromXmlElement(XmlElement element) {
  final deviceCapabilities = element.getElement('Capabilities',
      namespace: 'http://www.onvif.org/ver10/device/wsdl');
  return ServiceCapabilities(
      deviceCapabilities: deviceCapabilities != null
          ? device.Capabilities.fromXmlElement(deviceCapabilities)
          : null);
}

The actual code generated has Capabilities.fromXmlElement(deviceCapabilities) when the actual correct code isdevice.Capabilities.fromXmlElement(deviceCapabilities) (as shown above).

Only deserialize fields with an annotation in generate from XML element

Is your feature request related to a problem? Please describe.
I have a class with computed fields (getters). However, when I try to add a getter with computed logic, the generator fails with the error:

[SEVERE] xml_serializable on lib/src/api/login/models/computed.dart:

Invalid argument (element): `isValid` does not have a supported annotation. Add an annotation of the form `@XmlAttribute()`, `@XmlElement()`, or `@XmlText()` to `isValid`.: Instance of 'FieldElementImpl'

Here is the corresponding code:

@xml.XmlSerializable(createMixin: true)
@xml.XmlRootElement(name: 'Computed')
@immutable
class Computed with _$ComputedXmlSerializableMixin {
  @xml.XmlText()
  final String value;

  bool get isValid => value != 'invalid';

  const Computed({required this.value});

  factory Computed.fromXmlElement(XmlElement element) =>
      _$ComputedFromXmlElement(element);
}

Describe the solution you'd like
It would be nice if there was a XmlIgnore annotation (or something similar) so we could simply exclude such members from the generator:

  @xml.XmlIgnore()
  bool get isValid => value != 'invalid';

Describe alternatives you've considered
Another alternative would be to only take members with a Xml annotation into account and implicitly ignore members without it, but I think I would prefer an "ignore" annotation.

Better deserialization of empty elements / empty strings

Hi,
We lately ran into an issue with a an XML file that contains a mandatory element but that one contains an "empty string" like this.

 <?xml version="1.0"?>
  <test>
      <notnull></notnull>
  </test>

The element is there but it is empty. This cannot be parsed and raises an exception. The problem is that the getter code that is generated converts empty string to "null" in dart but at the same time puts a ! on it.

The model to process this XML looks like this:

import 'package:xml/xml.dart';
import 'package:xml_annotation/xml_annotation.dart' as annotation;

part 'xml_null_test.g.dart';


@annotation.XmlRootElement(name: 'test')
@annotation.XmlSerializable()
class XMLNullTest {
  @annotation.XmlElement(name: 'notnull')
  String notnull;

  XMLNullTest({required this.notnull});

  factory XMLNullTest.fromXmlElement(XmlElement element) =>
      _$XMLNullTestFromXmlElement(element);
...

As you can see the field notnull is of type String and is mandatory. But when we parse the XML above it fails with an exception.
the reason for this is the way how the getter is generated. It is generated like this:

final notnull = element.getElement('notnull')!.getText()!;

The method getText() returns null when the string is "empty" in the XML.
See: xml_text_getter_generator.dart
and getText extension method

Null vs "empty string" is not clearly specified in XML and there are many problems related to this. What you did is not "wrong" as it is not clear if an empty element should be interpreted as null or as "empty string". But the problem is that there is no way I could workaround this issue cleanly (only by making my field String? in my code but this is also not nice).

I would propose to make this somehow configurable if empty elements should be treated as null or as "empty strings".
Then it should generate this code:
final notnull = element.getElement('notnull')!.getText() ?? '';

If you do not want to change this as this might be a compatibility issue with existing code, then we could allow to select this via a flag on the @annotation.XmlSerializable() for the whole XML via a new flag.


Here a test case to reproduce this with the simple model class from above. It throws an exception when parsing the XML:

 test('Null XML', () {
    const test = '''
    <?xml version="1.0"?>
    <test>
      <notnull></notnull>
    </test>''';

    final document = XmlDocument.parse(test);
    final model = XMLNullTest.fromXmlElement(document.rootElement);
    expect(model, isNotNull);
  });

Testing started at 09:40 ...

package:amos_mobile_etlb/src/test/xml_null_test.g.dart 29:59 _$XMLNullTestFromXmlElement
package:amos_mobile_etlb/src/test/xml_null_test.dart 15:7 new XMLNullTest.fromXmlElement
test\xml_null_test.dart 15:31 main.

Null check operator used on a null value

Add support for fields in superclasses

Current structure

I have two classes named Student and Schoolclass.

Student extends Schoolclass so that the class Student can use the parameters gradeLevel and teacher.

Student class:

@annotation.XmlRootElement(name: 'Student')
@annotation.XmlSerializable()
class Student extends Schoolclass {
  @annotation.XmlAttribute(name: 'name')
  String name;

  Student({
    required this.name,

    required int gradeLevel,
    required String teacher,
  }) : super(gradeLevel: gradeLevel, teacher: teacher,);

  factory Student.fromXmlElement(XmlElement element) =>
      _$StudentFromXmlElement(element);

  @override
  String toString() {
    return 'Student{name: $name, gradeLevel: $gradeLevel, teacher: $teacher}';
  }

  void buildXmlChildren(
      XmlBuilder builder, {
        Map<String, String> namespaces = const {},
      }) =>
      _$StudentBuildXmlChildren(
        this,
        builder,
        namespaces: namespaces,
      );

  void buildXmlElement(
      XmlBuilder builder, {
        Map<String, String> namespaces = const {},
      }) =>
      _$StudentBuildXmlElement(
        this,
        builder,
        namespaces: namespaces,
      );

  List<XmlAttribute> toXmlAttributes({
    Map<String, String?> namespaces = const {},
  }) =>
      _$StudentToXmlAttributes(
        this,
        namespaces: namespaces,
      );

  List<XmlNode> toXmlChildren({
    Map<String, String?> namespaces = const {},
  }) =>
      _$StudentToXmlChildren(
        this,
        namespaces: namespaces,
      );

  XmlElement toXmlElement({
    Map<String, String?> namespaces = const {},
  }) =>
      _$StudentToXmlElement(
        this,
        namespaces: namespaces,
      );
}

Schoolclass class:

@annotation.XmlRootElement(name: 'Schoolclass')
@annotation.XmlSerializable()
abstract class Schoolclass {
  @annotation.XmlAttribute(name: 'gradeLevel')
  int gradeLevel;

  @annotation.XmlAttribute(name: 'teacher')
  String teacher;

  Schoolclass ({
    required this.gradeLevel,
    required this.teacher,
  });

  factory Schoolclass.fromXmlElement(XmlElement element) =>
      _$SchoolclassFromXmlElement(element);

  @override
  String toString() {
    return 'Schoolclass{gradeLevel: $gradeLevel, teacher: $teacher}';
  }

  void buildXmlChildren(
      XmlBuilder builder, {
        Map<String, String> namespaces = const {},
      }) =>
      _$SchoolclassBuildXmlChildren(
        this,
        builder,
        namespaces: namespaces,
      );

  void buildXmlElement(
      XmlBuilder builder, {
        Map<String, String> namespaces = const {},
      }) =>
      _$SchoolclassBuildXmlElement(
        this,
        builder,
        namespaces: namespaces,
      );

  List<XmlAttribute> toXmlAttributes({
    Map<String, String?> namespaces = const {},
  }) =>
      _$SchoolclassToXmlAttributes(
        this,
        namespaces: namespaces,
      );

  List<XmlNode> toXmlChildren({
    Map<String, String?> namespaces = const {},
  }) =>
      _$SchoolclassToXmlChildren(
        this,
        namespaces: namespaces,
      );

  XmlElement toXmlElement({
    Map<String, String?> namespaces = const {},
  }) =>
      _$SchoolclassToXmlElement(
        this,
        namespaces: namespaces,
      );
}

Current output

When generating the serializer with flutter packages pub run build_runner build, I get the following output:

void _$StudentBuildXmlChildren(Student instance, XmlBuilder builder,
    {Map<String, String> namespaces = const {}}) {
  final name = instance.name;
  final nameSerialized = name;
  builder.attribute('name', nameSerialized);
}

void _$StudentBuildXmlElement(Student instance, XmlBuilder builder,
    {Map<String, String> namespaces = const {}}) {
  builder.element('Student', namespaces: namespaces, nest: () {
    instance.buildXmlChildren(builder, namespaces: namespaces);
  });
}

Student _$StudentFromXmlElement(XmlElement element) {
  final name = element.getAttribute('name')!;
  return Student(name: name);
}

List<XmlAttribute> _$StudentToXmlAttributes(Student instance,
    {Map<String, String?> namespaces = const {}}) {
  final attributes = <XmlAttribute>[];
  final name = instance.name;
  final nameSerialized = name;
  final nameConstructed = XmlAttribute(XmlName('name'), nameSerialized);
  attributes.add(nameConstructed);
  return attributes;
}

List<XmlNode> _$StudentToXmlChildren(Student instance,
    {Map<String, String?> namespaces = const {}}) {
  final children = <XmlNode>[];
  return children;
}

XmlElement _$StudentToXmlElement(Student instance,
    {Map<String, String?> namespaces = const {}}) {
  return XmlElement(
      XmlName('Student'),
      [
        ...namespaces.toXmlAttributes(),
        ...instance.toXmlAttributes(namespaces: namespaces)
      ],
      instance.toXmlChildren(namespaces: namespaces));
}

void _$SchoolclassBuildXmlChildren(Schoolclass instance, XmlBuilder builder,
    {Map<String, String> namespaces = const {}}) {
  final gradeLevel = instance.gradeLevel;
  final gradeLevelSerialized = gradeLevel.toString();
  builder.attribute('gradeLevel', gradeLevelSerialized);
  final teacher = instance.teacher;
  final teacherSerialized = teacher;
  builder.attribute('teacher', teacherSerialized);
}

void _$SchoolclassBuildXmlElement(Schoolclass instance, XmlBuilder builder,
    {Map<String, String> namespaces = const {}}) {
  builder.element('Schoolclass', namespaces: namespaces, nest: () {
    instance.buildXmlChildren(builder, namespaces: namespaces);
  });
}

Schoolclass _$SchoolclassFromXmlElement(XmlElement element) {
  final gradeLevel = element.getAttribute('gradeLevel')!;
  final teacher = element.getAttribute('teacher')!;
  return Schoolclass(gradeLevel: int.parse(gradeLevel), teacher: teacher);
}

List<XmlAttribute> _$SchoolclassToXmlAttributes(Schoolclass instance,
    {Map<String, String?> namespaces = const {}}) {
  final attributes = <XmlAttribute>[];
  final gradeLevel = instance.gradeLevel;
  final gradeLevelSerialized = gradeLevel.toString();
  final gradeLevelConstructed =
      XmlAttribute(XmlName('gradeLevel'), gradeLevelSerialized);
  attributes.add(gradeLevelConstructed);
  final teacher = instance.teacher;
  final teacherSerialized = teacher;
  final teacherConstructed =
      XmlAttribute(XmlName('teacher'), teacherSerialized);
  attributes.add(teacherConstructed);
  return attributes;
}

List<XmlNode> _$SchoolclassToXmlChildren(Schoolclass instance,
    {Map<String, String?> namespaces = const {}}) {
  final children = <XmlNode>[];
  return children;
}

XmlElement _$SchoolclassToXmlElement(Schoolclass instance,
    {Map<String, String?> namespaces = const {}}) {
  return XmlElement(
      XmlName('Schoolclass'),
      [
        ...namespaces.toXmlAttributes(),
        ...instance.toXmlAttributes(namespaces: namespaces)
      ],
      instance.toXmlChildren(namespaces: namespaces));
}

Expected behavior

The function _$StudentFromXmlElement() does not feature the parameters of the extended class and because the parameters are required by the constructor the function will not work.

Student _$StudentFromXmlElement(XmlElement element) {
  final name = element.getAttribute('name')!;
  return Student(name: name);
}

Question

How can polymorphism be achieved with dart-xml-serializable?

Add support for serializing XML CDATA

Is your feature request related to a problem? Please describe.
As a developer I would like to serialize and deserialize XML CDATA in addition to XML text.

Describe the solution you'd like
I would like the xml_annotation package to export an XmlCDATA annotation.

Additional context
#45

Add support for renaming fields in a class

Is your feature request related to a problem? Please describe.
It is not possible to rename fields in a class to a case that isn't camel case without having to specify the name of each field.

Describe the solution you'd like
I would like to see a fieldRename option on XmlSerializable that allows for the renaming of fields in a class to the specified case.

Describe alternatives you've considered
The workaround at the moment is to specify the name of each field using the XmlAttribute and XmlElement annotations.

Some methods not generated by builder

To preface this, I have no idea what I'm doing, so, it's probably my fault. I'm writing a grade viewer app, which pulls a very large XML file from the gradebook service my school uses. I've got that stored in a string, and then followed the instructions in the docs, so I have a very large file with all the classes and things properly annotated. However, when I run the builder, the buildXmlElement and toXmlElement methods generated for only half of the classes.

Here is a sample of the XML I am deserializing:

<?xml version="1.0" encoding="UTF-8"?>
<Gradebook xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Type="Traditional" ErrorMessage="" HideStandardGraphInd="false" HideMarksColumnElementary="true" HidePointsColumnElementary="false" HidePercentSecondary="false" DisplayStandardsData="true" GBStandardsTabDefault="true">
   <ReportingPeriods>
      <ReportPeriod Index="0" GradePeriod="Quarter 1" StartDate="9/1/2022" EndDate="11/7/2022" />
      <ReportPeriod Index="1" GradePeriod="Semester 1 Final" StartDate="11/8/2022" EndDate="1/27/2023" />
      <ReportPeriod Index="2" GradePeriod="Quarter 3" StartDate="1/30/2023" EndDate="4/20/2023" />
      <ReportPeriod Index="3" GradePeriod="Semester 2 FInal" StartDate="4/21/2023" EndDate="6/22/2023" />
   </ReportingPeriods>
   <ReportingPeriod GradePeriod="Semester 2 FInal" StartDate="4/21/2023" EndDate="6/22/2023" />
   <Courses>
      <Course UsesRichContent="true" Period="1" Title="AP Comp Sci Princ" Room="xxx" Staff="xxxx" StaffEMail="xxxxxx@xxxxxorg" StaffGU="xxxxxxxxx" HighlightPercentageCutOffForProgressBar="50">
...

And part of the class (it's too long to share the whole thing, though I could put it up on github if that would be helpful):

@annotation.XmlElement(name: "GradeBook")
@annotation.XmlSerializable()
class GradeBook {
  @annotation.XmlElement(name: "ReportingPeriods")
  ReportingPeriods? reportingPeriods;
  @annotation.XmlElement(name: "ReportingPeriod")
  ReportingPeriod? reportingPeriod;
  @annotation.XmlElement(name: "Courses")
  Courses? courses;

  GradeBook({
    this.reportingPeriods,
    this.reportingPeriod,
    this.courses
  });

  @override
  String toString() {
    return 'GradeBook {'
        ' Reporting Periods: $reportingPeriods'
        ' Reporting Period: $reportingPeriod'
        ' Courses: $courses'
        '}';
  }

  factory GradeBook.fromXmlElement(XmlElement element) =>
      _$GradeBookFromXmlElement(element);

  void buildXmlChildren(
      XmlBuilder builder, {
        Map<String, String> namespaces = const {},
      }) =>
      _$GradeBookBuildXmlChildren(
        this,
        builder,
        namespaces: namespaces,
      );
...

I'm not sure why it's not working, I also only need to deserialize xml, so if this doesn't matter for that then I will just delete the ones that didn't generate and move on. Secondly, how do I use this? Now that there is a nice interface, what should I do to turn my String containing all the XML into Dart objects?

Thank you so much in advanced! You're a saint for almost single-handedly maintaining this library it's super useful, and surprisingly easy to setup despite the boilerplate.

Created List of single null class object but xml element is empty

Describe the bug
Created List of null class object but element is null (selfclosed)
Help me please, may be I do smt wrong.

Current behavior

      <UiMenuItem>
        <Id>0</Id>
        <Name>one</Name>
        <Hint/>
        <Url/>
        <IconUrl>https://test.com</IconUrl>
        <Kind>SubMenu</Kind>
        <Action>Undefined</Action>
        <Items>
          <UiMenuItem>
            <Id>13692716</Id>
            <Name>qwdqw</Name>
            <Hint/>
            <Url/>
            <IconUrl>https://test.com</IconUrl>
            <Kind>Action</Kind>
            <Action>Open</Action>
            <Items/>
          </UiMenuItem>
          <UiMenuItem>
            <Id>2559307</Id>
            <Name>dqwdqw</Name>
            <Hint/>
            <Url/>
            <IconUrl>https://test.com</IconUrl>
            <Kind>Action</Kind>
            <Action>SendFundsToTelepayContractorProfile</Action>
            <Items/>
          </UiMenuItem>
        </Items>
      </UiMenuItem>
@annotation.XmlRootElement(name: 'UiMenuItem')
@annotation.XmlSerializable()
class UiMenuItem {
  @annotation.XmlElement(name: 'Id')
  int id;
  @annotation.XmlElement(name: 'Name')
  String? name;
  @annotation.XmlElement(name: 'Hint')
  String? hint;
  @annotation.XmlElement(name: 'Url')
  String? url;
  @annotation.XmlElement(name: 'IconUrl')
  String? iconUrl;
  @annotation.XmlElement(name: 'Kind')
  String kind;
  @annotation.XmlElement(name: 'Action')
  String action;
  @annotation.XmlElement(name: 'Items')
  List<UiMenuItem>? items;

  UiMenuItem({
    required this.id,
    required this.name,
    required this.hint,
    required this.url,
    required this.iconUrl,
    required this.kind,
    required this.action,
    required this.items,
  });

  factory UiMenuItem.fromXmlElement(XmlElement element) => _$UiMenuItemFromXmlElement(element);

  void buildXmlChildren(
    XmlBuilder builder, {
    Map<String, String> namespaces = const {},
  }) =>
      _$UiMenuItemBuildXmlChildren(
        this,
        builder,
        namespaces: namespaces,
      );

  void buildXmlElement(
    XmlBuilder builder, {
    Map<String, String> namespaces = const {},
  }) =>
      _$UiMenuItemBuildXmlElement(
        this,
        builder,
        namespaces: namespaces,
      );

  List<XmlAttribute> toXmlAttributes({
    Map<String, String?> namespaces = const {},
  }) =>
      _$UiMenuItemToXmlAttributes(
        this,
        namespaces: namespaces,
      );

  List<XmlNode> toXmlChildren({
    Map<String, String?> namespaces = const {},
  }) =>
      _$UiMenuItemToXmlChildren(
        this,
        namespaces: namespaces,
      );

  XmlElement toXmlElement({
    Map<String, String?> namespaces = const {},
  }) =>
      _$UiMenuItemToXmlElement(
        this,
        namespaces: namespaces,
      );
}

So, I get from element: < Items / >" List of one element :

id: null,
name: null,
hint: null,
url: null,
action: null,
kind: null,
items: null

Expected behavior
get items: null or better get empty List, like a items: []

Deserialization of enum iterables is broken due to duplicate variables

Describe the bug
The generated code is unable to handle enum lists, as multiple methods use e, overshadowing each other.

Current behavior
Consider the following code:

@xml.XmlEnum()
enum AccessType {
  @xml.XmlValue('SiteA')
  siteA,
  @xml.XmlValue('SiteBeta')
  siteB;
}

@xml.XmlSerializable(createMixin: true)
@xml.XmlRootElement(name: 'Permissions')
class Permissions with _$PermissionsXmlSerializableMixin {
  @xml.XmlElement(name: 'Access')
  final List<AccessType>? accessTypes;

  const Permissions({
    required this.accessTypes,
  });

  factory Permissions.fromXmlElement(XmlElement element) =>
      _$PermissionsFromXmlElement(element);
}

The generator will generate the following snippet for the _$PermissionsFromXmlElement method:

Permissions _$PermissionsFromXmlElement(XmlElement element) {
  final accessTypes = element
      .getElements('Access')
      ?.map((e) => e.getText())
      .whereType<String>();
  return Permissions(
      accessTypes: accessTypes
          ?.map((e) => _$AccessTypeEnumMap.entries // HERE: e is defined  
              .singleWhere((e) => e.value == e, // HERE: e is defined again 
                  orElse: () => throw ArgumentError(
                      '`$e` is not one of the supported values: ${_$AccessTypeEnumMap.values.join(', ')}'))
              .key)
          .toList());
}

As you can see, e i used both in map and singleWhere, which leads to the second always being false (as e.value == e is obviously never true).

Expected behavior
It should work correctly and thus use two different variables. Recommendation: Use long names like element and enumEntry. Or even better generated names like accessTypesElement and accessTypeEnumEntry.

Add support for serializing additional types

Is your feature request related to a problem? Please describe.
This package currently only supports serializing String types and any custom types that are annotated with XmlSerializable().

Describe the solution you'd like
As a developer I would like this package to serialize types such as int and bool so that I do not have to implement that logic.

Describe alternatives you've considered
The current workaround is for the consuming application to implement logic to convert String types to other common types.

Additional context
This change will involve refactoring the XmlSerializableGenerator and creating SerializerGenerators that abstract the logic.

Include beginner friendly docs

Unless I mis-read your docs, nowhere does it state step by step how a beginner would use your project. You mention builders without explaining how to run a builder. Maybe you could write something like:

add build_runner to your dev_dependencies, then run dart run build_runner build to generate the files.

In the readme, you show an example piece of code and the resulting generated file. It'd be nice to start by showing the XML you're trying to model.

I think resolving #31 would go a long way to make it beginner friendly.

Reduce boilerplate code

Is your feature request related to a problem? Please describe.
There are always boilerplate code for buildXmlChildren, buildXmlElement, toXmlAttributes, toXmlChildren and toXmlElement.

Describe the solution you'd like
Put generated methods into private class and create mixin which will substitute these methods.
Proposed API will looks like:

import 'package:xml/xml.dart';
import 'package:xml_annotation/xml_annotation.dart' as annotation;

part 'example.g.dart';


@annotation.XmlRootElement(name: 'person')
@annotation.XmlSerializable()
class Person with XMLParserMixin<Person, _$PersonParser> {
  @annotation.XmlElement(name: 'name')
  final String? name;

  Person({
    this.name,
  });

  static const _personParser = _$PersonParser();

  @override
  _$PersonParser get _parser => _personParser;

  factory Person.fromXmlElement(XmlElement element) =>
    _personParser.fromXmlElement(element);
}

Describe alternatives you've considered
I see no better solutions for now.

Additional context
Here's an example implementation I came up with:

/// File code
class Person with XMLParserMixin<Person, _$PersonParser> {
  static const _personParser = _$PersonParser();

  @override
  _$PersonParser get _parser => _personParser;
  
  String? name;

  Person({
    this.name,
  });

  factory Person.fromXmlElement(XmlElement element) =>
    _personParser.fromXmlElement(element);
  
  // Other methods are implemented via mixin
}


/// Auxiliary code
abstract class XMLSerializableParser<T> {
  const XMLSerializableParser();

  T fromXmlElement(XmlElement element);
  void buildXmlChildren(
    T instance,
    XmlBuilder builder, {
    Map<String, String> namespaces = const {},
  });
  // and so on...
}

mixin XMLParserMixin<T, Parser extends XMLSerializableParser<T>> {
  Parser get _parser;

  void buildXmlChildren(
    XmlBuilder builder, {
    Map<String, String> namespaces = const {},
  }) =>
    _parser.buildXmlChildren(
      this as T,
      builder,
      namespaces: namespaces,
    );
  // and so on...
}


/// Generated code
class _$PersonParser extends XMLSerializableParser<Person> {
  const _$PersonParser() : super();

  @override
  Person fromXmlElement(XmlElement element) {
    print('called fromXmlElement of _\$PersonParser');
    return Person();
  }

  @override
  void buildXmlChildren(
    Person instance,
    XmlBuilder builder, {
    Map<String, String> namespaces = const {},
  }) {
    print('called buildXmlChildren of _\$PersonParser');
  }
}


/// Test
void main(List<String> arguments) async {
  final person = Person.fromXmlElement(XmlElement());
  person.buildXmlChildren(XmlBuilder());
}

Add support for serializing elements using InnerXml

If I use the XML like:

<?xml version="1.0"?>
    <bookshelf>
      <book>
        <title lang="English"><RandomUnknownTag>XML Pocket Reference</RandomUnknownTag ></title>
        <author>Simon St. Laurent</author>
        <author>Michael James Fitzgerald</author>
        <price></price>
      </book>
      <book>
        <title lang="English">HTML and XHTML Pocket Reference</title>
        <author>Jennifer Niederst Robbins</author>
        <price></price>
      </book>
    </bookshelf>

Will it be possible to have an @ InnerXml() tag in future request.

which will help to set the value of of text in title class to <RandomUnknownTag>XML Pocket Reference</RandomUnknownTag> as an innerXml String.

and back to <RandomUnknownTag>XML Pocket Reference</RandomUnknownTag> when generating XML.

If it is already possible and I'm missing this, Please do let me know how could I achieve this.

Upgrade the version constraint of analyzer

The lowest version of analyzer currently supported is 2.0.0 and the highest version is 4.7.0.

There have been a number of deprecations in this version range such as DartType.element.

I propose upgrading the version constraint of analyzer to >=4.6.0 <6.0.0 in this package.

This will allow a seamless migration internally from DartType.element to DartType.element2.

Unfortunately this does mean that support for all versions lower than 4.6.0 will be removed.

ignore attributes

I use the library now for a few months and it really works great.

Now, for the first time, I had a situation, where I needed to add a property to the class, which should not be used during serialization process. I have seen this is possible for JSON, but it seems to be not integrated to the xml serializable library yet.

Example:

@annotation.XmlRootElement(name: 'IMAGE')
@annotation.XmlSerializable()
class BlogEntryAssetImage {
@annotation.XmlElement(name: 'DATA')
BlogEntryAssetImageData? blogEntryAssetImageData;

BlogEntryAssetImage({
this.blogEntryAssetImageData,
this.image,
});

//also create an image provider for later use in the UI
@annotation.XmlElement(ignore: true)
ImageProvider? image;

factory BlogEntryAssetImage.fromXmlElement(XmlElement element) =>
_$BlogEntryAssetImageFromXmlElement(element);
...

the ImageProvider property is used later (when the XML is read) to create an instance of ImageProvider which represents the image stored within the blogEntryAssetImageData text (encoded as base64). It should just be ignored when running flutter pub run build_runner build - in fact, it works fine when the property is added after running flutter pub run build_runner build, but next time it is called, I get the message

image does not have a supported annotation. Add an annotation of the form @XmlAttribute(), @XmlElement(), or @XmlText() to image.: Instance of 'FieldElementImpl'

Is there already any way to add properties which can be ignored or is this feature not implemented at all?

Thank you for your help,
regards
Robert

Reduce boilerplate code

I tried writing the simplest class:

import 'package:xml_annotation/xml_annotation.dart' as annotation;

part 'character.g.dart';

@annotation.XmlRootElement(name: 'character')
@annotation.XmlSerializable()
class Character {}

And ran the generator. It generated the character.g.dart class but it had a compile error:

The method 'buildXmlChildren' isn't defined for the type 'Character'. Try correcting the name to the name of an existing method, or defining a method named 'buildXmlChildren'.

It would be nice to handle the simplest use cases to allow us to write even less boilerplate code. Judging from your readme example, i would still need to implement a few more methods for it to compile.

Add support for custom converters

Is your feature request related to a problem? Please describe.
As a developer I would like to provide an XmlConverter to control the serialization of data types.

Describe the solution you'd like
I would like a solution that is similar to the JsonConverter from the json_annotation package.

Additional context
https://github.com/google/json_serializable.dart/blob/master/json_annotation/lib/src/json_converter.dart
https://github.com/google/json_serializable.dart/blob/master/example/lib/json_converter_example.dart

Enum-Serializtion does not work anymore if split between multiple files

Describe the bug
I have an XmlEnum in one file and a XmlSerializable in another file. Because the enum map is private, it cannot be used in the second file.

Current behavior
Steps to reproduce the behavior:

  1. Create a.dart with an XmlEnum
  2. Create b.dart with an XmlSerializable
  3. Run the build runner
  4. See error

Expected behavior
Enums should be serializable even when used across multiple files

Dynamically choose names for XML-elements

Current Structure

I have a class named Student, which should have a name and book attribute.

The book attribute can correspond to different implementations. There are several classes that extend AbstractBook.

Student class:

@annotation.XmlRootElement(name: 'Student')
@annotation.XmlSerializable()
class Student {
  @annotation.XmlAttribute(name: 'name')
  String name;

  @annotation.XmlElement(name: 'Book') 
  AbstractBook book;

  Student({
    required this.name,
    required this.book,
  });

  factory Student.fromXmlElement(XmlElement element) =>
      _$StudentFromXmlElement(element);

  void buildXmlChildren(
      XmlBuilder builder, {
        Map<String, String> namespaces = const {},
      }) =>
      _$StudentBuildXmlChildren(
        this,
        builder,
        namespaces: namespaces,
      );

  void buildXmlElement(
      XmlBuilder builder, {
        Map<String, String> namespaces = const {},
      }) =>
      _$StudentBuildXmlElement(
        this,
        builder,
        namespaces: namespaces,
      );

  List<XmlAttribute> toXmlAttributes({
    Map<String, String?> namespaces = const {},
  }) =>
      _$StudentToXmlAttributes(
        this,
        namespaces: namespaces,
      );

  List<XmlNode> toXmlChildren({
    Map<String, String?> namespaces = const {},
  }) =>
      _$StudentToXmlChildren(
        this,
        namespaces: namespaces,
      );

  XmlElement toXmlElement({
    Map<String, String?> namespaces = const {},
  }) =>
      _$StudentToXmlElement(
        this,
        namespaces: namespaces,
      );
}

Question

Is it possible at the moment to easily and dynamically choose the name of the attribute inside the XML?

For example, the name should be "Math" if the object for AbstractBook is MathBook or "Chemistry" if the object is ChemistryBook.

upgrade analyzer

Hello,

Could you upgrade the analyzer to ^3.0.0 as it makes a conflict with Freezed Library

Thanks

Enum and other types

Is your feature request related to a problem? Please describe.
I'd like to be able to parse enums (for example S3 Object#ChecksumAlgorithm is a clear enum).
Also it would be nice if it would be possible to parse arbitrary type if it has factory constructor parse(String string)/static function tryParse(String string) or factory constructor fromXmlElement(XmlElement element).

Describe the solution you'd like
Test if required type has has factory constructor parse(String input) or factory constructor fromXmlElement(XmlElement element) and use it.

Describe alternatives you've considered
Don't have any yet.

Additional context
Enum from link could be like this:

enum ChecksumAlgorithm {
  crc32('CRC32'),
  crc32c('CRC32C'),
  sha1('SHA1'),
  sha256('SHA256');

  const ChecksumAlgorithm(this.value);

  factory ChecksumAlgorithm.fromXmlElement(XmlElement element) =>
    values.firstWhere((_enum) => _enum.value == element.text);

  final String value;
}

Nullable fields annotated with XmlCDATA results in incorrectly generated source code

Describe the bug
After adding an XmlCDATA annotation to a nullable field, a source code with compilation error is generated.

Current behavior
Add XmlCDATA annotation to a nullable field, e.g.:

  @annotation.XmlCDATA()
  @annotation.XmlElement(name: 'DESC')
  final String? description;

Generated source code is incorrect:

  final descriptionConstructed =
      descriptionSerialized != null ? XmlCDATA(descriptionSerialized) : null;
  children.add(descriptionConstructed); // The argument type 'XmlCDATA?' can't be assigned to the parameter type 'XmlNode'.

Expected behavior
Code should compile ;)

I'm not sure, but it may be as simple as:

  final descriptionConstructed =
      descriptionSerialized != null ? XmlCDATA(descriptionSerialized) : null;
  if (descriptionConstructed != null) {
    children.add(descriptionConstructed);
  }

Asynchronous deserialization with Streams

The xml lib has very good Stream support.
It would be great if the generated code would also make use of that.

This would probably improve performance as the data could be deserialized asynchronously as it arrives.

feat: Add support for XML base64Binary type

Is your feature request related to a problem? Please describe.

To be able to map XML type "base64Binary", to Dart Uint8List and vice-versa.

Describe the solution you'd like
Support "base64Binary" to be mapped to / from Uint8List.

Describe alternatives you've considered
Working with plain strings and mapping to Dart type when needed.

How to describe a self closing optional element?

I have the following structure:

<resourcetype>
  <collection/>
</resourcetype>

In this case collection never has any value and I only want to know if the element is present or not.
I can't figure out how I have to build my serializables to make this work.

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.