Welcome to mirror list, hosted at ThFree Co, Russian Federation.

XmlWriterAsync.cs « Core « Xml « System « System.Xml « referencesource « class « mcs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: e799402b01efc6e3d7ae86d997dfa47b14c1923e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525

using System.Threading.Tasks;

using System;
using System.IO;
using System.Text;
#if !SILVERLIGHT
using System.Xml.XPath;
#endif
using System.Xml.Schema;
using System.Diagnostics;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.Versioning;

namespace System.Xml {

    // Represents a writer that provides fast non-cached forward-only way of generating XML streams containing XML documents 
    // that conform to the W3C Extensible Markup Language (XML) 1.0 specification and the Namespaces in XML specification.
    public abstract partial class XmlWriter : IDisposable {

        // Write methods
        // Writes out the XML declaration with the version "1.0".

        public virtual Task WriteStartDocumentAsync() {
            throw new NotImplementedException();
        }

        //Writes out the XML declaration with the version "1.0" and the speficied standalone attribute.

        public virtual Task WriteStartDocumentAsync(bool standalone) {
            throw new NotImplementedException();
        }

        //Closes any open elements or attributes and puts the writer back in the Start state.

        public virtual Task WriteEndDocumentAsync() {
            throw new NotImplementedException();
        }

        // Writes out the DOCTYPE declaration with the specified name and optional attributes.

        public virtual Task WriteDocTypeAsync(string name, string pubid, string sysid, string subset) {
            throw new NotImplementedException();
        }

        // Writes out the specified start tag and associates it with the given namespace and prefix.

        public virtual Task WriteStartElementAsync(string prefix, string localName, string ns) {
            throw new NotImplementedException();
        }

        // Closes one element and pops the corresponding namespace scope.

        public virtual Task WriteEndElementAsync() {
            throw new NotImplementedException();
        }

        // Closes one element and pops the corresponding namespace scope. Writes out a full end element tag, e.g. </element>.

        public virtual Task WriteFullEndElementAsync() {
            throw new NotImplementedException();
        }

        // Writes out the attribute with the specified LocalName, value, and NamespaceURI.
#if !SILVERLIGHT
#endif
        // Writes out the attribute with the specified prefix, LocalName, NamespaceURI and value.
        public Task WriteAttributeStringAsync(string prefix, string localName, string ns, string value) {
            Task task = WriteStartAttributeAsync(prefix, localName, ns);
            if (task.IsSuccess()) {
                return WriteStringAsync(value).CallTaskFuncWhenFinish(WriteEndAttributeAsync);
            }
            else {
                return WriteAttributeStringAsyncHelper(task, value);
            }
        }

        private async Task WriteAttributeStringAsyncHelper(Task task, string value) {
            await task.ConfigureAwait(false);
            await WriteStringAsync(value).ConfigureAwait(false);
            await WriteEndAttributeAsync().ConfigureAwait(false);
        }

        // Writes the start of an attribute.

        protected internal virtual Task WriteStartAttributeAsync(string prefix, string localName, string ns) {
            throw new NotImplementedException();
        }

        // Closes the attribute opened by WriteStartAttribute call.

        protected internal virtual Task WriteEndAttributeAsync() {
            throw new NotImplementedException();
        }

        // Writes out a <![CDATA[...]]>; block containing the specified text.

        public virtual Task WriteCDataAsync(string text) {
            throw new NotImplementedException();
        }

        // Writes out a comment <!--...-->; containing the specified text.

        public virtual Task WriteCommentAsync(string text) {
            throw new NotImplementedException();
        }

        // Writes out a processing instruction with a space between the name and text as follows: <?name text?>

        public virtual Task WriteProcessingInstructionAsync(string name, string text) {
            throw new NotImplementedException();
        }

        // Writes out an entity reference as follows: "&"+name+";".

        public virtual Task WriteEntityRefAsync(string name) {
            throw new NotImplementedException();
        }

        // Forces the generation of a character entity for the specified Unicode character value.

