1
2
3
4
5
6 using System;
7 using System.Collections;
8 using System.Xml;
9 using System.Xml.Serialization;
10 using System.Text;
11 using System.IO;
12
13 namespace System.Xml.Serialization
14 {
15 internal class ScopedXmlBundleSetter
16 {
17 public ScopedXmlBundleSetter(XmlSerializationContext& ctx_, XmlBundle* bundle) : ctx(ctx_), prevBundle(ctx.GetXmlBundle())
18 {
19 ctx.SetXmlBundle(bundle);
20 }
21 public ~ScopedXmlBundleSetter()
22 {
23 ctx.SetXmlBundle(prevBundle);
24 }
25 private XmlSerializationContext& ctx;
26 private XmlBundle* prevBundle;
27 }
28
29 public class XmlBundle
30 {
31 public XmlBundle()
32 {
33 }
34 public void Add(XmlSerializable* object)
35 {
36 Add(object, true);
37 }
38 public void Add(XmlSerializable* object, bool own)
39 {
40 objects.Add(object);
41 if (own)
42 {
43 ownedObjects.Add(UniquePtr<XmlSerializable>(object));
44 }
45 objectMap[object->ObjectId()] = object;
46 }
47 public long Count() const
48 {
49 return objects.Count();
50 }
51 public long OwnedCount() const
52 {
53 return ownedObjects.Count();
54 }
55 public Result<UniquePtr<System.Xml.Document>> ToXmlDocument() const
56 {
57 auto result = ToXml();
58 if (result.Error())
59 {
60 return Result<UniquePtr<System.Xml.Document>>(ErrorId(result.GetErrorId()));
61 }
62 UniquePtr<System.Xml.Document> document(new System.Xml.Document());
63 document->AppendChild(result.Value());
64 return Result<UniquePtr<System.Xml.Document>>(Rvalue(document));
65 }
66 public Result<System.Xml.Element*> ToXml() const
67 {
68 UniquePtr<System.Xml.Element> bundleElement(System.Xml.MakeElement("xmlBundle"));
69 for (XmlSerializable* object : objects)
70 {
71 Result<System.Xml.Element*> objectElementResult = object->ToXml("object");
72 if (objectElementResult.Error()) return Result<System.Xml.Element*>(ErrorId(objectElementResult.GetErrorId()));
73 bundleElement->AppendChild(objectElementResult.Value());
74 }
75 return Result<System.Xml.Element*>(bundleElement.Release());
76 }
77 [nodiscard]
78 public Result<bool> FromXml(System.Xml.Document& document)
79 {
80 return FromXml(document.DocumentElement());
81 }
82 [nodiscard]
83 public Result<bool> FromXml(System.Xml.Document& document, XmlSerializationContext& ctx)
84 {
85 return FromXml(document.DocumentElement(), ctx);
86 }
87 [nodiscard]
88 public Result<bool> FromXml(System.Xml.Element* xmlElement)
89 {
90 XmlSerializationContext ctx;
91 return FromXml(xmlElement, ctx);
92 }
93 [nodiscard]
94 public Result<bool> FromXml(System.Xml.Element* xmlElement, XmlSerializationContext& ctx)
95 {
96 ScopedXmlBundleSetter scopedSetter(ctx, this);
97 Result<UniquePtr<System.XPath.NodeSet>> nodeSetResult = System.XPath.EvaluateToNodeSet("object", xmlElement);
98 if (nodeSetResult.Error())
99 {
100 return Result<bool>(ErrorId(nodeSetResult.GetErrorId()));
101 }
102 System.XPath.NodeSet* nodeSet = nodeSetResult.Value().Get();
103 int n = nodeSet->Count();
104 for (int i = 0; i < n; ++i;)
105 {
106 System.Xml.Node* node = nodeSet->GetNode(i);
107 if (node->IsElementNode())
108 {
109 System.Xml.Element* element = cast<System.Xml.Element*>(node);
110 string classIdAttr = element->GetAttribute("classId");
111 if (!classIdAttr.IsEmpty())
112 {
113 auto classIdResult = ParseInt(classIdAttr);
114 if (classIdResult.Error())
115 {
116 return Result<bool>(ErrorId(classIdResult.GetErrorId()));
117 }
118 int classId = classIdResult.Value();
119 Result<XmlSerializable*> serializableResult = XmlClassRegistry.Instance().Create(classId);
120 if (serializableResult.Error())
121 {
122 return Result<bool>(ErrorId(serializableResult.GetErrorId()));
123 }
124 XmlSerializable* serializable = serializableResult.Value();
125 auto result = serializable->FromXml(element, ctx);
126 if (result.Error())
127 {
128 return result;
129 }
130 Add(serializable);
131 }
132 else
133 {
134 int errorId = AllocateError("object element has no class id");
135 return Result<bool>(ErrorId(errorId));
136 }
137 }
138 else
139 {
140 int errorId = AllocateError("XML element expected");
141 return Result<bool>(ErrorId(errorId));
142 }
143 }
144 auto resolveResult = Resolve(ctx);
145 if (resolveResult.Error()) return resolveResult;
146 return Result<bool>(true);
147 }
148 public void AddPtr(XmlPtrBase* ptr)
149 {
150 ptrs.Add(ptr);
151 }
152 [nodiscard]
153 public Result<bool> Resolve(XmlSerializationContext& ctx)
154 {
155 for (XmlPtrBase* ptrBase : ptrs)
156 {
157 XmlSerializable* s = Get(ptrBase->TargetObjectId());
158 if (s == null && ctx.GetFlag(XmlSerializationFlags.failOnNotFoundObjects))
159 {
160 auto objectIdResult = ToString(ptrBase->TargetObjectId());
161 string objectIdStr;
162 if (!objectIdResult.Error())
163 {
164 objectIdStr = objectIdResult.Value();
165 }
166 int errorId = AllocateError("XmlBundle.Resolve: object with id " + objectIdStr + " not found from xmlBundle");
167 return Result<bool>(ErrorId(errorId));
168 }
169 ptrBase->SetPtr(s);
170 }
171 return Result<bool>(true);
172 }
173 public void ClearPtrs()
174 {
175 ptrs.Clear();
176 }
177 public XmlSerializable* Get(int index) const
178 {
179 return objects[index];
180 }
181 public XmlSerializable* Release(int index)
182 {
183 return ownedObjects[index].Release();
184 }
185 public XmlSerializable* Get(const Uuid& objectId) const
186 {
187 auto it = objectMap.Find(objectId);
188 if (it != objectMap.End())
189 {
190 return it->second;
191 }
192 else
193 {
194 return null;
195 }
196 }
197 public const Map<Uuid, XmlSerializable*>& ObjectMap() const
198 {
199 return objectMap;
200 }
201 private List<XmlSerializable*> objects;
202 private List<UniquePtr<XmlSerializable>> ownedObjects;
203 private List<XmlPtrBase*> ptrs;
204 private Map<Uuid, XmlSerializable*> objectMap;
205 }
206 }