Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ToonOutput.cs
1using System;
3using System.Globalization;
4using System.Text;
6
7namespace Waher.Content.Toon
8{
12 public class ToonOutput
13 {
14 private readonly StringBuilder output = new StringBuilder();
15 private char delimiterCharacter = ',';
16 private char indentCharacter = '\t';
17 private int indentCharacterCount = 1;
18 private int keyFoldingDepth = int.MaxValue;
19 private bool standardIndentation = true;
20 private bool standardDelimiter = true;
21 private bool keyFolding = true;
22 private bool empty = true;
23 private bool lastIsListItem = false;
24
28 public ToonOutput()
29 : this(new StringBuilder())
30 {
31 }
32
37 public ToonOutput(StringBuilder Output)
38 {
39 this.output = Output;
40 }
41
45 public char IndentCharacter
46 {
47 get => this.indentCharacter;
48 set
49 {
50 this.indentCharacter = value;
51 this.standardIndentation =
52 this.indentCharacter == '\t' &&
53 this.indentCharacterCount == 1;
54 }
55 }
56
61 {
62 get => this.indentCharacterCount;
63 set
64 {
65 if (value <= 0)
66 {
67 throw new ArgumentException("Indent character count must be a positive integer.",
68 nameof(this.IndentCharacterCount));
69 }
70
71 this.indentCharacterCount = value;
72 this.standardIndentation =
73 this.indentCharacter == '\t' &&
74 this.indentCharacterCount == 1;
75 }
76 }
77
81 public bool StandardIndentation => this.standardIndentation;
82
86 public bool StandardDelimiter => this.standardDelimiter;
87
91 public StringBuilder Output => this.output;
92
96 public bool Empty => this.empty;
97
102 {
103 get => this.delimiterCharacter;
104 set
105 {
106 this.delimiterCharacter = value;
107 this.standardDelimiter = this.delimiterCharacter == ',';
108 }
109 }
110
114 public bool KeyFolding
115 {
116 get => this.keyFolding;
117 set
118 {
119 this.keyFolding = value;
120
121 if (value && this.keyFoldingDepth <= 1)
122 this.keyFoldingDepth = 2;
123 }
124 }
125
131 {
132 get => this.keyFoldingDepth;
133 set
134 {
135 if (value < 2)
136 this.keyFolding = false;
137
138 this.keyFoldingDepth = value;
139 }
140 }
141
146 public void Indent(int Level)
147 {
148 this.empty = false;
149
150 if (this.standardIndentation)
151 JSON.Indent(this.output, Level);
152 else
153 {
154 Level *= this.indentCharacterCount;
155
156 while (Level-- > 0)
157 this.output.Append(this.indentCharacter);
158 }
159
160 this.lastIsListItem = false;
161 }
162
164 public override string ToString()
165 {
166 return this.output.ToString();
167 }
168
173 public void Append(char Value)
174 {
175 this.empty = false;
176 this.lastIsListItem = false;
177 this.output.Append(Value);
178 }
179
184 public void Append(string Value)
185 {
186 this.empty = false;
187 this.lastIsListItem = false;
188 this.output.Append(Value);
189 }
190
194 public void AppendDelimiter()
195 {
196 this.empty = false;
197 this.lastIsListItem = false;
198 this.output.Append(this.delimiterCharacter);
199 }
200
204 public void AppendListItem()
205 {
206 this.output.Append('-');
207 this.lastIsListItem = true;
208 }
209
213 public void AppendLine()
214 {
215 this.empty = false;
216 this.lastIsListItem = false;
217 this.output.Append('\n');
218 }
219
225 public void AppendEncoded(string s, bool InObject)
226 {
227 this.Append(this.Encode(s, InObject));
228 }
229
236 public string Encode(string s, bool InObject)
237 {
238 switch (s)
239 {
240 case null:
241 case "":
242 return "\"\"";
243
244 case "true":
245 return "\"true\"";
246
247 case "false":
248 return "\"false\"";
249
250 case "null":
251 return "\"null\"";
252
253 case "-":
254 return "\"-\"";
255
256 default:
257 if (double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out _))
258 return "\"" + s + "\"";
259
261 return "\"" + JSON.Encode(s) + "\"";
262
263 if (s.StartsWith("[") ||
264 s.StartsWith("{") ||
265 s.IndexOf(this.delimiterCharacter) >= 0)
266 {
267 return "\"" + s + "\"";
268 }
269
270 if (InObject)
271 {
272 if (s.IndexOfAny(objectKeyCharacters) >= 0)
273 return "\"" + s + "\"";
274 }
275 else
276 {
277 if (s.IndexOfAny(keyCharacters) >= 0)
278 return "\"" + s + "\"";
279 }
280
281 return s;
282 }
283 }
284
285 private static readonly char[] objectKeyCharacters = new char[] { ':', '-', ' ' };
286 private static readonly char[] keyCharacters = new char[] { ':', '-' };
287
294 public void AppendAsObject(IEnumerable<KeyValuePair<string, object>> Object,
295 int? Indent, Func<string, bool> MemberExists)
296 {
297 bool MultiRow = Indent.HasValue;
298 bool First = true;
299
300 if (MultiRow)
301 Indent++;
302
303 if (!(Object is null))
304 {
305 foreach (KeyValuePair<string, object> Member in Object)
306 {
307 if (!MultiRow)
308 {
309 if (!MultiRow)
310 {
311 if (First)
312 First = false;
313 else
314 this.AppendDelimiter();
315 }
316 }
317
318 this.AppendMember(Member.Key, Member.Value, Indent, MemberExists);
319 }
320 }
321
322 if (MultiRow)
323 {
324 Indent--;
325
326 if (!First && Indent.Value > 0)
327 {
328 this.AppendLine();
329 this.Indent(Indent.Value);
330 }
331 }
332 }
333
340 public void AppendAsObject(IEnumerable<KeyValuePair<string, IElement>> Object,
341 int? Indent, Func<string, bool> MemberExists)
342 {
343 bool MultiRow = Indent.HasValue;
344 bool First = true;
345
346 if (MultiRow)
347 Indent++;
348
349 if (!(Object is null))
350 {
351 foreach (KeyValuePair<string, IElement> Member in Object)
352 {
353 if (!MultiRow)
354 {
355 if (First)
356 First = false;
357 else
358 this.AppendDelimiter();
359 }
360
361 this.AppendMember(Member.Key, Member.Value.AssociatedObjectValue, Indent,
362 MemberExists);
363 }
364 }
365
366 if (MultiRow)
367 {
368 Indent--;
369
370 if (!First && Indent.Value > 0)
371 {
372 this.AppendLine();
373 this.Indent(Indent.Value);
374 }
375 }
376 }
377
385 public void AppendMember(string Name, object Value, int? Indent,
386 Func<string, bool> MemberExists)
387 {
388 bool AppendSpaces = Indent.HasValue;
389
390 if (AppendSpaces && (Indent.Value > 0 || (Indent.Value == 0 && !this.empty)))
391 {
392 if (this.lastIsListItem)
393 {
394 this.output.Append(' ');
395 this.lastIsListItem = false;
396 }
397 else
398 {
399 this.AppendLine();
400 this.Indent(Indent.Value);
401 }
402 }
403
404 if (Value is null)
405 {
406 this.AppendEncoded(Name, true);
407
408 if (AppendSpaces)
409 this.Append(": ");
410 else
411 this.Append(':');
412
413 this.Append("null");
414 return;
415 }
416
417 IToonEncoder Encoder = TOON.GetEncoder(Value);
418
419 if (this.keyFolding &&
420 Encoder.EncodesAsObject(Value) &&
421 this.Encode(Name, true) == Name)
422 {
423 string OriginalName = Name;
424 object OriginalValue = Value;
425 IToonEncoder OriginalEncoder = Encoder;
426 int Depth = 1;
427
428 while (Depth < this.keyFoldingDepth &&
429 Encoder.CanFold(Value, out string FoldedName, out object FoldedValue) &&
430 this.Encode(FoldedName, true) == FoldedName)
431 {
432 Name += "." + FoldedName;
433 Value = FoldedValue;
434 Encoder = TOON.GetEncoder(Value);
435 Depth++;
436
437 if (!Encoder.EncodesAsObject(Value))
438 break;
439 }
440
441 if (Depth > 1 && MemberExists(Name))
442 {
443 this.keyFolding = false;
444
445 this.AppendEncoded(OriginalName, true);
446
447 if (OriginalEncoder.EncodesAsVector(OriginalValue))
448 OriginalEncoder.Encode(OriginalValue, Indent, this, BracketsMode.Count);
449 else
450 {
451 if (OriginalEncoder.EncodesMultipleRows || !AppendSpaces)
452 this.Append(':');
453 else
454 this.Append(": ");
455
456 OriginalEncoder.Encode(OriginalValue, Indent, this);
457 }
458
459 this.keyFolding = true;
460 return;
461 }
462 else if (Depth == this.keyFoldingDepth)
463 {
464 this.keyFolding = false;
465
466 this.AppendEncoded(Name, true);
467
468 if (Encoder.EncodesAsVector(Value))
469 Encoder.Encode(Value, Indent, this, BracketsMode.Count);
470 else
471 {
472 if (Encoder.EncodesMultipleRows || !AppendSpaces)
473 this.Append(':');
474 else
475 this.Append(": ");
476
477 Encoder.Encode(Value, Indent, this);
478 }
479
480 this.keyFolding = true;
481 return;
482 }
483 }
484
485 this.AppendEncoded(Name, true);
486
487 if (Encoder.EncodesAsVector(Value))
488 Encoder.Encode(Value, Indent, this, BracketsMode.Count);
489 else
490 {
491 if (Encoder.EncodesMultipleRows || !AppendSpaces)
492 this.Append(':');
493 else
494 this.Append(": ");
495
496 Encoder.Encode(Value, Indent, this);
497 }
498 }
499
500 }
501}
Helps with common JSON-related tasks.
Definition: JSON.cs:16
static void Indent(StringBuilder Output, int NrTabs)
Appends an indentation to a string builder using tab characters.
Definition: JSON.cs:762
static string Encode(string s)
Encodes a string for inclusion in JSON.
Definition: JSON.cs:537
static bool ContainsEscapeCharacters(string s)
If a string contains characters that need to be escaped to be encoded into JSON.
Definition: JSON.cs:548
Helps with common TOON-related tasks.
Definition: TOON.cs:12
static IToonEncoder GetEncoder(object Value)
Gets a TOON encoder for a given object, by looking up the best available encoder, based on the type o...
Definition: TOON.cs:79
TOON Output builder
Definition: ToonOutput.cs:13
void AppendMember(string Name, object Value, int? Indent, Func< string, bool > MemberExists)
Appends a member of an object as TOON.
Definition: ToonOutput.cs:385
void Append(string Value)
Appends a string to the output.
Definition: ToonOutput.cs:184
int KeyFoldingDepth
Maximum depth for key folding. Default is int.MaxValue, meaning that all keys will be folded,...
Definition: ToonOutput.cs:131
string Encode(string s, bool InObject)
Encodes a string for inclusion in TOON.
Definition: ToonOutput.cs:236
void AppendLine()
Appends a new-line character to the output.
Definition: ToonOutput.cs:213
void AppendListItem()
Appends a list item character to the output (hyphen).
Definition: ToonOutput.cs:204
void AppendEncoded(string s, bool InObject)
Encodes a string, if necessary, and appends it to the output.
Definition: ToonOutput.cs:225
void AppendDelimiter()
Appends the delimiter character to the output.
Definition: ToonOutput.cs:194
bool KeyFolding
If key-folding is enabled (safe-mode). Default is true.
Definition: ToonOutput.cs:115
char IndentCharacter
Indentation character to use. Default is the TAB character.
Definition: ToonOutput.cs:46
int IndentCharacterCount
Indentation character to use. Default is the TAB character.
Definition: ToonOutput.cs:61
ToonOutput(StringBuilder Output)
TOON Output builder
Definition: ToonOutput.cs:37
StringBuilder Output
String builder where TOON output is appended.
Definition: ToonOutput.cs:91
bool Empty
If no output has been appended.
Definition: ToonOutput.cs:96
bool StandardIndentation
If the indentation is standard (one TAB character per step).
Definition: ToonOutput.cs:81
override string ToString()
Definition: ToonOutput.cs:164
void AppendAsObject(IEnumerable< KeyValuePair< string, IElement > > Object, int? Indent, Func< string, bool > MemberExists)
Appends an object as a TOON object.
Definition: ToonOutput.cs:340
void Append(char Value)
Appends a character to the output.
Definition: ToonOutput.cs:173
void Indent(int Level)
Appends an indentation to the output, according to the level specified.
Definition: ToonOutput.cs:146
ToonOutput()
TOON Output builder
Definition: ToonOutput.cs:28
void AppendAsObject(IEnumerable< KeyValuePair< string, object > > Object, int? Indent, Func< string, bool > MemberExists)
Appends an object as a TOON object.
Definition: ToonOutput.cs:294
char DelimiterCharacter
Delimiter character to use. Default is the comma character.
Definition: ToonOutput.cs:102
bool StandardDelimiter
If the standard delimiter is used.
Definition: ToonOutput.cs:86
Interface for encoding objects of certain types to TOON.
Definition: IToonEncoder.cs:33
bool EncodesMultipleRows
If the encoder encodes values into multiple rows.
Definition: IToonEncoder.cs:45
void Encode(object Object, int? Indent, ToonOutput Toon)
Encodes the Object to TOON.
bool EncodesAsVector(object Value)
If the encoder encodes a value as a vector.
bool EncodesAsObject(object Value)
If the encoder encodes a value as an object.
bool CanFold(object Object, out string FoldedName, out object FoldedValue)
Checks if an object can be folded to a shorter representation, and if so, returns the folded name and...
Definition: ImplTypes.g.cs:58
BracketsMode
How brackets should be handled when encoding vectors.
Definition: IToonEncoder.cs:12