        public virtual Task WriteCharEntityAsync(char ch) {
            throw new NotImplementedException();
        }

        // Writes out the given whitespace.

        public virtual Task WriteWhitespaceAsync(string ws) {
            throw new NotImplementedException();
        }

        // Writes out the specified text content.

        public virtual Task WriteStringAsync(string text) {
            throw new NotImplementedException();
        }

        // Write out the given surrogate pair as an entity reference.

        public virtual Task WriteSurrogateCharEntityAsync(char lowChar, char highChar) {
            throw new NotImplementedException();
        }

        // Writes out the specified text content.

        public virtual Task WriteCharsAsync(char[] buffer, int index, int count) {
            throw new NotImplementedException();
        }

        // Writes raw markup from the given character buffer.

        public virtual Task WriteRawAsync(char[] buffer, int index, int count) {
            throw new NotImplementedException();
        }

        // Writes raw markup from the given string.

        public virtual Task WriteRawAsync(string data) {
            throw new NotImplementedException();
        }

        // Encodes the specified binary bytes as base64 and writes out the resulting text.

        public virtual Task WriteBase64Async(byte[] buffer, int index, int count) {
            throw new NotImplementedException();
        }

        // Encodes the specified binary bytes as binhex and writes out the resulting text.
        public virtual Task WriteBinHexAsync(byte[] buffer, int index, int count) {
            return BinHexEncoder.EncodeAsync(buffer, index, count, this);
        }

        // Flushes data that is in the internal buffers into the underlying streams/TextReader and flushes the stream/TextReader.

        public virtual Task FlushAsync() {
            throw new NotImplementedException();
        }

        // Scalar Value Methods

        // Writes out the specified name, ensuring it is a valid NmToken according to the XML specification 
        // (http://www.w3.org/TR/1998/REC-xml-19980210#NT-Name).
        public virtual Task WriteNmTokenAsync(string name) {
            if (name == null || name.Length == 0) {
                throw new ArgumentException(Res.GetString(Res.Xml_EmptyName));
            }
            return WriteStringAsync(XmlConvert.VerifyNMTOKEN(name, ExceptionType.ArgumentException));
        }

        // Writes out the specified name, ensuring it is a valid Name according to the XML specification
        // (http://www.w3.org/TR/1998/REC-xml-19980210#NT-Name).
        public virtual Task WriteNameAsync(string name) {
            return WriteStringAsync(XmlConvert.VerifyQName(name, ExceptionType.ArgumentException));
        }

        // Writes out the specified namespace-qualified name by looking up the prefix that is in scope for the given namespace.
        public virtual async Task WriteQualifiedNameAsync(string localName, string ns) {
            if (ns != null && ns.Length > 0) {
                string prefix = LookupPrefix(ns);
                if (prefix == null) {
                    throw new ArgumentException(Res.GetString(Res.Xml_UndefNamespace, ns));
                }
                await WriteStringAsync(prefix).ConfigureAwait(false);
                await WriteStringAsync(":").ConfigureAwait(false);
            }
            await WriteStringAsync(localName).ConfigureAwait(false);
        }

        // XmlReader Helper Methods

        // Writes out all the attributes found at the current position in the specified XmlReader.
        public virtual async Task WriteAttributesAsync(XmlReader reader, bool defattr) {
            if (null == reader) {
                throw new ArgumentNullException("reader");
            }

            if (reader.NodeType == XmlNodeType.Element || reader.NodeType == XmlNodeType.XmlDeclaration) {
                if (reader.MoveToFirstAttribute()) {
                    await WriteAttributesAsync(reader, defattr).ConfigureAwait(false);
                    reader.MoveToElement();
                }
            }
            else if (reader.NodeType != XmlNodeType.Attribute) {
                throw new XmlException(Res.Xml_InvalidPosition, string.Empty);
            }
            else {
                do {
                    // we need to check both XmlReader.IsDefault and XmlReader.SchemaInfo.IsDefault. 
                    // If either of these is true and defattr=false, we should not write the attribute out
                    if (defattr || !reader.IsDefaultInternal) {
                        await WriteStartAttributeAsync(reader.Prefix, reader.LocalName, reader.NamespaceURI).ConfigureAwait(false);
                        while (reader.ReadAttributeValue()) {
                            if (reader.NodeType == XmlNodeType.EntityReference) {
                                await WriteEntityRefAsync(reader.Name).ConfigureAwait(false);
                            }
                            else {
                                await WriteStringAsync(reader.Value).ConfigureAwait(false);
                            }
                        }
                        await WriteEndAttributeAsync().ConfigureAwait(false);
                    }
                }
                while (reader.MoveToNextAttribute());
            }
        }

