1using System.Globalization;
17 public class XmlDatabaseExport(XmlWriter Output, int BinaryDataSizeLimit) :
IDatabaseExportFilter, IDisposable
19 private readonly XmlWriter output = Output;
20 private readonly
int binaryDataSizeLimit = BinaryDataSizeLimit;
21 private bool disposeWriter;
29 public XmlDatabaseExport(StringBuilder Output,
bool Indent,
int BinaryDataSizeLimit)
30 : this(XmlWriter.Create(Output,
XML.WriterSettings(Indent, true)), BinaryDataSizeLimit)
32 this.disposeWriter =
true;
39 public Task<bool> StartDatabase()
41 this.output.WriteStartElement(
"Database");
42 return Task.FromResult(
true);
49 public Task<bool> EndDatabase()
51 this.output.WriteEndElement();
52 return Task.FromResult(
true);
60 public bool CanExportCollection(
string CollectionName)
70 public Task<bool> StartCollection(
string CollectionName)
72 this.output.WriteStartElement(
"Collection");
73 this.output.WriteAttributeString(
"name", CollectionName);
74 return Task.FromResult(
true);
81 public Task<bool> EndCollection()
83 this.output.WriteEndElement();
84 return Task.FromResult(
true);
91 public Task<bool> StartIndex()
93 this.output.WriteStartElement(
"Index");
94 return Task.FromResult(
true);
103 public Task<bool> ReportIndexField(
string FieldName,
bool Ascending)
105 this.output.WriteStartElement(
"Index");
106 this.output.WriteAttributeString(
"field", FieldName);
108 this.output.WriteEndElement();
109 return Task.FromResult(
true);
116 public Task<bool> EndIndex()
118 this.output.WriteEndElement();
119 return Task.FromResult(
true);
132 if (!Object.
TryGetFieldValue(
"Key", out
object Value) || Value is not
string Key)
135 if (Key.StartsWith(ServiceRef.XmppService.ContractsClient.ContractKeySettingsPrefix, StringComparison.Ordinal) ||
136 Key.StartsWith(ServiceRef.XmppService.ContractsClient.KeySettingsPrefix, StringComparison.Ordinal))
150 public Task<string> StartObject(
string ObjectId,
string TypeName)
152 this.output.WriteStartElement(
"Obj");
153 this.output.WriteAttributeString(
"id", ObjectId);
154 this.output.WriteAttributeString(
"type", TypeName);
155 return Task.FromResult(ObjectId);
164 public async Task<bool> ReportProperty(
string? PropertyName,
object? PropertyValue)
166 if (PropertyValue is
null)
168 this.output.WriteStartElement(
"Null");
170 if (PropertyName is not
null)
171 this.output.WriteAttributeString(
"n", PropertyName);
173 this.output.WriteEndElement();
175 else if (PropertyValue is Enum)
177 this.output.WriteStartElement(
"En");
179 if (PropertyName is not
null)
180 this.output.WriteAttributeString(
"n", PropertyName);
182 this.output.WriteAttributeString(
"v",
string.Empty, PropertyValue.ToString());
183 this.output.WriteEndElement();
187 switch (Type.GetTypeCode(PropertyValue.GetType()))
189 case TypeCode.Boolean:
190 this.output.WriteStartElement(
"Bl");
192 if (PropertyName is not
null)
193 this.output.WriteAttributeString(
"n", PropertyName);
195 this.output.WriteAttributeString(
"v",
string.Empty,
CommonTypes.
Encode((
bool)PropertyValue));
196 this.output.WriteEndElement();
200 this.output.WriteStartElement(
"B");
202 if (PropertyName is not
null)
203 this.output.WriteAttributeString(
"n", PropertyName);
205 this.output.WriteAttributeString(
"v",
string.Empty, PropertyValue.ToString());
206 this.output.WriteEndElement();
210 this.output.WriteStartElement(
"Ch");
212 if (PropertyName is not
null)
213 this.output.WriteAttributeString(
"n", PropertyName);
215 this.output.WriteAttributeString(
"v",
string.Empty, PropertyValue.ToString());
216 this.output.WriteEndElement();
219 case TypeCode.DateTime:
220 this.output.WriteStartElement(
"DT");
222 if (PropertyName is not
null)
223 this.output.WriteAttributeString(
"n", PropertyName);
225 this.output.WriteAttributeString(
"v",
string.Empty,
XML.
Encode((DateTime)PropertyValue));
226 this.output.WriteEndElement();
229 case TypeCode.Decimal:
230 this.output.WriteStartElement(
"Dc");
232 if (PropertyName is not
null)
233 this.output.WriteAttributeString(
"n", PropertyName);
235 this.output.WriteAttributeString(
"v",
string.Empty,
CommonTypes.
Encode((decimal)PropertyValue));
236 this.output.WriteEndElement();
239 case TypeCode.Double:
240 this.output.WriteStartElement(
"Db");
242 if (PropertyName is not
null)
243 this.output.WriteAttributeString(
"n", PropertyName);
245 this.output.WriteAttributeString(
"v",
string.Empty,
CommonTypes.
Encode((
double)PropertyValue));
246 this.output.WriteEndElement();
250 this.output.WriteStartElement(
"I2");
252 if (PropertyName is not
null)
253 this.output.WriteAttributeString(
"n", PropertyName);
255 this.output.WriteAttributeString(
"v",
string.Empty, PropertyValue.ToString());
256 this.output.WriteEndElement();
260 this.output.WriteStartElement(
"I4");
262 if (PropertyName is not
null)
263 this.output.WriteAttributeString(
"n", PropertyName);
265 this.output.WriteAttributeString(
"v",
string.Empty, PropertyValue.ToString());
266 this.output.WriteEndElement();
270 this.output.WriteStartElement(
"I8");
272 if (PropertyName is not
null)
273 this.output.WriteAttributeString(
"n", PropertyName);
275 this.output.WriteAttributeString(
"v",
string.Empty, PropertyValue.ToString());
276 this.output.WriteEndElement();
280 this.output.WriteStartElement(
"I1");
282 if (PropertyName is not
null)
283 this.output.WriteAttributeString(
"n", PropertyName);
285 this.output.WriteAttributeString(
"v",
string.Empty, PropertyValue.ToString());
286 this.output.WriteEndElement();
289 case TypeCode.Single:
290 this.output.WriteStartElement(
"Fl");
292 if (PropertyName is not
null)
293 this.output.WriteAttributeString(
"n", PropertyName);
295 this.output.WriteAttributeString(
"v",
string.Empty,
CommonTypes.
Encode((
float)PropertyValue));
296 this.output.WriteEndElement();
299 case TypeCode.String:
300 string s = PropertyValue?.ToString() ??
string.Empty;
303 XmlConvert.VerifyXmlChars(s);
304 this.output.WriteStartElement(
"S");
306 if (PropertyName is not
null)
307 this.output.WriteAttributeString(
"n", PropertyName);
309 this.output.WriteAttributeString(
"v",
string.Empty, s);
310 this.output.WriteEndElement();
314 byte[] Bin = Encoding.UTF8.GetBytes(s);
315 s = Convert.ToBase64String(Bin);
316 this.output.WriteStartElement(
"S64");
318 if (PropertyName is not
null)
319 this.output.WriteAttributeString(
"n", PropertyName);
321 this.output.WriteAttributeString(
"v",
string.Empty, s);
322 this.output.WriteEndElement();
326 case TypeCode.UInt16:
327 this.output.WriteStartElement(
"U2");
329 if (PropertyName is not
null)
330 this.output.WriteAttributeString(
"n", PropertyName);
332 this.output.WriteAttributeString(
"v",
string.Empty, PropertyValue.ToString());
333 this.output.WriteEndElement();
336 case TypeCode.UInt32:
337 this.output.WriteStartElement(
"U4");
339 if (PropertyName is not
null)
340 this.output.WriteAttributeString(
"n", PropertyName);
342 this.output.WriteAttributeString(
"v",
string.Empty, PropertyValue.ToString());
343 this.output.WriteEndElement();
346 case TypeCode.UInt64:
347 this.output.WriteStartElement(
"U8");
349 if (PropertyName is not
null)
350 this.output.WriteAttributeString(
"n", PropertyName);
352 this.output.WriteAttributeString(
"v",
string.Empty, PropertyValue.ToString());
353 this.output.WriteEndElement();
356 case TypeCode.DBNull:
358 this.output.WriteStartElement(
"Null");
360 if (PropertyName is not
null)
361 this.output.WriteAttributeString(
"n", PropertyName);
363 this.output.WriteEndElement();
366 case TypeCode.Object:
367 if (PropertyValue is TimeSpan)
369 this.output.WriteStartElement(
"TS");
371 if (PropertyName is not
null)
372 this.output.WriteAttributeString(
"n", PropertyName);
374 this.output.WriteAttributeString(
"v",
string.Empty, PropertyValue.ToString());
375 this.output.WriteEndElement();
377 else if (PropertyValue is DateTimeOffset DTO)
379 this.output.WriteStartElement(
"DTO");
381 if (PropertyName is not
null)
382 this.output.WriteAttributeString(
"n", PropertyName);
384 this.output.WriteAttributeString(
"v",
string.Empty,
XML.
Encode(DTO));
385 this.output.WriteEndElement();
392 XmlConvert.VerifyXmlChars(s);
393 this.output.WriteStartElement(
"CIS");
395 if (PropertyName is not
null)
396 this.output.WriteAttributeString(
"n", PropertyName);
398 this.output.WriteAttributeString(
"v",
string.Empty, s);
399 this.output.WriteEndElement();
403 byte[] Bin = Encoding.UTF8.GetBytes(s);
404 s = Convert.ToBase64String(Bin);
405 this.output.WriteStartElement(
"CIS64");
407 if (PropertyName is not
null)
408 this.output.WriteAttributeString(
"n", PropertyName);
410 this.output.WriteAttributeString(
"v",
string.Empty, s);
411 this.output.WriteEndElement();
414 else if (PropertyValue is
byte[] Bin)
416 this.output.WriteStartElement(
"Bin");
418 if (PropertyName is not
null)
419 this.output.WriteAttributeString(
"n", PropertyName);
423 if (c <= this.binaryDataSizeLimit)
426 this.output.WriteAttributeString(
"v", Convert.ToBase64String(Bin));
445 if (i == 0 && j == c)
452 Array.Copy(Bin, i, Buf, 0, j);
454 this.output.WriteElementString(
"Chunk", Convert.ToBase64String(Buf, 0, j, Base64FormattingOptions.None));
460 this.output.WriteAttributeString(
"bytes", c.ToString(CultureInfo.InvariantCulture));
462 this.output.WriteEndElement();
464 else if (PropertyValue is Guid)
466 this.output.WriteStartElement(
"ID");
468 if (PropertyName is not
null)
469 this.output.WriteAttributeString(
"n", PropertyName);
471 this.output.WriteAttributeString(
"v",
string.Empty, PropertyValue.ToString());
472 this.output.WriteEndElement();
474 else if (PropertyValue is Array A)
476 this.output.WriteStartElement(
"Array");
478 if (PropertyName is not
null)
479 this.output.WriteAttributeString(
"n", PropertyName);
481 this.output.WriteAttributeString(
"elementType",
string.Empty,
482 PropertyValue.GetType().GetElementType()?.FullName);
484 foreach (
object Obj
in A)
485 await this.ReportProperty(
null, Obj);
487 this.output.WriteEndElement();
491 this.output.WriteStartElement(
"Obj");
493 if (PropertyName is not
null)
494 this.output.WriteAttributeString(
"n", PropertyName);
496 this.output.WriteAttributeString(
"type",
string.Empty, Obj.TypeName);
498 foreach (KeyValuePair<string, object?> P
in Obj)
499 await this.ReportProperty(P.Key, P.Value);
501 this.output.WriteEndElement();
504 throw new Exception(
"Unhandled property value type: " + PropertyValue.GetType().FullName);
509 throw new Exception(
"Unhandled property value type: " + PropertyValue.GetType().FullName);
520 public Task<bool> EndObject()
522 this.output.WriteEndElement();
523 return Task.FromResult(
true);
531 public Task<bool> ReportError(
string Message)
533 this.output.WriteElementString(
"Error", Message);
534 return Task.FromResult(
true);
542 public async Task<bool> ReportException(Exception Exception)
544 this.output.WriteStartElement(
"Exception");
545 this.output.WriteAttributeString(
"message", Exception.Message);
546 this.output.WriteElementString(
"StackTrace",
Log.
CleanStackTrace(Exception.StackTrace));
548 if (Exception is AggregateException AggregateException)
550 foreach (Exception ex
in AggregateException.InnerExceptions)
551 await this.ReportException(ex);
553 else if (Exception.InnerException is not
null)
554 await this.ReportException(Exception.InnerException);
556 this.output.WriteEndElement();
564 public void Dispose()
567 GC.SuppressFinalize(
this);
573 protected virtual void Dispose(
bool disposing)
575 if (!this.disposeWriter)
581 this.output.Dispose();
584 this.disposeWriter =
false;
Helps with parsing of commong data types.
static string Encode(bool x)
Encodes a Boolean for use in XML and other formats.
Helps with common XML-related tasks.
static string Encode(string s)
Encodes a string for use in XML.
Static class managing the application event log. Applications and services log events on this static ...
static string CleanStackTrace(string StackTrace)
Cleans a Stack Trace string, removing entries from the asynchronous execution model,...
Represents a case-insensitive string.
Generic object. Contains a sequence of properties.
bool TryGetFieldValue(string PropertyName, out object Value)
Gets the value of a field or property of the object, given its name.
string CollectionName
Collection name.
Interface for database exports that filter objects.