Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
RecordSet.cs
1using System;
3using System.Text;
4using System.Threading.Tasks;
5using System.Xml;
11using Waher.Script;
17
19{
23 public class RecordSet : Parameter
24 {
25 private Parameter[] recordDefinition = null;
26 private Parameter[][] records = null;
27 private int? minRecords = null;
28 private int? maxRecords = null;
29
33 [DefaultValueNull]
34 public int? MinRecords
35 {
36 get => this.minRecords;
37 set => this.minRecords = value;
38 }
39
43 [DefaultValueNull]
44 public int? MaxRecords
45 {
46 get => this.maxRecords;
47 set => this.maxRecords = value;
48 }
49
53 public override object ObjectValue => string.Empty;
54
58 public override string StringValue
59 {
60 get => string.Empty;
61 set => throw new Exception("Record set parameters are set via the records or the record definition.");
62 }
63
67 public override void ClearValue()
68 {
69 ClearValues(this.recordDefinition);
70
71 if (this.records is null)
72 return;
73
74 foreach (Parameter[] Record in this.records)
75 ClearValues(Record);
76 }
77
78 private static void ClearValues(Parameter[] Parameters)
79 {
80 if (Parameters is null)
81 return;
82
83 foreach (Parameter P in Parameters)
84 P.ClearValue();
85 }
86
87
93 public override async Task ToMarkdown(MarkdownOutput Markdown, MarkdownOutputState State)
94 {
95 Markdown.AppendLine();
96 Markdown.AppendLine();
97
98 Table.NotesRef NotesRef = new Table.NotesRef();
100 {
101 Language = State.Language,
102 Contract = State.Contract,
103 Level = 1,
104 Indentation = 0
105 };
106
107 if (!(this.recordDefinition is null))
108 {
109 foreach (Parameter P in this.recordDefinition)
110 await Table.ToMarkdownCell(Markdown, State2, P.Descriptions, NotesRef);
111
112 Markdown.AppendLine(" |");
113 Markdown.Append('|');
114
115 foreach (Parameter P in this.recordDefinition)
116 Table.ToMarkdown(Markdown, P.CellAlignment, false);
117
118 Markdown.AppendLine();
119 }
120
121 if (!(this.records is null))
122 {
123 foreach (Parameter[] Record in this.records)
124 {
125 foreach (Parameter P in Record)
126 {
127 await Table.ToMarkdownCell(Markdown, State2, P, NotesRef);
128 Markdown.Append(' ');
129 }
130
131 Markdown.AppendLine("|");
132 }
133 }
134
135 Table.ToMarkdown(Markdown, State, NotesRef.Notes);
136 }
137
142 public override void Serialize(StringBuilder Xml)
143 {
144 Xml.Append("<recordSet");
145
146 if (!string.IsNullOrEmpty(this.Expression))
147 {
148 Xml.Append(" exp=\"");
149 Xml.Append(XML.Encode(this.Expression.Normalize(NormalizationForm.FormC)));
150 Xml.Append('"');
151 }
152
153 if (this.maxRecords.HasValue)
154 {
155 Xml.Append(" maxRecords=\"");
156 Xml.Append(this.maxRecords.Value.ToString());
157 Xml.Append('"');
158 }
159
160 if (this.minRecords.HasValue)
161 {
162 Xml.Append(" minRecords=\"");
163 Xml.Append(this.minRecords.Value.ToString());
164 Xml.Append('"');
165 }
166
167 Xml.Append(" name=\"");
168 Xml.Append(XML.Encode(this.Name.Value.Normalize(NormalizationForm.FormC)));
169 Xml.Append("\">");
170
171 if (!(this.Descriptions is null))
172 {
173 foreach (HumanReadableText Description in this.Descriptions)
174 Description.Serialize(Xml, "description", null);
175 }
176
177 Xml.Append("<recordDefinition>");
178
179 if (!(this.recordDefinition is null))
180 {
181 foreach (Parameter P in this.recordDefinition)
182 P.Serialize(Xml);
183 }
184
185 Xml.Append("</recordDefinition>");
186
187 if (!(this.records is null))
188 {
189 foreach (Parameter[] Record in this.records)
190 {
191 Xml.Append("<record>");
192
193 foreach (Parameter P in Record)
194 {
196 P.Serialize(Xml);
197 }
198
199 Xml.Append("</record>");
200 }
201 }
202
203 Xml.Append("</recordSet>");
204 }
205
213 public override async Task<string> IsParameterValid(Variables Variables,
215 {
216 if (!this.minRecords.HasValue)
217 return "Minimum number of records missing.";
218
219 if (!this.maxRecords.HasValue)
220 return "Maximum number of records missing.";
221
222 if (this.minRecords.Value > 0 && (this.records is null || this.records.Length < this.minRecords.Value))
223 return "Too few records defined.";
224
225 if (!(this.records is null) && this.records.Length > this.maxRecords.Value)
226 return "Too many records defined.";
227
228 if (!(this.records is null))
229 {
230 foreach (Parameter[] Record in this.records)
231 {
232 if (Record.Length != (this.recordDefinition?.Length ?? 0))
233 return "Record length mismatch.";
234
235 int i, c = Record.Length;
236
237 for (i = 0; i < c; i++)
238 {
239 Parameter Item = Record[i];
240
241 if (!Item.CopyValidationRules(this.recordDefinition[i]))
242 return "Record element type mismatch.";
243
244 string Error = await Item.IsParameterValid(Variables, Legal, Profiler);
245
246 if (!string.IsNullOrEmpty(Error))
247 return Error;
248 }
249 }
250 }
251
252 return await base.IsParameterValid(Variables, Legal, Profiler);
253 }
254
261 {
263
264 if (!(this.records is null))
265 {
266 Variables RecordVariables = null;
267
268 foreach (Parameter[] Record in this.records)
269 {
270 if (RecordVariables is null)
271 RecordVariables = new Variables();
272 else
273 RecordVariables.Clear();
274
275 foreach (Parameter P in Record)
276 P.Populate(RecordVariables, Profiler);
277
278 Dictionary<string, IElement> Items = new Dictionary<string, IElement>();
279
280 foreach (Variable Variable in RecordVariables)
282
283 Records.Add(new ObjectValue(Items));
284 }
285 }
286
287 Variables[this.Name] = new ObjectVector(Records.ToArray());
288 }
289
295 public override bool UpdateRequiresReview(Parameter UpdatedParameter)
296 {
297 if (!(UpdatedParameter is RecordSet UpdatedRecordSet))
298 return true;
299
300 int i, j, c, d;
301
302 if (this.minRecords != UpdatedRecordSet.minRecords ||
303 this.maxRecords != UpdatedRecordSet.maxRecords ||
304 (c = this.recordDefinition?.Length ?? 0) != (UpdatedRecordSet.recordDefinition?.Length ?? 0) ||
305 (d = this.records?.Length ?? 0) != (UpdatedRecordSet.records?.Length ?? 0) ||
306 base.UpdateRequiresReview(UpdatedParameter))
307 {
308 return true;
309 }
310
311 for (i = 0; i < c; i++)
312 {
313 if (this.recordDefinition[i].UpdateRequiresReview(UpdatedRecordSet.recordDefinition[i]))
314 return true;
315 }
316
317 for (j = 0; j < d; j++)
318 {
319 Parameter[] Record = this.records[j];
320 if (Record.Length != c)
321 return true;
322
323 Parameter[] UpdatedRecord = UpdatedRecordSet.records[j];
324 if (UpdatedRecord.Length != c)
325 return true;
326
327 for (i = 0; i < c; i++)
328 {
329 if (Record[i].UpdateRequiresReview(UpdatedRecord[i]))
330 return true;
331 }
332 }
333
334 return false;
335 }
336
342 public override Parameter TryCreateNew(object NewValue)
343 {
344 return null;
345 }
346
352 public override async Task<bool> Import(XmlElement Xml)
353 {
354 this.minRecords = Xml.HasAttribute("minRecords") ? XML.Attribute(Xml, "minRecords", 0) : (int?)null;
355 this.maxRecords = Xml.HasAttribute("maxRecords") ? XML.Attribute(Xml, "maxRecords", 0) : (int?)null;
356
357 ChunkedList<Parameter> RecordDefinitions = new ChunkedList<Parameter>();
359 ChunkedList<Parameter> Record = null;
360
361 foreach (XmlNode N in Xml.ChildNodes)
362 {
363 if (!(N is XmlElement E))
364 continue;
365
366 switch (E.LocalName)
367 {
368 case "recordDefinition":
369 if (!await Contract.ParseParameters(E, RecordDefinitions))
370 return false;
371 break;
372
373 case "record":
374 if (Record is null)
375 Record = new ChunkedList<Parameter>();
376 else
377 Record.Clear();
378
379 if (!await Contract.ParseParameters(E, Record))
380 return false;
381
382 Records.Add(Record.ToArray());
383 break;
384 }
385 }
386
387 return await base.Import(Xml);
388 }
389
395 protected override bool IsChildLocalNameRecognized(string LocalName)
396 {
397 switch (LocalName)
398 {
399 case "recordDefinition":
400 case "record":
401 return true;
402
403 default:
404 return base.IsChildLocalNameRecognized(LocalName);
405 }
406 }
407
412
418 public override bool CopyValidationRules(Parameter From)
419 {
420 if (!(From is RecordSet Typed))
421 return false;
422
423 this.recordDefinition = Typed.recordDefinition;
424 this.records = Typed.records;
425 this.minRecords = Typed.minRecords;
426 this.maxRecords = Typed.maxRecords;
427
428 return base.CopyValidationRules(From);
429 }
430
434 public override void ClearValidationRules()
435 {
436 this.recordDefinition = null;
437 this.records = null;
438 this.minRecords = null;
439 this.maxRecords = null;
440
441 base.ClearValidationRules();
442 }
443
444 }
445}
Helps with common XML-related tasks.
Definition: XML.cs:21
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:1062
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:29
A chunked list is a linked list of chunks of objects of type T .
Definition: ChunkedList.cs:54
void Add(T Item)
Adds an item to the collection.
Definition: ChunkedList.cs:272
T[] ToArray()
Returns an array containing all elements of the collection.
Class that keeps track of events and timing.
Definition: Profiler.cs:68
Class that keeps track of events and timing for one thread.
Class managing a script expression.
Definition: Expression.cs:41
static readonly StringValue Empty
The empty string.
Definition: StringValue.cs:212
Contains information about a variable.
Definition: Variable.cs:10
string Name
Name of variable.
Definition: Variable.cs:78
IElement ValueElement
Value element of variable.
Definition: Variable.cs:83
Collection of variables.
Definition: Variables.cs:25
TextAlignment
Text alignment of contents.