Skip to content

Commit 7d55af3

Browse files
committed
Xml support for C#
Signed-off-by: Clemens Vasters <clemens@vasters.com>
1 parent 82fddde commit 7d55af3

12 files changed

+331
-130
lines changed

avrotize/avrotize.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,18 @@ def create_subparsers(subparsers, commands):
3737
if arg['type'] == 'bool':
3838
kwargs['action'] = 'store_true'
3939
del kwargs['type']
40-
carg = cmd_parser.add_argument(arg['name'], **kwargs)
40+
argname = arg['name']
41+
if '_' in argname:
42+
argname2 = argname.replace('_', '-')
43+
carg = cmd_parser.add_argument(argname, argname2, **kwargs)
44+
else:
45+
carg = cmd_parser.add_argument(arg['name'], **kwargs)
4146
else:
42-
carg = cmd_parser.add_argument(arg['name'], **kwargs)
47+
if '_' in arg['name']:
48+
argname2 = arg['name'].replace('_', '-')
49+
carg = cmd_parser.add_argument(arg['name'], argname2, **kwargs)
50+
else:
51+
carg = cmd_parser.add_argument(arg['name'], **kwargs)
4352
carg.required = arg.get('required', True)
4453

4554
def dynamic_import(module, func):

avrotize/avrotocsharp.py

+160-59
Large diffs are not rendered by default.

avrotize/avrotocsharp/class_test.cs.jinja

+12-2
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,24 @@ public class {{ test_class_name }}
5656
{%- if avro_annotation %}
5757
/// <summary> Testing Avro serializer </summary>
5858
[Test]
59-
public void Test_ToByteArray_FromData()
59+
public void Test_ToByteArray_FromData_Avro()
6060
{
6161
var mediaType = "application/vnd.apache.avro+avro";
6262
var bytes = _instance.ToByteArray(mediaType);
6363
var newInstance = {{ class_base_name }}.FromData(bytes, mediaType);
6464
_instance.Should().BeEquivalentTo(newInstance);
6565
}
66-
66+
{%- endif %}
67+
{%- if system_xml_annotation %}
68+
/// <summary> Testing XML serializer </summary>
69+
[Test]
70+
public void Test_ToByteArray_FromData_Xml()
71+
{
72+
var mediaType = "application/xml";
73+
var bytes = _instance.ToByteArray(mediaType);
74+
var newInstance = {{ class_base_name }}.FromData(bytes, mediaType);
75+
_instance.Should().BeEquivalentTo(newInstance);
76+
}
6777
{%- endif %}
6878
}
6979
{% endfilter %}

avrotize/avrotocsharp/dataclass_core.jinja

+57-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation %}
1+
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation or system_xml_annotation %}
22
/// <summary>
33
/// Creates an object from the data
44
/// </summary>
@@ -11,7 +11,7 @@
1111
if ( data is {{ class_name }}) return ({{ class_name }})data;
1212
if ( contentTypeString == null ) contentTypeString = System.Net.Mime.MediaTypeNames.Application.Octet;
1313
var contentType = new System.Net.Mime.ContentType(contentTypeString);
14-
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation %}
14+
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation or system_xml_annotation %}
1515
if ( contentType.MediaType.EndsWith("+gzip"))
1616
{
1717
var stream = data switch
@@ -87,10 +87,37 @@
8787
return ((System.BinaryData)data).ToObjectFromJson<{{ class_name }}>();
8888
}
8989
}
90+
{%- endif %}
91+
{%- if system_xml_annotation %}
92+
if ( contentType.MediaType.StartsWith(System.Net.Mime.MediaTypeNames.Text.Xml) || contentType.MediaType.StartsWith(System.Net.Mime.MediaTypeNames.Application.Xml) || contentType.MediaType.EndsWith("+xml"))
93+
{
94+
var serializer = new System.Xml.Serialization.XmlSerializer(typeof({{ class_name }}));
95+
if (data is string)
96+
{
97+
using (var reader = new System.IO.StringReader((string)data))
98+
{
99+
return ({{ class_name }}?)serializer.Deserialize(reader);
100+
}
101+
}
102+
else if (data is System.IO.Stream)
103+
{
104+
return ({{ class_name }}?)serializer.Deserialize((System.IO.Stream)data);
105+
}
106+
else if (data is System.BinaryData)
107+
{
108+
var memoryStream = new System.IO.MemoryStream(((System.BinaryData)data).ToArray());
109+
return ({{ class_name }}?)serializer.Deserialize(memoryStream);
110+
}
111+
else if (data is byte[])
112+
{
113+
var memoryStream = new System.IO.MemoryStream((byte[])data);
114+
return ({{ class_name }}?)serializer.Deserialize(memoryStream);
115+
}
116+
}
90117
{%- endif %}
91118
throw new System.NotSupportedException($"Unsupported media type {contentType.MediaType}");
92119
}
93-
{%-endif %}
120+
{%- endif %}
94121

95122
{%- if avro_annotation %}
96123
private class SpecificDatumWriter : global::Avro.Specific.SpecificDatumWriter<{{ class_name }}>
@@ -101,15 +128,23 @@
101128

102129
protected override WriteItem ResolveEnum(global::Avro.EnumSchema es)
103130
{
104-
return base.ResolveEnum(global::Avro.EnumSchema.Create(es.Name, es.Symbols, GetType().Assembly.GetName().Name+"."+es.Namespace, null, null, es.Documentation, es.Default));
131+
var enumType = GetType().Assembly.GetType(GetType().Assembly.GetName().Name+"."+es.Namespace + "." + es.Name, false, true);
132+
if (enumType != null)
133+
{
134+
return base.ResolveEnum(global::Avro.EnumSchema.Create(enumType.Name, es.Symbols, enumType.Namespace, null, null, es.Documentation, es.Default));
135+
}
136+
else
137+
{
138+
return base.ResolveEnum(es);
139+
}
105140
}
106141
}
107142
{%- endif %}
108143

