Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
XmlCodec.cs
1using System;
3using System.IO;
4using System.Runtime.ExceptionServices;
5using System.Text;
6using System.Threading.Tasks;
7using System.Xml;
8using Waher.Events;
12
14{
19 {
23 public XmlCodec()
24 {
25 }
26
30 public const string DefaultContentType = "text/xml";
31
35 public const string SchemaContentType = "application/xml";
36
40 public static readonly string[] XmlContentTypes = new string[]
41 {
44 };
45
49 public static readonly string[] XmlFileExtensions = new string[]
50 {
51 "xml",
52 "xsd"
53 };
54
58 public string[] ContentTypes => XmlContentTypes;
59
64
71 public bool Decodes(string ContentType, out Grade Grade)
72 {
73 if (Array.IndexOf(XmlContentTypes, ContentType) >= 0)
74 {
75 Grade = Grade.Excellent;
76 return true;
77 }
78 else if (ContentType.StartsWith("application/") && ContentType.EndsWith("+xml"))
79 {
80 Grade = Grade.Barely;
81 return true;
82 }
83 else
84 {
85 Grade = Grade.NotAtAll;
86 return false;
87 }
88 }
89
100 public Task<ContentResponse> DecodeAsync(string ContentType, byte[] Data, Encoding Encoding,
101 KeyValuePair<string, string>[] Fields, Uri BaseUri, ICodecProgress Progress)
102 {
103 XmlDocument Doc;
104
105 if (Encoding is null)
106 {
107 Doc = new XmlDocument()
108 {
109 PreserveWhitespace = true
110 };
111
112 using (MemoryStream ms = new MemoryStream(Data))
113 {
114 XmlReaderSettings Settings = new XmlReaderSettings()
115 {
116 CheckCharacters = false,
117 ConformanceLevel = ConformanceLevel.Document,
118 DtdProcessing = DtdProcessing.Ignore,
119 IgnoreComments = true,
120 IgnoreProcessingInstructions = true,
121 IgnoreWhitespace = false
122 };
123
124 using (XmlReader xr = XmlReader.Create(ms, Settings))
125 {
126 Doc.Load(xr);
127 }
128 }
129 }
130 else
131 {
132 string s = Strings.GetString(Data, Encoding);
133
134 try
135 {
136 Doc = XML.ParseXml(s, true);
137 }
138 catch (XmlException ex)
139 {
140 Doc = XML.ParseXml(XML.RepairXml(s), true);
141
142 Log.Warning("Invalid XML was received and repaired.",
143 new KeyValuePair<string, object>("BaseUri", BaseUri?.OriginalString),
144 new KeyValuePair<string, object>("Error", ex.Message));
145 }
146 }
147
148 return Task.FromResult(new ContentResponse(ContentType, Doc, Data));
149 }
150
157 public bool TryGetContentType(string FileExtension, out string ContentType)
158 {
159 switch (FileExtension.ToLower())
160 {
161 case "xml":
162 ContentType = DefaultContentType;
163 return true;
164
165 case "xsd":
166 ContentType = SchemaContentType;
167 return true;
168
169 default:
170 ContentType = string.Empty;
171 return false;
172 }
173 }
174
181 public bool TryGetFileExtension(string ContentType, out string FileExtension)
182 {
183 ContentType = ContentType.ToLower();
184
185 switch (ContentType.ToLower())
186 {
188 FileExtension = "xml";
189 return true;
190
192 FileExtension = "xsd";
193 return true;
194
195 default:
196 if (ContentType.StartsWith("application/") && ContentType.EndsWith("+xml"))
197 {
198 FileExtension = ContentType.Substring(12, ContentType.Length - 4 - 12);
199 return true;
200 }
201 else
202 {
203 FileExtension = string.Empty;
204 return false;
205 }
206 }
207 }
208
216 public bool Encodes(object Object, out Grade Grade, params string[] AcceptedContentTypes)
217 {
218 if ((Object is XmlDocument || Object is XmlElement || Object is NamedDictionary<string, object>) &&
219 InternetContent.IsAccepted(XmlContentTypes, AcceptedContentTypes))
220 {
221 Grade = Grade.Ok;
222 return true;
223 }
224
225 if ((Object is NamedDictionary<string, IElement>) &&
226 InternetContent.IsAccepted(XmlContentTypes, AcceptedContentTypes))
227 {
228 Grade = Grade.Barely;
229 return true;
230 }
231
232 Grade = Grade.NotAtAll;
233 return false;
234 }
235
244 public Task<ContentResponse> EncodeAsync(object Object, Encoding Encoding, ICodecProgress Progress, params string[] AcceptedContentTypes)
245 {
246 if (InternetContent.IsAccepted(XmlContentTypes, out string ContentType, AcceptedContentTypes))
247 {
248 if (Object is XmlDocument Doc)
249 return EncodeXmlAsync(Doc, Encoding, ContentType);
250 else if (Object is XmlElement E)
251 {
252 Doc = new XmlDocument();
253 Doc.AppendChild(Doc.ImportNode(E, true));
254 return EncodeXmlAsync(Doc, Encoding, ContentType);
255 }
256 else if (Object is NamedDictionary<string, object> Obj)
257 {
258 string Xml = XML.Encode(Obj);
259 return EncodeXmlAsync(Xml, Encoding, ContentType);
260 }
261 else if (Object is NamedDictionary<string, IElement> Obj2)
262 {
263 string Xml = XML.Encode(NamedDictionary<string, object>.ToNamedDictionary(Obj2));
264 return EncodeXmlAsync(Xml, Encoding, ContentType);
265 }
266 }
267
268 return Task.FromResult(new ContentResponse(new ArgumentException("Unable to encode object, or content type not accepted.", nameof(Object))));
269 }
270
278 public static Task<ContentResponse> EncodeXmlAsync(XmlDocument Xml, Encoding Encoding, string ContentType)
279 {
280 MemoryStream ms = null;
281 XmlWriterSettings Settings;
282 XmlWriter w = null;
283 byte[] Result;
284
285 try
286 {
287 ms = new MemoryStream();
288 Settings = XML.WriterSettings(false, false);
289
290 if (Encoding is null)
291 {
292 Settings.Encoding = Encoding.UTF8;
293 ContentType += "; charset=utf-8";
294 }
295 else
296 {
297 Settings.Encoding = Encoding;
298 ContentType += "; charset=" + Encoding.WebName;
299 }
300
301 w = XmlWriter.Create(ms, Settings);
302
303 Xml.Save(w);
304 w.Flush();
305
306 Result = ms.ToArray();
307 }
308 finally
309 {
310 w?.Dispose();
311 ms?.Dispose();
312 }
313
314 return Task.FromResult(new ContentResponse(ContentType, Xml, Result));
315 }
316
324 public static Task<ContentResponse> EncodeXmlAsync(string Xml, Encoding Encoding, string ContentType)
325 {
326 byte[] Bin;
327
328 if (Encoding is null)
329 {
330 ContentType += "; charset=utf-8";
331 Bin = Encoding.UTF8.GetBytes(Xml);
332 }
333 else
334 {
335 ContentType += "; charset=" + Encoding.WebName;
336 Bin = Encoding.GetBytes(Xml);
337 }
338
339 return Task.FromResult(new ContentResponse(ContentType, Xml, Bin));
340 }
341 }
342}
Contains information about a response to a content request.
Static class managing encoding and decoding of internet content.
static bool IsAccepted(string ContentType, params string[] AcceptedContentTypes)
Checks if a given content type is acceptable.
A Named dictionary is a dictionary, with a local name and a namespace. Use it to return content that ...
XML encoder/decoder.
Definition: XmlCodec.cs:19
bool TryGetFileExtension(string ContentType, out string FileExtension)
Tries to get the file extension of an item, given its Content-Type.
Definition: XmlCodec.cs:181
string[] ContentTypes
Supported content types.
Definition: XmlCodec.cs:58
static readonly string[] XmlContentTypes
XML content types.
Definition: XmlCodec.cs:40
Task< ContentResponse > EncodeAsync(object Object, Encoding Encoding, ICodecProgress Progress, params string[] AcceptedContentTypes)
Encodes an object.
Definition: XmlCodec.cs:244
static readonly string[] XmlFileExtensions
XML file extensions.
Definition: XmlCodec.cs:49
Task< ContentResponse > DecodeAsync(string ContentType, byte[] Data, Encoding Encoding, KeyValuePair< string, string >[] Fields, Uri BaseUri, ICodecProgress Progress)
Decodes an object.
Definition: XmlCodec.cs:100
const string DefaultContentType
Default content type for XML documents.
Definition: XmlCodec.cs:30
string[] FileExtensions
Supported file extensions.
Definition: XmlCodec.cs:63
const string SchemaContentType
Default content type for XML schema documents.
Definition: XmlCodec.cs:35
static Task< ContentResponse > EncodeXmlAsync(XmlDocument Xml, Encoding Encoding, string ContentType)
Encodes an XML Document.
Definition: XmlCodec.cs:278
bool Decodes(string ContentType, out Grade Grade)
If the decoder decodes an object with a given content type.
Definition: XmlCodec.cs:71
static Task< ContentResponse > EncodeXmlAsync(string Xml, Encoding Encoding, string ContentType)
Encodes an XML Document.
Definition: XmlCodec.cs:324
XmlCodec()
XML encoder/decoder.
Definition: XmlCodec.cs:23
bool Encodes(object Object, out Grade Grade, params string[] AcceptedContentTypes)
If the encoder encodes a given object.
Definition: XmlCodec.cs:216
bool TryGetContentType(string FileExtension, out string ContentType)
Tries to get the content type of an item, given its file extension.
Definition: XmlCodec.cs:157
Helps with common XML-related tasks.
Definition: XML.cs:21
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:29
static string RepairXml(string Xml)
Repairs broker XML by reencoding any illegal characters.
Definition: XML.cs:1840
static XmlWriterSettings WriterSettings(bool Indent, bool OmitXmlDeclaration)
Gets an XML writer settings object.
Definition: XML.cs:1351
static XmlDocument ParseXml(string Xml)
Parses an XML Document from its string representation.
Definition: XML.cs:713
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:14
static void Warning(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a warning event.
Definition: Log.cs:576
Static class managing binary representations of strings.
Definition: Strings.cs:10
static string GetString(byte[] Data, int Offset, int Count, Encoding DefaultEncoding)
Gets a string from its binary representation, taking any Byte Order Mark (BOM) into account.
Definition: Strings.cs:148
Interface for reporting progress about an encoding or decoding.
Basic interface for Internet Content decoders. A class implementing this interface and having a defau...
Basic interface for Internet Content encoders. A class implementing this interface and having a defau...
Grade
Grade enumeration
Definition: Grade.cs:7