        // Copies the current node from the given reader to the writer (including child nodes), and if called on an element moves the XmlReader 
        // to the corresponding end element.
        public virtual Task WriteNodeAsync(XmlReader reader, bool defattr) {
            if (null == reader) {
                throw new ArgumentNullException("reader");
            }

            if (reader.Settings != null && reader.Settings.Async) {
                return WriteNodeAsync_CallAsyncReader(reader, defattr);
            }
            else {
                return WriteNodeAsync_CallSyncReader(reader, defattr);
            }
        }


        // Copies the current node from the given reader to the writer (including child nodes), and if called on an element moves the XmlReader 
        // to the corresponding end element.
        //use sync methods on the reader
        internal async Task WriteNodeAsync_CallSyncReader(XmlReader reader, bool defattr) {
        
            bool canReadChunk = reader.CanReadValueChunk;
            int d = reader.NodeType == XmlNodeType.None ? -1 : reader.Depth;
            do {
                switch (reader.NodeType) {
                    case XmlNodeType.Element:
                        await WriteStartElementAsync(reader.Prefix, reader.LocalName, reader.NamespaceURI).ConfigureAwait(false);
                        await WriteAttributesAsync(reader, defattr).ConfigureAwait(false);
                        if (reader.IsEmptyElement) {
                            await WriteEndElementAsync().ConfigureAwait(false);
                            break;
                        }
                        break;
                    case XmlNodeType.Text:
                        if (canReadChunk) {
                            if (writeNodeBuffer == null) {
                                writeNodeBuffer = new char[WriteNodeBufferSize];
                            }
                            int read;
                            while ((read = reader.ReadValueChunk(writeNodeBuffer, 0, WriteNodeBufferSize)) > 0) {
                                await this.WriteCharsAsync(writeNodeBuffer, 0, read).ConfigureAwait(false);
                            }
                        }
                        else {
                            await WriteStringAsync(reader.Value).ConfigureAwait(false);
                        }
                        break;
                    case XmlNodeType.Whitespace:
                    case XmlNodeType.SignificantWhitespace:
                        await WriteWhitespaceAsync(reader.Value).ConfigureAwait(false);
                        break;
                    case XmlNodeType.CDATA:
                        await WriteCDataAsync(reader.Value).ConfigureAwait(false);
                        break;
                    case XmlNodeType.EntityReference:
                        await WriteEntityRefAsync(reader.Name).ConfigureAwait(false);
                        break;
                    case XmlNodeType.XmlDeclaration:
                    case XmlNodeType.ProcessingInstruction:
                        await WriteProcessingInstructionAsync(reader.Name, reader.Value).ConfigureAwait(false);
                        break;
                    case XmlNodeType.DocumentType:
                        await WriteDocTypeAsync(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value).ConfigureAwait(false);
                        break;

                    case XmlNodeType.Comment:
                        await WriteCommentAsync(reader.Value).ConfigureAwait(false);
                        break;
                    case XmlNodeType.EndElement:
                        await WriteFullEndElementAsync().ConfigureAwait(false);
                        break;
                }
            } while (reader.Read() && (d < reader.Depth || (d == reader.Depth && reader.NodeType == XmlNodeType.EndElement)));
        
        }