109144
{%- if avro_annotation %}
110145
{%- endif%}
111146

112-
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation %}
147+
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation or system_xml_annotation %}
113148
/// <summary>
114149
/// Converts the object to a byte array
115150
/// </summary>
@@ -151,7 +186,22 @@
151186
result = System.Text.Encoding.GetEncoding(contentType.CharSet??"utf-8").GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(this));
152187
}
153188
{%- endif %}
154-
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation %}
189+
{%- if system_xml_annotation %}
190+
if (contentType.MediaType.StartsWith(System.Net.Mime.MediaTypeNames.Text.Xml) || contentType.MediaType.StartsWith(System.Net.Mime.MediaTypeNames.Application.Xml) || contentType.MediaType.EndsWith("+xml"))
191+
{
192+
var serializer = new System.Xml.Serialization.XmlSerializer(typeof({{ class_name }}));
193+
using (var stream = new System.IO.MemoryStream())
194+
{
195+
using (var writer = new System.IO.StreamWriter(stream))
196+
{
197+
serializer.Serialize(writer, this);
198+
writer.Flush();
199+
result = stream.ToArray();
200+
}
201+
}
202+
}
203+
{%- endif %}
204+
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation or system_xml_annotation %}
155205
if (result != null && contentType.MediaType.EndsWith("+gzip"))
156206
{
157207
var stream = new System.IO.MemoryStream();
@@ -166,7 +216,7 @@
166216
}
167217
{%- endif %}
168218

169-
{%- if system_text_json_annotation %}
219+
{%- if system_text_json_annotation or newtonsoft_json_annotation %}
170220
/// <summary>
171221
/// Checks if the JSON element matches the schema
172222
/// </summary>

avrotize/avrotocsharp/project.csproj.jinja

+6
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@
55
<GenerateDocumentationFile>true</GenerateDocumentationFile>
66
</PropertyGroup>
77
<ItemGroup>
8+
{%- if avro_annotation %}
89
<PackageReference Include="Apache.Avro" Version="1.11.3" />
10+
{%- endif %}
11+
{%- if newtonsoft_json_annotation %}
912
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
13+
{%- endif %}
14+
{%- if system_text_json_annotation %}
1015
<PackageReference Include="System.Text.Json" Version="8.0.5" />
16+
{%- endif %}
1117
<PackageReference Include="System.Memory.Data" Version="8.0.0" />
1218
</ItemGroup>
1319
<ItemGroup>

avrotize/avrotots/class_core.ts.jinja

+3
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ export class {{ class_name }} {
107107
throw new Error(`Unsupported media type: ${contentTypeString}`);
108108
}
109109

110+
111+
{%- if typed_json_annotation %}
110112
public static isJsonMatch(element: any): boolean {
111113
{%- if fields|length == 0 %}
112114
return true;
@@ -120,4 +122,5 @@ export class {{ class_name }} {
120122
{%- endif %}
121123
}
122124
{%- endif %}
125+
{%- endif %}
123126
}

avrotize/avrotots/enum_core.ts.jinja

+2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ export class {{ enum_name }}Utils {
3838
}
3939
}
4040

41+
{%- if typed_json_annotation %}
4142
static isJsonMatch(value: string): boolean {
4243
return Object.values({{ enum_name }}).includes(value as {{ enum_name }});
4344
}
45+
{%- endif %}
4446
}

avrotize/commands.json

+8
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,7 @@
899899
"avro_annotation": "args.avro_annotation",
900900
"system_text_json_annotation": "args.system_text_json_annotation",
901901
"newtonsoft_json_annotation": "args.newtonsoft_json_annotation",
902+
"system_xml_annotation": "args.system_xml_annotation",
902903
"pascal_properties": "args.pascal_properties",
903904
"base_namespace": "args.namespace"
904905
}
@@ -944,6 +945,13 @@
944945
"default": false,
945946
"required": false
946947
},
948+
{
949+
"name": "--system-xml-annotation",
950+
"type": "bool",
951+
"help": "Use System.Xml annotations",
952+
"default": false,
953+
"required": false
954+
},
947955
{
948956
"name": "--newtonsoft-json-annotation",
949957
"type": "bool",

avrotize/xsdtoavro.py

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def __init__(self) -> None:
2222
""" Initialize the class. """
2323
self.simple_type_map: Dict[str, str | dict] = {}
2424
self.avro_namespace = ''
25+
self.xml_namespace = ''
2526

2627
def xsd_targetnamespace_to_avro_namespace(self, targetnamespace: str) -> str:
2728
"""Convert a XSD namespace to Avro Namespace."""
@@ -303,6 +304,7 @@ def process_top_level_element(self, element: ET.Element, namespaces: dict):
303304
'type': 'record',
304305
'name': 'Root',
305306
'namespace': self.avro_namespace,
307+
'xmlns': self.xml_namespace,
306308
'fields': []
307309
}
308310
annotation = element.find(f'{{{XSD_NAMESPACE}}}annotation', namespaces)
@@ -349,6 +351,7 @@ def xsd_to_avro(self, xsd_path: str, code_namespace: str | None = None):
349351
target_namespace = root.get('targetNamespace')
350352
if target_namespace is None:
351353
raise ValueError('targetNamespace not found')
354+
self.xml_namespace = target_namespace
352355
if not code_namespace:
353356
self.avro_namespace = self.xsd_targetnamespace_to_avro_namespace(target_namespace)
354357
else:

0 commit comments

Comments
 (0)