Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InnerXml #53

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions xml_annotation/lib/src/annotations/inner_xml.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/// An annotation used to specify how a innerxml is serialized.
class InnerXml {
const InnerXml();
}
9 changes: 8 additions & 1 deletion xml_annotation/lib/src/extensions/xml_node_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ extension XmlNodeExtensions on XmlNode {
@Deprecated(
'Use findAllElements(name, namespace: namespace).map((e) => e.getCDATA()).whereType<String>() instead.',
)
Iterable<String> findAllElementsCDATA(String name, {String? namespace}) sync* {
Iterable<String> findAllElementsCDATA(String name,
{String? namespace}) sync* {
for (final element in findAllElements(name, namespace: namespace)) {
final cdata = element.getCDATA();
if (cdata != null) yield cdata;
Expand Down Expand Up @@ -78,4 +79,10 @@ extension XmlNodeExtensions on XmlNode {
final texts = children.whereType<XmlText>().map((e) => e.value);
return texts.isNotEmpty ? texts.join() : null;
}

/// Gets the text or `null` if there are no `InnerXml` children.
String? getInnerXml() {
final texts = children.map((e) => e.toXmlString());
return texts.isNotEmpty ? texts.join() : null;
}
}
1 change: 1 addition & 0 deletions xml_annotation/lib/xml_annotation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export 'package:xml_annotation/src/annotations/xml_enum.dart';
export 'package:xml_annotation/src/annotations/xml_root_element.dart';
export 'package:xml_annotation/src/annotations/xml_serializable.dart';
export 'package:xml_annotation/src/annotations/xml_text.dart';
export 'package:xml_annotation/src/annotations/inner_xml.dart';
export 'package:xml_annotation/src/annotations/xml_value.dart';
export 'package:xml_annotation/src/extensions/namespace_map_extensions.dart';
export 'package:xml_annotation/src/extensions/xml_node_extensions.dart';
6 changes: 3 additions & 3 deletions xml_serializable/example/xml_serializable_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ void main() {
'''<?xml version="1.0"?>
<bookshelf>
<book>
<title lang="English">XML Pocket Reference</title>
<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>
<title lang="English"><Thomas>HTML and XHTML Pocket Reference</Thomas></title>
<author>Jennifer Niederst Robbins</author>
<price></price>
</book>
Expand Down Expand Up @@ -181,7 +181,7 @@ class Title {
@annotation.XmlAttribute(name: 'lang')
Language? language;

@annotation.XmlText()
@annotation.InnerXml()
String? text;

Title({
Expand Down
10 changes: 6 additions & 4 deletions xml_serializable/example/xml_serializable_example.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'builder_generator.dart';

class InnerXmlBuilderGenerator extends BuilderGenerator {
/// If `false` (the default) then the type does not represent a nullable type.
final bool _isNullable;

const InnerXmlBuilderGenerator({bool isNullable = false})
: _isNullable = isNullable;

@override
String generateBuilder(String expression, {String builder = 'builder'}) {
final buffer = StringBuffer();

if (_isNullable) {
buffer.write('if ($expression != null) { ');
}

buffer.write('$builder.xml($expression);');

if (_isNullable) {
buffer.write(' }');
}

return buffer.toString();
}
}

class NullableInnerXmlBuilderGenerator extends InnerXmlBuilderGenerator {
const NullableInnerXmlBuilderGenerator() : super(isNullable: true);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'constructor_generator.dart';

class InnerXmlConstructorGenerator extends ConstructorGenerator {
/// If `false` (the default) then the type does not represent a nullable type.
final bool _isNullable;

const InnerXmlConstructorGenerator({bool isNullable = false})
: _isNullable = isNullable;

@override
String generateConstructor(String expression) {
final buffer = StringBuffer();

if (_isNullable) {
buffer.write('$expression != null ? ');
}

buffer.write('XmlDocument.parse($expression).rootElement');

if (_isNullable) {
buffer.write(' : null');
}

return buffer.toString();
}
}

class NullableInnerXmlConstructorGenerator extends InnerXmlConstructorGenerator {
const NullableInnerXmlConstructorGenerator() : super(isNullable: true);
}
17 changes: 17 additions & 0 deletions xml_serializable/lib/src/extensions/dart_object_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,23 @@ extension DartObjectExtensions on DartObject {
return null;
}

/// Returns an [InnerXml] corresponding to the value of the object being represented or `null` if this object is not of type [InnerXml].
InnerXml? toInnerXmlValue() {
final type = this.type;

if (type is InterfaceType) {
final element = type.element;

if (element is ClassElement &&
element.library.identifier.startsWith('package:xml_annotation') &&
element.name == 'InnerXml') {
return InnerXml();
}
}

return null;
}

/// Returns an [XmlValue] corresponding to the value of the object being represented or `null` if this object is not of type [XmlValue].
XmlValue? toXmlValueValue() {
final type = this.type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,13 @@ extension ElementAnnotationExtensions on ElementAnnotation {
element.library.identifier.startsWith('package:xml_annotation') &&
element.enclosingElement.name == 'XmlValue';
}

/// Returns `true` if this annotation marks the associated member as being serializable as an `InnerXml`.
bool get isInnerXml {
final element = this.element;

return element is ConstructorElement &&
element.library.identifier.startsWith('package:xml_annotation') &&
element.enclosingElement.name == 'InnerXml';
}
}
4 changes: 4 additions & 0 deletions xml_serializable/lib/src/extensions/element_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,8 @@ extension ElementExtensions on Element {

/// Returns `true` if this element has an annotation of the form `@XmlValue()`.
bool get hasXmlValue => metadata.any((e) => e.isXmlValue);


/// Returns `true` if this element has an annotation of the form `@InnerXml()`.
bool get hasInnerXml => metadata.any((e) => e.isInnerXml);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:xml_serializable/src/builder_generators/inner_xml_builder_generator.dart';

import '../builder_generators/builder_generator.dart';
import '../builder_generators/iterable_builder_generator.dart';
Expand Down Expand Up @@ -69,6 +70,16 @@ BuilderGenerator builderGeneratorFactory(Element element) {
'`@XmlText()` can only be used on fields.',
);
}
} else if (element.hasInnerXml) {
if (element is FieldElement) {
return InnerXmlBuilderGenerator(isNullable: element.type.isNullable);
} else {
throw ArgumentError.value(
element,
'element',
'`@InnerXml()` can only be used on fields.',
);
}
}

throw ArgumentError.value(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:xml_serializable/src/constructor_generators/inner_xml_constructor_generator.dart';

import '../constructor_generators/constructor_generator.dart';
import '../constructor_generators/iterable_constructor_generator.dart';
Expand Down Expand Up @@ -71,6 +72,16 @@ ConstructorGenerator constructorGeneratorFactory(Element element) {
'`@XmlText()` can only be used on fields.',
);
}
} else if (element.hasInnerXml) {
if (element is FieldElement) {
return InnerXmlConstructorGenerator(isNullable: element.type.isNullable);
} else {
throw ArgumentError.value(
element,
'element',
'`@InnerXml()` can only be used on fields.',
);
}
}

throw ArgumentError.value(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:xml_serializable/src/getter_generators/inner_xml_getter_generator.dart';

import '../extensions/dart_object_extensions.dart';
import '../extensions/dart_type_extensions.dart';
Expand Down Expand Up @@ -57,6 +58,16 @@ GetterGenerator getterGeneratorFactory(Element element) {
'`@XmlText()` can only be used on fields.',
);
}
} else if (element.hasInnerXml) {
if (element is FieldElement) {
return InnerXmlGetterGenerator(isNullable: element.type.isNullable);
} else {
throw ArgumentError.value(
element,
'element',
'`@InnerXml()` can only be used on fields.',
);
}
}

throw ArgumentError.value(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'getter_generator.dart';

class InnerXmlGetterGenerator extends GetterGenerator {
/// If `false` (the default) then the type does not represent a nullable type.
final bool _isNullable;

const InnerXmlGetterGenerator({bool isNullable = false})
: _isNullable = isNullable;

@override
String generateGetter(String expression) {
final buffer = StringBuffer(expression);

buffer.write('.getInnerXml()');

if (!_isNullable) {
buffer.write('!');
}

return buffer.toString();
}
}

class NullableInnerXmlGetterGenerator extends InnerXmlGetterGenerator {
const NullableInnerXmlGetterGenerator() : super(isNullable: true);
}
19 changes: 16 additions & 3 deletions xml_serializable/lib/src/xml_serializable_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ class XmlSerializableGenerator extends GeneratorForAnnotation<XmlSerializable> {
if (element.hasXmlAttribute ||
element.hasXmlCDATA ||
element.hasXmlElement ||
element.hasXmlText) {
element.hasXmlText ||
element.hasInnerXml) {
buffer.writeln(
'final ${element.name} = instance.${element.name};',
);
Expand Down Expand Up @@ -157,7 +158,8 @@ class XmlSerializableGenerator extends GeneratorForAnnotation<XmlSerializable> {
if (element.hasXmlAttribute ||
element.hasXmlCDATA ||
element.hasXmlElement ||
element.hasXmlText) {
element.hasXmlText ||
element.hasInnerXml) {
buffer.writeln(
'final ${element.name} = ${_getterGeneratorFactory(element).generateGetter('element')};',
);
Expand Down Expand Up @@ -266,7 +268,10 @@ class XmlSerializableGenerator extends GeneratorForAnnotation<XmlSerializable> {
buffer.writeln('final children = <XmlNode>[];');

for (final element in element.allFields) {
if (element.hasXmlCDATA || element.hasXmlElement || element.hasXmlText) {
if (element.hasXmlCDATA ||
element.hasXmlElement ||
element.hasXmlText ||
element.hasInnerXml) {
buffer.writeln('final ${element.name} = instance.${element.name};');

buffer.writeln(
Expand All @@ -284,8 +289,16 @@ class XmlSerializableGenerator extends GeneratorForAnnotation<XmlSerializable> {
if (element.type.isDartCoreIterable ||
element.type.isDartCoreList ||
element.type.isDartCoreSet) {
if (element.hasInnerXml) {
buffer.write(
'${element.name}Constructed.forEach((e) => e.detachParent(e.parent!));');
}
buffer.write('children.addAll(${element.name}Constructed);');
} else {
if (element.hasInnerXml) {
buffer.write(
'${element.name}Constructed.detachParent(${element.name}Constructed.parent!);');
}
buffer.write('children.add(${element.name}Constructed);');
}

Expand Down
3 changes: 2 additions & 1 deletion xml_serializable/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ dependencies:
recase: ^4.0.0
source_gen: ^1.0.0
xml: '>=5.0.0 <7.0.0'
xml_annotation: ^2.3.0
xml_annotation:
path: ../xml_annotation

dev_dependencies:
build_runner: ^2.0.0
Expand Down
Loading