        // Copies the current node from the given reader to the writer (including child nodes), and if called on an element moves the XmlReader 
        // to the corresponding end element.
        //use async methods on the reader
        internal async Task WriteNodeAsync_CallAsyncReader(XmlReader reader, bool defattr) {
            bool canReadChunk = reader.CanReadValueChunk;
            int d = reader.NodeType == XmlNodeType.None ? -1 : reader.Depth;
            do {
                switch (reader.NodeType) {
                    case XmlNodeType.Element:
                        await WriteStartElementAsync(reader.Prefix, reader.LocalName, reader.NamespaceURI).ConfigureAwait(false);
                        await WriteAttributesAsync(reader, defattr).ConfigureAwait(false);
                        if (reader.IsEmptyElement) {
                            await WriteEndElementAsync().ConfigureAwait(false);
                            break;
                        }
                        break;
                    case XmlNodeType.Text:
                        if (canReadChunk) {
                            if (writeNodeBuffer == null) {
                                writeNodeBuffer = new char[WriteNodeBufferSize];
                            }
                            int read;
                            while ((read = await reader.ReadValueChunkAsync(writeNodeBuffer, 0, WriteNodeBufferSize).ConfigureAwait(false)) > 0) {
                                await this.WriteCharsAsync(writeNodeBuffer, 0, read).ConfigureAwait(false);
                            }
                        }
                        else {
                            //reader.Value may block on Text or WhiteSpace node, use GetValueAsync
                            await WriteStringAsync(await reader.GetValueAsync().ConfigureAwait(false)).ConfigureAwait(false);
                        }
                        break;
                    case XmlNodeType.Whitespace:
                    case XmlNodeType.SignificantWhitespace:
                        await WriteWhitespaceAsync(await reader.GetValueAsync().ConfigureAwait(false)).ConfigureAwait(false);
                        break;
                    case XmlNodeType.CDATA:
                        await WriteCDataAsync(reader.Value).ConfigureAwait(false);
                        break;
                    case XmlNodeType.EntityReference:
                        await WriteEntityRefAsync(reader.Name).ConfigureAwait(false);
                        break;
                    case XmlNodeType.XmlDeclaration:
                    case XmlNodeType.ProcessingInstruction:
                        await WriteProcessingInstructionAsync(reader.Name, reader.Value).ConfigureAwait(false);
                        break;
                    case XmlNodeType.DocumentType:
                        await WriteDocTypeAsync(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value).ConfigureAwait(false);
                        break;

                    case XmlNodeType.Comment:
                        await WriteCommentAsync(reader.Value).ConfigureAwait(false);
                        break;
                    case XmlNodeType.EndElement:
                        await WriteFullEndElementAsync().ConfigureAwait(false);
                        break;
                }
            } while (await reader.ReadAsync().ConfigureAwait(false) && (d < reader.Depth || (d == reader.Depth && reader.NodeType == XmlNodeType.EndElement)));
        }

#if !SILVERLIGHT // Removing dependency on XPathNavigator
        // Copies the current node from the given XPathNavigator to the writer (including child nodes).
        public virtual async Task WriteNodeAsync(XPathNavigator navigator, bool defattr) {
            if (navigator == null) {
                throw new ArgumentNullException("navigator");
            }
            int iLevel = 0;

            navigator = navigator.Clone();

            while (true) {
                bool mayHaveChildren = false;
                XPathNodeType nodeType = navigator.NodeType;

                switch (nodeType) {
                    case XPathNodeType.Element:
                        await WriteStartElementAsync(navigator.Prefix, navigator.LocalName, navigator.NamespaceURI).ConfigureAwait(false);

                        // Copy attributes
                        if (navigator.MoveToFirstAttribute()) {
                            do {
                                IXmlSchemaInfo schemaInfo = navigator.SchemaInfo;
                                if (defattr || (schemaInfo == null || !schemaInfo.IsDefault)) {
                                    await WriteStartAttributeAsync(navigator.Prefix, navigator.LocalName, navigator.NamespaceURI).ConfigureAwait(false);
                                    // copy string value to writer
                                    await WriteStringAsync(navigator.Value).ConfigureAwait(false);
                                    await WriteEndAttributeAsync().ConfigureAwait(false);
                                }
                            } while (navigator.MoveToNextAttribute());
                            navigator.MoveToParent();
                        }

                        // Copy namespaces
                        if (navigator.MoveToFirstNamespace(XPathNamespaceScope.Local)) {
                            await WriteLocalNamespacesAsync(navigator).ConfigureAwait(false);
                            navigator.MoveToParent();
                        }
                        mayHaveChildren = true;
                        break;
                    case XPathNodeType.Attribute:
                        // do nothing on root level attribute
                        break;
                    case XPathNodeType.Text:
                        await WriteStringAsync(navigator.Value).ConfigureAwait(false);
                        break;
                    case XPathNodeType.SignificantWhitespace:
                    case XPathNodeType.Whitespace:
                        await WriteWhitespaceAsync(navigator.Value).ConfigureAwait(false);
                        break;
                    case XPathNodeType.Root:
                        mayHaveChildren = true;
                        break;
                    case XPathNodeType.Comment:
                        await WriteCommentAsync(navigator.Value).ConfigureAwait(false);
                        break;
                    case XPathNodeType.ProcessingInstruction:
                        await WriteProcessingInstructionAsync(navigator.LocalName, navigator.Value).ConfigureAwait(false);
                        break;
                    case XPathNodeType.Namespace:
                        // do nothing on root level namespace
                        break;
                    default:
                        Debug.Assert(false);
                        break;
                }

                if (mayHaveChildren) {
                    // If children exist, move down to next level
                    if (navigator.MoveToFirstChild()) {
                        iLevel++;
                        continue;
                    }
                    else {
                        // EndElement
                        if (navigator.NodeType == XPathNodeType.Element) {
                            if (navigator.IsEmptyElement) {
                                await WriteEndElementAsync().ConfigureAwait(false);
                            }
                            else {
                                await WriteFullEndElementAsync().ConfigureAwait(false);
                            }
                        }
                    }
                }

                // No children
                while (true) {
                    if (iLevel == 0) {
                        // The entire subtree has been copied
                        return;
                    }

                    if (navigator.MoveToNext()) {
                        // Found a sibling, so break to outer loop
                        break;
                    }

                    // No siblings, so move up to previous level
                    iLevel--;
                    navigator.MoveToParent();

                    // EndElement
                    if (navigator.NodeType == XPathNodeType.Element)
                        await WriteFullEndElementAsync().ConfigureAwait(false);
                }
            }
        }
#endif

