1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Concepts;
  8 using System.Collections;
  9 using System.Dom;
 10 using System.XPath;
 11 
 12 namespace System.Xml.Serialization
 13 {
 14     public concept XmlConstructible<T>
 15     {
 16         where DefaultConstructible<T>;
 17         void T.FromXml(Element* element);
 18     }
 19 
 20     public concept XmlImportableScalarType<T>
 21     {
 22         where
 23             T is bool or 
 24             T is sbyte or 
 25             T is byte or 
 26             T is short or 
 27             T is ushort or 
 28             T is int or 
 29             T is uint or 
 30             T is long or 
 31             T is ulong or 
 32             T is float or 
 33             T is double or 
 34             T is char or 
 35             T is wchar or 
 36             T is uchar or 
 37             T is string or 
 38             T is wstring or 
 39             T is ustring or 
 40             T is System.Uuid or 
 41             T is System.Date or 
 42             T is System.DateTime or 
 43             T is System.Timestamp or 
 44             T is System.TimePoint or 
 45             T is System.Duration;
 46     }
 47 
 48     public concept XmlImportableEnumeratedType<T>
 49     {
 50         where System.Meta.IsEnumeratedType<T>();
 51     }
 52 
 53     public nothrow Element* GetXmlFieldElement(const string& fieldNameElement* fromElement)
 54     {
 55         UniquePtr<XPathObject> result = Evaluate(ToUtf32(fieldName)fromElement);
 56         if (!result.IsNull())
 57         {
 58             if (result.Get() is XPathNodeSet*)
 59             {
 60                 XPathNodeSet* nodeSet = cast<XPathNodeSet*>(result.Get());
 61                 if (nodeSet->Length() == 1)
 62                 {
 63                     Node* node = (*nodeSet)[0];
 64                     if (node is Element*)
 65                     {
 66                         Element* fieldElement = cast<Element*>(node);
 67                         return fieldElement;
 68                     }
 69                 }
 70             }
 71         }
 72         return null;
 73     }
 74 
 75     public void FromXml(Element* elementbool& value)
 76     {
 77         if (element != null)
 78         {
 79             value = ParseBool(ToUtf8(element->GetAttribute(u"value")));
 80         }
 81     }
 82 
 83     public void FromXml(Element* parentElementconst string& fieldNamebool& value)
 84     {
 85         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
 86     }
 87 
 88     public void FromXml(Element* elementsbyte& value)
 89     {
 90         if (element != null)
 91         {
 92             value = ParseSByte(ToUtf8(element->GetAttribute(u"value")));
 93         }
 94     }
 95 
 96     public void FromXml(Element* parentElementconst string& fieldNamesbyte& value)
 97     {
 98         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
 99     }
100 
101     public void FromXml(Element* elementbyte& value)
102     {
103         if (element != null)
104         {
105             value = ParseByte(ToUtf8(element->GetAttribute(u"value")));
106         }
107     }
108 
109     public void FromXml(Element* parentElementconst string& fieldNamebyte& value)
110     {
111         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
112     }
113 
114     public void FromXml(Element* elementshort& value)
115     {
116         if (element != null)
117         {
118             value = ParseShort(ToUtf8(element->GetAttribute(u"value")));
119         }
120     }
121 
122     public void FromXml(Element* parentElementconst string& fieldNameshort& value)
123     {
124         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
125     }
126 
127     public void FromXml(Element* elementushort& value)
128     {
129         if (element != null)
130         {
131             value = ParseUShort(ToUtf8(element->GetAttribute(u"value")));
132         }
133     }
134 
135     public void FromXml(Element* parentElementconst string& fieldNameushort& value)
136     {
137         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
138     }
139 
140     public void FromXml(Element* elementint& value)
141     {
142         if (element != null)
143         {
144             value = ParseInt(ToUtf8(element->GetAttribute(u"value")));
145         }
146     }
147 
148     public void FromXml(Element* parentElementconst string& fieldNameint& value)
149     {
150         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
151     }
152 
153     public void FromXml(Element* elementuint& value)
154     {
155         if (element != null)
156         {
157             value = ParseUInt(ToUtf8(element->GetAttribute(u"value")));
158         }
159     }
160 
161     public void FromXml(Element* parentElementconst string& fieldNameuint& value)
162     {
163         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
164     }
165 
166     public void FromXml(Element* elementlong& value)
167     {
168         if (element != null)
169         {
170             value = ParseLong(ToUtf8(element->GetAttribute(u"value")));
171         }
172     }
173 
174     public void FromXml(Element* parentElementconst string& fieldNamelong& value)
175     {
176         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
177     }
178 
179     public void FromXml(Element* elementulong& value)
180     {
181         if (element != null)
182         {
183             value = ParseULong(ToUtf8(element->GetAttribute(u"value")));
184         }
185     }
186 
187     public void FromXml(Element* parentElementconst string& fieldNameulong& value)
188     {
189         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
190     }
191 
192     public void FromXml(Element* elementfloat& value)
193     {
194         if (element != null)
195         {
196             value = ParseFloat(ToUtf8(element->GetAttribute(u"value")));
197         }
198     }
199 
200     public void FromXml(Element* parentElementconst string& fieldNamefloat& value)
201     {
202         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
203     }
204 
205     public void FromXml(Element* elementdouble& value)
206     {
207         if (element != null)
208         {
209             value = ParseDouble(ToUtf8(element->GetAttribute(u"value")));
210         }
211     }
212 
213     public void FromXml(Element* parentElementconst string& fieldNamedouble& value)
214     {
215         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
216     }
217 
218     public void FromXml(Element* elementchar& value)
219     {
220         if (element != null)
221         {
222             value = ToUtf8(element->GetAttribute(u"value"))[0];
223         }
224     }
225 
226     public void FromXml(Element* parentElementconst string& fieldNamechar& value)
227     {
228         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
229     }
230 
231     public void FromXml(Element* elementwchar& value)
232     {
233         if (element != null)
234         {
235             value = ToUtf16(element->GetAttribute(u"value"))[0];
236         }
237     }
238 
239     public void FromXml(Element* parentElementconst string& fieldNamewchar& value)
240     {
241         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
242     }
243 
244     public void FromXml(Element* elementuchar& value)
245     {
246         if (element != null)
247         {
248             value = element->GetAttribute(u"value")[0];
249         }
250     }
251 
252     public void FromXml(Element* parentElementconst string& fieldNameuchar& value)
253     {
254         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
255     }
256 
257     public void FromXml<T>(Element* elementT& value)
258         where T is XmlImportableEnumeratedType
259     {
260         if (element != null)
261         {
262             value = cast<T>(cast<T.UnderlyingType>(ParseLong(ToUtf8(element->GetAttribute(u"value")))));
263         }
264     }
265 
266     public void FromXml<T>(Element* parentElementconst string& fieldNameT& value)
267         where T is XmlImportableEnumeratedType
268     {
269         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
270     }
271 
272     public void FromXml(Element* elementSystem.Date& value)
273     {
274         if (element != null)
275         {
276             value = ParseDate(ToUtf8(element->GetAttribute(u"value")));
277         }
278     }
279 
280     public void FromXml(Element* parentElementconst string& fieldNameSystem.Date& value)
281     {
282         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
283     }
284 
285     public void FromXml(Element* elementSystem.DateTime& value)
286     {
287         if (element != null)
288         {
289             value = ParseDateTime(ToUtf8(element->GetAttribute(u"value")));
290         }
291     }
292 
293     public void FromXml(Element* parentElementconst string& fieldNameSystem.DateTime& value)
294     {
295         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
296     }
297 
298     public void FromXml(Element* elementSystem.Timestamp& value)
299     {
300         if (element != null)
301         {
302             value = ParseTimestamp(ToUtf8(element->GetAttribute(u"value")));
303         }
304     }
305 
306     public void FromXml(Element* parentElementconst string& fieldNameSystem.Timestamp& value)
307     {
308         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
309     }
310 
311     public void FromXml(Element* elementstring& value)
312     {
313         if (element != null)
314         {
315             value = ToUtf8(element->GetAttribute(u"value"));
316         }
317     }
318 
319     public void FromXml(Element* parentElementconst string& fieldNamestring& value)
320     {
321         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
322     }
323 
324     public void FromXml(Element* elementwstring& value)
325     {
326         if (element != null)
327         {
328             value = ToUtf16(element->GetAttribute(u"value"));
329         }
330     }
331 
332     public void FromXml(Element* parentElementconst string& fieldNamewstring& value)
333     {
334         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
335     }
336 
337     public void FromXml(Element* elementustring& value)
338     {
339         if (element != null)
340         {
341             value = element->GetAttribute(u"value");
342         }
343     }
344 
345     public void FromXml(Element* parentElementconst string& fieldNameustring& value)
346     {
347         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
348     }
349 
350     public void FromXml(Element* elementSystem.TimePoint& value)
351     {
352         if (element != null)
353         {
354             value = TimePoint(ParseLong(ToUtf8(element->GetAttribute(u"value"))));
355         }
356     }
357 
358     public void FromXml(Element* parentElementconst string& fieldNameSystem.TimePoint& value)
359     {
360         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
361     }
362 
363     public void FromXml(Element* elementSystem.Duration& value)
364     {
365         if (element != null)
366         {
367             value = Duration(ParseLong(ToUtf8(element->GetAttribute(u"value"))));
368         }
369     }
370 
371     public void FromXml(Element* parentElementconst string& fieldNameSystem.Duration& value)
372     {
373         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
374     }
375 
376     public void FromXml(Element* elementSystem.Uuid& value)
377     {
378         if (element != null)
379         {
380             value = ParseUuid(ToUtf8(element->GetAttribute(u"value")));
381         }
382     }
383 
384     public void FromXml(Element* parentElementconst string& fieldNameSystem.Uuid& value)
385     {
386         FromXml(GetXmlFieldElement(fieldNameparentElement)value);
387     }
388 
389     public void FromXml<T>(Element* parentElementconst string& fieldNameT& object)
390         where T is XmlConstructible
391     {
392         Element* element = GetXmlFieldElement(fieldNameparentElement);
393         if (element != null)
394         {
395             object.FromXml(element);
396         }
397     }
398 
399     public void FromXml<T>(Element* parentElementconst string& fieldNameUniquePtr<T>& object)
400         where T is XmlConstructible
401     {
402         object.Reset();
403         Element* element = GetXmlFieldElement(fieldNameparentElement);
404         if (element != null)
405         {
406             ustring value = element->GetAttribute(u"value");
407             if (value != u"null")
408             {
409                 ustring classIdAttr = element->GetAttribute(u"classId");
410                 if (!classIdAttr.IsEmpty())
411                 {
412                     int classId = ParseInt(ToUtf8(classIdAttr));
413                     object.Reset(cast<T*>(XmlClassRegistry.Instance().Create(classId)));
414                     object->FromXml(element);
415                 }
416             }
417         }
418     }
419 
420     public void FromXml<T>(Element* parentElementconst string& fieldNameSharedPtr<T>& object)
421         where T is XmlConstructible
422     {
423         object.Reset();
424         Element* element = GetXmlFieldElement(fieldNameparentElement);
425         if (element != null)
426         {
427             ustring value = element->GetAttribute(u"value");
428             if (value != u"null")
429             {
430                 ustring classIdAttr = element->GetAttribute(u"classId");
431                 if (!classIdAttr.IsEmpty())
432                 {
433                     int classId = ParseInt(ToUtf8(classIdAttr));
434                     object.Reset(cast<T*>(XmlClassRegistry.Instance().Create(classId)));
435                     object->FromXml(element);
436                 }
437             }
438         }
439     }
440 
441     public void FromXml<T>(Element* parentElementconst string& fieldNameXmlPtr<T>& ptr)
442         where T is XmlConstructible
443     {
444         ptr.Reset();
445         Element* element = GetXmlFieldElement(fieldNameparentElement);
446         if (element != null)
447         {
448             ustring value = element->GetAttribute(u"value");
449             if (value != u"null")
450             {
451                 ustring objectIdAttr = element->GetAttribute(u"objectId");
452                 if (!objectIdAttr.IsEmpty())
453                 {
454                     Uuid objectId = ParseUuid(ToUtf8(objectIdAttr));
455                     ptr.SetTargetObjectId(objectId);
456                 }
457             }
458         }
459     }
460 
461     public void FromXml<T>(Element* parentElementconst string& fieldNameUniqueXmlPtr<T>& ptr)
462         where T is XmlConstructible
463     {
464         ptr.Reset();
465         Element* element = GetXmlFieldElement(fieldNameparentElement);
466         if (element != null)
467         {
468             ustring value = element->GetAttribute(u"value");
469             if (value != u"null")
470             {
471                 ustring objectIdAttr = element->GetAttribute(u"objectId");
472                 if (!objectIdAttr.IsEmpty())
473                 {
474                     Uuid objectId = ParseUuid(ToUtf8(objectIdAttr));
475                     ptr.SetTargetObjectId(objectId);
476                 }
477             }
478         }
479     }
480 
481     public void FromXml<T>(Element* parentElementconst string& fieldNameList<T>& list)
482         where T is XmlImportableScalarType
483     {
484         list.Clear();
485         Element* element = GetXmlFieldElement(fieldNameparentElement);
486         if (element != null)
487         {
488             UniquePtr<XPathObject> result = Evaluate(u"item"element);
489             if (!result.IsNull())
490             {
491                 if (result.Get() is XPathNodeSet*)
492                 {
493                     XPathNodeSet* nodeSet = cast<XPathNodeSet*>(result.Get());
494                     int n = nodeSet->Length();
495                     for (int i = 0; i < n; ++i;)
496                     {
497                         Node* node = (*nodeSet)[i];
498                         if (node is Element*)
499                         {
500                             Element* element = cast<Element*>(node);
501                             T value;
502                             FromXml(elementvalue);
503                             list.Add(Rvalue(value));
504                         }
505                     }
506                 }
507             }
508         }
509     }
510 
511     public void FromXml<T>(Element* parentElementconst string& fieldNameList<T>& list)
512         where T is XmlConstructible
513     {
514         list.Clear();
515         Element* element = GetXmlFieldElement(fieldNameparentElement);
516         if (element != null)
517         {
518             UniquePtr<XPathObject> result = Evaluate(u"item"element);
519             if (!result.IsNull())
520             {
521                 if (result.Get() is XPathNodeSet*)
522                 {
523                     XPathNodeSet* nodeSet = cast<XPathNodeSet*>(result.Get());
524                     int n = nodeSet->Length();
525                     for (int i = 0; i < n; ++i;)
526                     {
527                         Node* node = (*nodeSet)[i];
528                         if (node is Element*)
529                         {
530                             Element* element = cast<Element*>(node);
531                             T object;
532                             object.FromXml(element);
533                             list.Add(Rvalue(object));
534                         }
535                     }
536                 }
537             }
538         }
539     }
540 
541     public void FromXml<T>(Element* parentElementconst string& fieldNameList<UniquePtr<T>>& list)
542         where T is XmlConstructible
543     {
544         list.Clear();
545         Element* element = GetXmlFieldElement(fieldNameparentElement);
546         if (element != null)
547         {
548             UniquePtr<XPathObject> result = Evaluate(u"item"element);
549             if (!result.IsNull())
550             {
551                 if (result.Get() is XPathNodeSet*)
552                 {
553                     XPathNodeSet* nodeSet = cast<XPathNodeSet*>(result.Get());
554                     int n = nodeSet->Length();
555                     for (int i = 0; i < n; ++i;)
556                     {
557                         Node* node = (*nodeSet)[i];
558                         if (node is Element*)
559                         {
560                             Element* element = cast<Element*>(node);
561                             UniquePtr<T> object;
562                             ustring value = element->GetAttribute(u"value");
563                             if (value != u"null")
564                             {
565                                 ustring classIdAttr = element->GetAttribute(u"classId");
566                                 if (!classIdAttr.IsEmpty())
567                                 {
568                                     int classId = ParseInt(ToUtf8(classIdAttr));
569                                     object.Reset(cast<T*>(XmlClassRegistry.Instance().Create(classId)));
570                                     object->FromXml(element);
571                                 }
572                             }
573                             list.Add(Rvalue(object));
574                         }
575                     }
576                 }
577             }
578         }
579     }
580 
581     public void FromXml<T>(Element* parentElementconst string& fieldNameList<SharedPtr<T>>& list)
582         where T is XmlConstructible
583     {
584         list.Clear();
585         Element* element = GetXmlFieldElement(fieldNameparentElement);
586         if (element != null)
587         {
588             UniquePtr<XPathObject> result = Evaluate(u"item"element);
589             if (!result.IsNull())
590             {
591                 if (result.Get() is XPathNodeSet*)
592                 {
593                     XPathNodeSet* nodeSet = cast<XPathNodeSet*>(result.Get());
594                     int n = nodeSet->Length();
595                     for (int i = 0; i < n; ++i;)
596                     {
597                         Node* node = (*nodeSet)[i];
598                         if (node is Element*)
599                         {
600                             Element* element = cast<Element*>(node);
601                             SharedPtr<T> object;
602                             ustring value = element->GetAttribute(u"value");
603                             if (value != u"null")
604                             {
605                                 ustring classIdAttr = element->GetAttribute(u"classId");
606                                 if (!classIdAttr.IsEmpty())
607                                 {
608                                     int classId = ParseInt(ToUtf8(classIdAttr));
609                                     object.Reset(cast<T*>(XmlClassRegistry.Instance().Create(classId)));
610                                     object->FromXml(element);
611                                 }
612                             }
613                             list.Add(Rvalue(object));
614                         }
615                     }
616                 }
617             }
618         }
619     }
620 
621     public void FromXml<T>(Element* parentElementconst string& fieldNameList<XmlPtr<T>>& list)
622         where T is XmlConstructible
623     {
624         list.Clear();
625         Element* element = GetXmlFieldElement(fieldNameparentElement);
626         if (element != null)
627         {
628             UniquePtr<XPathObject> result = Evaluate(u"item"element);
629             if (!result.IsNull())
630             {
631                 if (result.Get() is XPathNodeSet*)
632                 {
633                     XPathNodeSet* nodeSet = cast<XPathNodeSet*>(result.Get());
634                     int n = nodeSet->Length();
635                     for (int i = 0; i < n; ++i;)
636                     {
637                         Node* node = (*nodeSet)[i];
638                         if (node is Element*)
639                         {
640                             Element* element = cast<Element*>(node);
641                             list.Add(XmlPtr<T>());
642                             XmlPtr<T>& ptr = list.Back();
643                             ustring value = element->GetAttribute(u"value");
644                             if (value != u"null")
645                             {
646                                 ustring objectIdAttr = element->GetAttribute(u"objectId");
647                                 if (!objectIdAttr.IsEmpty())
648                                 {
649                                     Uuid objectId = ParseUuid(ToUtf8(objectIdAttr));
650                                     ptr.SetTargetObjectId(objectId);
651                                 }
652                             }
653                         }
654                     }
655                 }
656             }
657         }
658     }
659 
660     public void FromXml<T>(Element* parentElementconst string& fieldNameList<UniqueXmlPtr<T>>& list)
661         where T is XmlConstructible
662     {
663         list.Clear();
664         Element* element = GetXmlFieldElement(fieldNameparentElement);
665         if (element != null)
666         {
667             UniquePtr<XPathObject> result = Evaluate(u"item"element);
668             if (!result.IsNull())
669             {
670                 if (result.Get() is XPathNodeSet*)
671                 {
672                     XPathNodeSet* nodeSet = cast<XPathNodeSet*>(result.Get());
673                     int n = nodeSet->Length();
674                     for (int i = 0; i < n; ++i;)
675                     {
676                         Node* node = (*nodeSet)[i];
677                         if (node is Element*)
678                         {
679                             Element* element = cast<Element*>(node);
680                             list.Add(UniqueXmlPtr<T>());
681                             UniqueXmlPtr<T>& ptr = list.Back();
682                             ustring value = element->GetAttribute(u"value");
683                             if (value != u"null")
684                             {
685                                 ustring objectIdAttr = element->GetAttribute(u"objectId");
686                                 if (!objectIdAttr.IsEmpty())
687                                 {
688                                     Uuid objectId = ParseUuid(ToUtf8(objectIdAttr));
689                                     ptr.SetTargetObjectId(objectId);
690                                 }
691                             }
692                         }
693                     }
694                 }
695             }
696         }
697     }
698 }
699 
700