1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Text;
  8 using System.IO;
  9 
 10 namespace System.Xml.Serialization
 11 {
 12     public enum XmlBundleKind : int
 13     {
 14         shallow = 0deep = 1
 15     }
 16 
 17     public class XmlBundle : XmlContainer
 18     {
 19         public nothrow XmlBundle() : base()owning(false)
 20         {
 21         }
 22         public ~XmlBundle()
 23         {
 24             if (owning)
 25             {
 26                 DestroyNonownedObjects();
 27             }
 28         }
 29         public nothrow bool IsOwning() const
 30         {
 31             return owning;
 32         }
 33         public nothrow void SetOwning()
 34         {
 35             owning = true;
 36         }
 37         public nothrow void ResetOwning()
 38         {
 39             owning = false;
 40         }
 41         public nothrow void DestroyNonownedObjects()
 42         {
 43             List<XmlSerializableProxy*> proxies = GetProxies();
 44             List<XmlSerializableProxy*> toBeDestroyed;
 45             for (XmlSerializableProxy* proxy : proxies)
 46             {
 47                 if (!proxy->IsOwned())
 48                 {
 49                     toBeDestroyed.Add(proxy);
 50                 }
 51             }
 52             for (XmlSerializableProxy* d : toBeDestroyed)
 53             {
 54                 d->DestroyObject();
 55             }
 56             Clear();
 57         }
 58         public nothrow const Uuid& RootObjectId() const
 59         {
 60             return rootObjectId;
 61         }
 62         public override nothrow void SetRootObjectId(const Uuid& rootObjectId_)
 63         {
 64             rootObjectId = rootObjectId_;
 65         }
 66         public nothrow XmlSerializableProxy* Root() const
 67         {
 68             if (rootObjectId != Uuid())
 69             {
 70                 return Get(rootObjectId);
 71             }
 72             else
 73             {
 74                 return null;
 75             }
 76         }
 77         public UniquePtr<System.Dom.Document> ToXmlDocument()
 78         {
 79             UniquePtr<System.Dom.Element> rootElement(new System.Dom.Element(u"xmlBundle"));
 80             rootElement->SetAttribute(u"rootObjectId"ToUtf32(ToString(rootObjectId)));
 81             List<XmlSerializableProxy*> proxies = GetProxies();
 82             for (XmlSerializableProxy* proxy : proxies)
 83             {
 84                 if (proxy->Object() != null)
 85                 {
 86                     UniquePtr<System.Dom.Element> serializableElement = proxy->ToXml("object");
 87                     rootElement->AppendChild(UniquePtr<System.Dom.Node>(serializableElement.Release()));
 88                 }
 89             }
 90             UniquePtr<System.Dom.Document> document(new System.Dom.Document());
 91             document->AppendChild(UniquePtr<System.Dom.Node>(rootElement.Release()));
 92             return document;
 93         }
 94         public string ToXmlString() const
 95         {
 96             return ToXmlString(1);
 97         }
 98         public string ToXmlString(int indent) const
 99         {
100             UniquePtr<System.Dom.Document> document = ToXmlDocument();
101             StringWriter stringWriter;
102             CodeFormatter formatter(stringWriter);
103             formatter.SetIndentSize(indent);
104             document->Write(formatter);
105             return stringWriter.GetString();
106         }
107         public void ResolveXmlPtrs()
108         {
109             List<XmlSerializableProxy*> proxies = GetProxies();
110             for (XmlSerializableProxy* proxy : proxies)
111             {
112                 List<XmlPtrBase*> ptrs = proxy->GetPtrs();
113                 for (XmlPtrBase* ptr : ptrs)
114                 {
115                     ptr->Resolve(this);
116                 }
117             }
118         }
119         private Uuid rootObjectId;
120         private bool owning;
121     }
122 
123     public UniquePtr<XmlBundle> ToXmlBundle(const string& xmlStrconst string& systemId)
124     {
125         return ToXmlBundle(xmlStrsystemIdtrue);
126     }
127 
128     public UniquePtr<XmlBundle> ToXmlBundle(const string& xmlStrconst string& systemIdbool createOwningBundle)
129     {
130         UniquePtr<XmlBundle> bundle(new XmlBundle());
131         if (createOwningBundle)
132         {
133             bundle->SetOwning();
134         }
135         ustring content = ToUtf32(xmlStr);
136         UniquePtr<System.Dom.Document> document = System.Dom.ParseDocument(contentsystemId);
137         UniquePtr<System.XPath.XPathObject> bundleObject = System.XPath.Evaluate(u"xmlBundle"document.Get());
138         if (!bundleObject.IsNull())
139         {
140             if (bundleObject.Get() is System.XPath.XPathNodeSet*)
141             {
142                 System.XPath.XPathNodeSet* nodeSet = cast<System.XPath.XPathNodeSet*>(bundleObject.Get());
143                 int length = nodeSet->Length();
144                 if (length == 1)
145                 {
146                     System.Dom.Node* node = (*nodeSet)[0];
147                     if (node is System.Dom.Element*)
148                     {
149                         System.Dom.Element* rootElement = cast<System.Dom.Element*>(node);
150                         ustring rootObjectIdAttr = rootElement->GetAttribute(u"rootObjectId");
151                         if (!rootObjectIdAttr.IsEmpty())
152                         {
153                             Uuid rootObjectId = ParseUuid(ToUtf8(rootObjectIdAttr));
154                             bundle->SetRootObjectId(rootObjectId);
155                         }
156                     }
157                     UniquePtr<System.XPath.XPathObject> object = System.XPath.Evaluate(u"xmlBundle/object"document.Get());
158                     if (!object.IsNull())
159                     {
160                         if (object.Get() is System.XPath.XPathNodeSet*)
161                         {
162                             System.XPath.XPathNodeSet* nodeSet = cast<System.XPath.XPathNodeSet*>(object.Get());
163                             int n = nodeSet->Length();
164                             for (int i = 0; i < n; ++i;)
165                             {
166                                 System.Dom.Node* node = (*nodeSet)[i];
167                                 if (node is System.Dom.Element*)
168                                 {
169                                     System.Dom.Element* element = cast<System.Dom.Element*>(node);
170                                     ustring classIdAttr = element->GetAttribute(u"classId");
171                                     if (!classIdAttr.IsEmpty())
172                                     {
173                                         int classId = ParseInt(ToUtf8(classIdAttr));
174                                         XmlSerializable xmlSerializable = XmlClassRegistry.Instance().CreateXmlSerializable(classId);
175                                         xmlSerializable.FromXml(element);
176                                         bundle->Add(xmlSerializable);
177                                     }
178                                 }
179                             }
180                         }
181                     }
182                     bundle->ResolveXmlPtrs();
183                 }
184                 else
185                 {
186                     throw XmlSerializationException("single 'xmlBundle' element expected");
187                 }
188             }
189         }
190         return bundle;
191     }
192 }
193