        // Element Helper Methods

        // Writes out an attribute with the specified name, namespace URI, and string value.
        public async Task WriteElementStringAsync(string prefix, String localName, String ns, String value) {
            await WriteStartElementAsync(prefix, localName, ns).ConfigureAwait(false);
            if (null != value && 0 != value.Length) {
                await WriteStringAsync(value).ConfigureAwait(false);
            }
            await WriteEndElementAsync().ConfigureAwait(false);
        }

#if !SILVERLIGHT // Removing dependency on XPathNavigator
        // Copy local namespaces on the navigator's current node to the raw writer. The namespaces are returned by the navigator in reversed order. 
        // The recursive call reverses them back.
        private async Task WriteLocalNamespacesAsync(XPathNavigator nsNav) {
            string prefix = nsNav.LocalName;
            string ns = nsNav.Value;

            if (nsNav.MoveToNextNamespace(XPathNamespaceScope.Local)) {
                await WriteLocalNamespacesAsync(nsNav).ConfigureAwait(false);
            }

            if (prefix.Length == 0) {
                await WriteAttributeStringAsync(string.Empty, "xmlns", XmlReservedNs.NsXmlNs, ns).ConfigureAwait(false);
            }
            else {
                await WriteAttributeStringAsync("xmlns", prefix, XmlReservedNs.NsXmlNs, ns).ConfigureAwait(false);
            }
        }
#endif

    }
}