Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
XmlDatabaseExport.cs
1using System.Globalization;
2using System.Text;
3using System.Xml;
4using Waher.Content;
6using Waher.Events;
9
11{
17 public class XmlDatabaseExport(XmlWriter Output, int BinaryDataSizeLimit) : IDatabaseExportFilter, IDisposable
18 {
19 private readonly XmlWriter output = Output;
20 private readonly int binaryDataSizeLimit = BinaryDataSizeLimit;
21 private bool disposeWriter;
22
29 public XmlDatabaseExport(StringBuilder Output, bool Indent, int BinaryDataSizeLimit)
30 : this(XmlWriter.Create(Output, XML.WriterSettings(Indent, true)), BinaryDataSizeLimit)
31 {
32 this.disposeWriter = true;
33 }
34
39 public Task<bool> StartDatabase()
40 {
41 this.output.WriteStartElement("Database");
42 return Task.FromResult(true);
43 }
44
49 public Task<bool> EndDatabase()
50 {
51 this.output.WriteEndElement();
52 return Task.FromResult(true);
53 }
54
60 public bool CanExportCollection(string CollectionName)
61 {
62 return true;
63 }
64
70 public Task<bool> StartCollection(string CollectionName)
71 {
72 this.output.WriteStartElement("Collection");
73 this.output.WriteAttributeString("name", CollectionName);
74 return Task.FromResult(true);
75 }
76
81 public Task<bool> EndCollection()
82 {
83 this.output.WriteEndElement();
84 return Task.FromResult(true);
85 }
86
91 public Task<bool> StartIndex()
92 {
93 this.output.WriteStartElement("Index");
94 return Task.FromResult(true);
95 }
96
103 public Task<bool> ReportIndexField(string FieldName, bool Ascending)
104 {
105 this.output.WriteStartElement("Index");
106 this.output.WriteAttributeString("field", FieldName);
107 this.output.WriteAttributeString("asc", CommonTypes.Encode(Ascending));
108 this.output.WriteEndElement();
109 return Task.FromResult(true);
110 }
111
116 public Task<bool> EndIndex()
117 {
118 this.output.WriteEndElement();
119 return Task.FromResult(true);
120 }
121
127 public bool CanExportObject(GenericObject Object)
128 {
129 if (Object.CollectionName != "Settings")
130 return true;
131
132 if (!Object.TryGetFieldValue("Key", out object Value) || Value is not string Key)
133 return true;
134
135 if (Key.StartsWith(ServiceRef.XmppService.ContractsClient.ContractKeySettingsPrefix, StringComparison.Ordinal) ||
136 Key.StartsWith(ServiceRef.XmppService.ContractsClient.KeySettingsPrefix, StringComparison.Ordinal))
137 {
138 return false;
139 }
140
141 return true;
142 }
143
150 public Task<string> StartObject(string ObjectId, string TypeName)
151 {
152 this.output.WriteStartElement("Obj");
153 this.output.WriteAttributeString("id", ObjectId);
154 this.output.WriteAttributeString("type", TypeName);
155 return Task.FromResult(ObjectId);
156 }
157
164 public async Task<bool> ReportProperty(string? PropertyName, object? PropertyValue)
165 {
166 if (PropertyValue is null)
167 {
168 this.output.WriteStartElement("Null");
169
170 if (PropertyName is not null)
171 this.output.WriteAttributeString("n", PropertyName);
172
173 this.output.WriteEndElement();
174 }
175 else if (PropertyValue is Enum)
176 {
177 this.output.WriteStartElement("En");
178
179 if (PropertyName is not null)
180 this.output.WriteAttributeString("n", PropertyName);
181
182 this.output.WriteAttributeString("v", string.Empty, PropertyValue.ToString());
183 this.output.WriteEndElement();
184 }
185 else
186 {
187 switch (Type.GetTypeCode(PropertyValue.GetType()))
188 {
189 case TypeCode.Boolean:
190 this.output.WriteStartElement("Bl");
191
192 if (PropertyName is not null)
193 this.output.WriteAttributeString("n", PropertyName);
194
195 this.output.WriteAttributeString("v", string.Empty, CommonTypes.Encode((bool)PropertyValue));
196 this.output.WriteEndElement();
197 break;
198
199 case TypeCode.Byte:
200 this.output.WriteStartElement("B");
201
202 if (PropertyName is not null)
203 this.output.WriteAttributeString("n", PropertyName);
204
205 this.output.WriteAttributeString("v", string.Empty, PropertyValue.ToString());
206 this.output.WriteEndElement();
207 break;
208
209 case TypeCode.Char:
210 this.output.WriteStartElement("Ch");
211
212 if (PropertyName is not null)
213 this.output.WriteAttributeString("n", PropertyName);
214
215 this.output.WriteAttributeString("v", string.Empty, PropertyValue.ToString());
216 this.output.WriteEndElement();
217 break;
218
219 case TypeCode.DateTime:
220 this.output.WriteStartElement("DT");
221
222 if (PropertyName is not null)
223 this.output.WriteAttributeString("n", PropertyName);
224
225 this.output.WriteAttributeString("v", string.Empty, XML.Encode((DateTime)PropertyValue));
226 this.output.WriteEndElement();
227 break;
228
229 case TypeCode.Decimal:
230 this.output.WriteStartElement("Dc");
231
232 if (PropertyName is not null)
233 this.output.WriteAttributeString("n", PropertyName);
234
235 this.output.WriteAttributeString("v", string.Empty, CommonTypes.Encode((decimal)PropertyValue));
236 this.output.WriteEndElement();
237 break;
238
239 case TypeCode.Double:
240 this.output.WriteStartElement("Db");
241
242 if (PropertyName is not null)
243 this.output.WriteAttributeString("n", PropertyName);
244
245 this.output.WriteAttributeString("v", string.Empty, CommonTypes.Encode((double)PropertyValue));
246 this.output.WriteEndElement();
247 break;
248
249 case TypeCode.Int16:
250 this.output.WriteStartElement("I2");
251
252 if (PropertyName is not null)
253 this.output.WriteAttributeString("n", PropertyName);
254
255 this.output.WriteAttributeString("v", string.Empty, PropertyValue.ToString());
256 this.output.WriteEndElement();
257 break;
258
259 case TypeCode.Int32:
260 this.output.WriteStartElement("I4");
261
262 if (PropertyName is not null)
263 this.output.WriteAttributeString("n", PropertyName);
264
265 this.output.WriteAttributeString("v", string.Empty, PropertyValue.ToString());
266 this.output.WriteEndElement();
267 break;
268
269 case TypeCode.Int64:
270 this.output.WriteStartElement("I8");
271
272 if (PropertyName is not null)
273 this.output.WriteAttributeString("n", PropertyName);
274
275 this.output.WriteAttributeString("v", string.Empty, PropertyValue.ToString());
276 this.output.WriteEndElement();
277 break;
278
279 case TypeCode.SByte:
280 this.output.WriteStartElement("I1");
281
282 if (PropertyName is not null)
283 this.output.WriteAttributeString("n", PropertyName);
284
285 this.output.WriteAttributeString("v", string.Empty, PropertyValue.ToString());
286 this.output.WriteEndElement();
287 break;
288
289 case TypeCode.Single:
290 this.output.WriteStartElement("Fl");
291
292 if (PropertyName is not null)
293 this.output.WriteAttributeString("n", PropertyName);
294
295 this.output.WriteAttributeString("v", string.Empty, CommonTypes.Encode((float)PropertyValue));
296 this.output.WriteEndElement();
297 break;
298
299 case TypeCode.String:
300 string s = PropertyValue?.ToString() ?? string.Empty;
301 try
302 {
303 XmlConvert.VerifyXmlChars(s);
304 this.output.WriteStartElement("S");
305
306 if (PropertyName is not null)
307 this.output.WriteAttributeString("n", PropertyName);
308
309 this.output.WriteAttributeString("v", string.Empty, s);
310 this.output.WriteEndElement();
311 }
312 catch (XmlException)
313 {
314 byte[] Bin = Encoding.UTF8.GetBytes(s);
315 s = Convert.ToBase64String(Bin);
316 this.output.WriteStartElement("S64");
317
318 if (PropertyName is not null)
319 this.output.WriteAttributeString("n", PropertyName);
320
321 this.output.WriteAttributeString("v", string.Empty, s);
322 this.output.WriteEndElement();
323 }
324 break;
325
326 case TypeCode.UInt16:
327 this.output.WriteStartElement("U2");
328
329 if (PropertyName is not null)
330 this.output.WriteAttributeString("n", PropertyName);
331
332 this.output.WriteAttributeString("v", string.Empty, PropertyValue.ToString());
333 this.output.WriteEndElement();
334 break;
335
336 case TypeCode.UInt32:
337 this.output.WriteStartElement("U4");
338
339 if (PropertyName is not null)
340 this.output.WriteAttributeString("n", PropertyName);
341
342 this.output.WriteAttributeString("v", string.Empty, PropertyValue.ToString());
343 this.output.WriteEndElement();
344 break;
345
346 case TypeCode.UInt64:
347 this.output.WriteStartElement("U8");
348
349 if (PropertyName is not null)
350 this.output.WriteAttributeString("n", PropertyName);
351
352 this.output.WriteAttributeString("v", string.Empty, PropertyValue.ToString());
353 this.output.WriteEndElement();
354 break;
355
356 case TypeCode.DBNull:
357 case TypeCode.Empty:
358 this.output.WriteStartElement("Null");
359
360 if (PropertyName is not null)
361 this.output.WriteAttributeString("n", PropertyName);
362
363 this.output.WriteEndElement();
364 break;
365
366 case TypeCode.Object:
367 if (PropertyValue is TimeSpan)
368 {
369 this.output.WriteStartElement("TS");
370
371 if (PropertyName is not null)
372 this.output.WriteAttributeString("n", PropertyName);
373
374 this.output.WriteAttributeString("v", string.Empty, PropertyValue.ToString());
375 this.output.WriteEndElement();
376 }
377 else if (PropertyValue is DateTimeOffset DTO)
378 {
379 this.output.WriteStartElement("DTO");
380
381 if (PropertyName is not null)
382 this.output.WriteAttributeString("n", PropertyName);
383
384 this.output.WriteAttributeString("v", string.Empty, XML.Encode(DTO));
385 this.output.WriteEndElement();
386 }
387 else if (PropertyValue is CaseInsensitiveString Cis)
388 {
389 s = Cis.Value;
390 try
391 {
392 XmlConvert.VerifyXmlChars(s);
393 this.output.WriteStartElement("CIS");
394
395 if (PropertyName is not null)
396 this.output.WriteAttributeString("n", PropertyName);
397
398 this.output.WriteAttributeString("v", string.Empty, s);
399 this.output.WriteEndElement();
400 }
401 catch (XmlException)
402 {
403 byte[] Bin = Encoding.UTF8.GetBytes(s);
404 s = Convert.ToBase64String(Bin);
405 this.output.WriteStartElement("CIS64");
406
407 if (PropertyName is not null)
408 this.output.WriteAttributeString("n", PropertyName);
409
410 this.output.WriteAttributeString("v", string.Empty, s);
411 this.output.WriteEndElement();
412 }
413 }
414 else if (PropertyValue is byte[] Bin)
415 {
416 this.output.WriteStartElement("Bin");
417
418 if (PropertyName is not null)
419 this.output.WriteAttributeString("n", PropertyName);
420
421 long c = Bin.Length;
422
423 if (c <= this.binaryDataSizeLimit)
424 {
425 if (c <= 1024)
426 this.output.WriteAttributeString("v", Convert.ToBase64String(Bin));
427 else
428 {
429 byte[]? Buf = null;
430 long i = 0;
431 long d;
432 int j;
433
434 while (i < c)
435 {
436 d = c - i;
437
438 if (d > 49152)
439 j = 49152;
440 else
441 j = (int)d;
442
443 if (Buf is null)
444 {
445 if (i == 0 && j == c)
446 Buf = Bin;
447 else
448 Buf = new byte[j];
449 }
450
451 if (Buf != Bin)
452 Array.Copy(Bin, i, Buf, 0, j);
453
454 this.output.WriteElementString("Chunk", Convert.ToBase64String(Buf, 0, j, Base64FormattingOptions.None));
455 i += j;
456 }
457 }
458 }
459 else
460 this.output.WriteAttributeString("bytes", c.ToString(CultureInfo.InvariantCulture));
461
462 this.output.WriteEndElement();
463 }
464 else if (PropertyValue is Guid)
465 {
466 this.output.WriteStartElement("ID");
467
468 if (PropertyName is not null)
469 this.output.WriteAttributeString("n", PropertyName);
470
471 this.output.WriteAttributeString("v", string.Empty, PropertyValue.ToString());
472 this.output.WriteEndElement();
473 }
474 else if (PropertyValue is Array A)
475 {
476 this.output.WriteStartElement("Array");
477
478 if (PropertyName is not null)
479 this.output.WriteAttributeString("n", PropertyName);
480
481 this.output.WriteAttributeString("elementType", string.Empty,
482 PropertyValue.GetType().GetElementType()?.FullName);
483
484 foreach (object Obj in A)
485 await this.ReportProperty(null, Obj);
486
487 this.output.WriteEndElement();
488 }
489 else if (PropertyValue is GenericObject Obj)
490 {
491 this.output.WriteStartElement("Obj");
492
493 if (PropertyName is not null)
494 this.output.WriteAttributeString("n", PropertyName);
495
496 this.output.WriteAttributeString("type", string.Empty, Obj.TypeName);
497
498 foreach (KeyValuePair<string, object?> P in Obj)
499 await this.ReportProperty(P.Key, P.Value);
500
501 this.output.WriteEndElement();
502 }
503 else
504 throw new Exception("Unhandled property value type: " + PropertyValue.GetType().FullName);
505
506 break;
507
508 default:
509 throw new Exception("Unhandled property value type: " + PropertyValue.GetType().FullName);
510 }
511 }
512
513 return true;
514 }
515
520 public Task<bool> EndObject()
521 {
522 this.output.WriteEndElement();
523 return Task.FromResult(true);
524 }
525
531 public Task<bool> ReportError(string Message)
532 {
533 this.output.WriteElementString("Error", Message);
534 return Task.FromResult(true);
535 }
536
542 public async Task<bool> ReportException(Exception Exception)
543 {
544 this.output.WriteStartElement("Exception");
545 this.output.WriteAttributeString("message", Exception.Message);
546 this.output.WriteElementString("StackTrace", Log.CleanStackTrace(Exception.StackTrace));
547
548 if (Exception is AggregateException AggregateException)
549 {
550 foreach (Exception ex in AggregateException.InnerExceptions)
551 await this.ReportException(ex);
552 }
553 else if (Exception.InnerException is not null)
554 await this.ReportException(Exception.InnerException);
555
556 this.output.WriteEndElement();
557
558 return true;
559 }
560
564 public void Dispose()
565 {
566 this.Dispose(true);
567 GC.SuppressFinalize(this);
568 }
569
573 protected virtual void Dispose(bool disposing)
574 {
575 if (!this.disposeWriter)
576 return;
577
578 if (disposing)
579 {
580 this.output.Flush();
581 this.output.Dispose();
582 }
583
584 this.disposeWriter = false;
585 }
586 }
587}
Helps with parsing of commong data types.
Definition: CommonTypes.cs:13
static string Encode(bool x)
Encodes a Boolean for use in XML and other formats.
Definition: CommonTypes.cs:594
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:27
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static string CleanStackTrace(string StackTrace)
Cleans a Stack Trace string, removing entries from the asynchronous execution model,...
Definition: Log.cs:184
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.
Interface for database exports that filter objects.