Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Xml / System / Xml / Core / XmlWriter.cs
blobf4ca61856cf0ed288b54ce27f58629b7df965443
2 //------------------------------------------------------------------------------
3 // <copyright file="XmlWriter.cs" company="Microsoft">
4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // </copyright>
6 // <owner current="true" primary="true">Microsoft</owner>
7 //------------------------------------------------------------------------------
9 using System;
10 using System.IO;
11 using System.Text;
12 #if !SILVERLIGHT
13 using System.Xml.XPath;
14 #endif
15 using System.Xml.Schema;
16 using System.Diagnostics;
17 using System.Collections.Generic;
18 using System.Globalization;
19 using System.Runtime.Versioning;
21 namespace System.Xml {
23 // Specifies the state of the XmlWriter.
24 public enum WriteState {
25 // Nothing has been written yet.
26 Start,
28 // Writing the prolog.
29 Prolog,
31 // Writing a the start tag for an element.
32 Element,
34 // Writing an attribute value.
35 Attribute,
37 // Writing element content.
38 Content,
40 // XmlWriter is closed; Close has been called.
41 Closed,
43 // Writer is in error state.
44 Error,
47 // Represents a writer that provides fast non-cached forward-only way of generating XML streams containing XML documents
48 // that conform to the W3C Extensible Markup Language (XML) 1.0 specification and the Namespaces in XML specification.
49 public abstract partial class XmlWriter : IDisposable {
51 // Helper buffer for WriteNode(XmlReader, bool)
52 char[] writeNodeBuffer;
54 // Constants
55 const int WriteNodeBufferSize = 1024;
57 // Returns the settings describing the features of the the writer. Returns null for V1 XmlWriters (XmlTextWriter).
58 public virtual XmlWriterSettings Settings {
59 get {
60 return null;
64 // Write methods
65 // Writes out the XML declaration with the version "1.0".
67 public abstract void WriteStartDocument();
69 //Writes out the XML declaration with the version "1.0" and the speficied standalone attribute.
71 public abstract void WriteStartDocument(bool standalone);
73 //Closes any open elements or attributes and puts the writer back in the Start state.
75 public abstract void WriteEndDocument();
77 // Writes out the DOCTYPE declaration with the specified name and optional attributes.
79 public abstract void WriteDocType(string name, string pubid, string sysid, string subset);
81 // Writes out the specified start tag and associates it with the given namespace.
82 public void WriteStartElement(string localName, string ns) {
83 WriteStartElement(null, localName, ns);
86 // Writes out the specified start tag and associates it with the given namespace and prefix.
88 public abstract void WriteStartElement(string prefix, string localName, string ns);
90 // Writes out a start tag with the specified local name with no namespace.
91 public void WriteStartElement(string localName) {
92 WriteStartElement(null, localName, (string)null);
95 // Closes one element and pops the corresponding namespace scope.
97 public abstract void WriteEndElement();
99 // Closes one element and pops the corresponding namespace scope. Writes out a full end element tag, e.g. </element>.
101 public abstract void WriteFullEndElement();
103 // Writes out the attribute with the specified LocalName, value, and NamespaceURI.
104 #if !SILVERLIGHT
105 #endif
106 public void WriteAttributeString(string localName, string ns, string value) {
107 WriteStartAttribute(null, localName, ns);
108 WriteString(value);
109 WriteEndAttribute();
112 // Writes out the attribute with the specified LocalName and value.
113 public void WriteAttributeString(string localName, string value) {
114 WriteStartAttribute(null, localName, (string)null);
115 WriteString(value);
116 WriteEndAttribute();
119 // Writes out the attribute with the specified prefix, LocalName, NamespaceURI and value.
120 public void WriteAttributeString(string prefix, string localName, string ns, string value) {
121 WriteStartAttribute(prefix, localName, ns);
122 WriteString(value);
123 WriteEndAttribute();
126 // Writes the start of an attribute.
127 public void WriteStartAttribute(string localName, string ns) {
128 WriteStartAttribute(null, localName, ns);
131 // Writes the start of an attribute.
133 public abstract void WriteStartAttribute(string prefix, string localName, string ns);
135 // Writes the start of an attribute.
136 public void WriteStartAttribute(string localName) {
137 WriteStartAttribute(null, localName, (string)null);
140 // Closes the attribute opened by WriteStartAttribute call.
142 public abstract void WriteEndAttribute();
144 // Writes out a <![CDATA[...]]>; block containing the specified text.
146 public abstract void WriteCData(string text);
148 // Writes out a comment <!--...-->; containing the specified text.
150 public abstract void WriteComment(string text);
152 // Writes out a processing instruction with a space between the name and text as follows: <?name text?>
154 public abstract void WriteProcessingInstruction(string name, string text);
156 // Writes out an entity reference as follows: "&"+name+";".
158 public abstract void WriteEntityRef(string name);
160 // Forces the generation of a character entity for the specified Unicode character value.
162 public abstract void WriteCharEntity(char ch);
164 // Writes out the given whitespace.
166 public abstract void WriteWhitespace(string ws);
168 // Writes out the specified text content.
170 public abstract void WriteString(string text);
172 // Write out the given surrogate pair as an entity reference.
174 public abstract void WriteSurrogateCharEntity(char lowChar, char highChar);
176 // Writes out the specified text content.
178 public abstract void WriteChars(char[] buffer, int index, int count);
180 // Writes raw markup from the given character buffer.
182 public abstract void WriteRaw(char[] buffer, int index, int count);
184 // Writes raw markup from the given string.
186 public abstract void WriteRaw(string data);
188 // Encodes the specified binary bytes as base64 and writes out the resulting text.
190 public abstract void WriteBase64(byte[] buffer, int index, int count);
192 // Encodes the specified binary bytes as binhex and writes out the resulting text.
193 public virtual void WriteBinHex(byte[] buffer, int index, int count) {
194 BinHexEncoder.Encode(buffer, index, count, this);
197 // Returns the state of the XmlWriter.
198 public abstract WriteState WriteState { get; }
200 // Closes the XmlWriter and the underlying stream/TextReader (if Settings.CloseOutput is true).
201 public virtual void Close() { }
203 // Flushes data that is in the internal buffers into the underlying streams/TextReader and flushes the stream/TextReader.
205 public abstract void Flush();
207 // Returns the closest prefix defined in the current namespace scope for the specified namespace URI.
208 public abstract string LookupPrefix(string ns);
210 // Gets an XmlSpace representing the current xml:space scope.
211 public virtual XmlSpace XmlSpace {
212 get {
213 return XmlSpace.Default;
217 // Gets the current xml:lang scope.
218 public virtual string XmlLang {
219 get {
220 return string.Empty;
224 // Scalar Value Methods
226 // Writes out the specified name, ensuring it is a valid NmToken according to the XML specification
227 // (http://www.w3.org/TR/1998/REC-xml-19980210#NT-Name).
228 public virtual void WriteNmToken(string name) {
229 if (name == null || name.Length == 0) {
230 throw new ArgumentException(Res.GetString(Res.Xml_EmptyName));
232 WriteString(XmlConvert.VerifyNMTOKEN(name, ExceptionType.ArgumentException));
235 // Writes out the specified name, ensuring it is a valid Name according to the XML specification
236 // (http://www.w3.org/TR/1998/REC-xml-19980210#NT-Name).
237 public virtual void WriteName(string name) {
238 WriteString(XmlConvert.VerifyQName(name, ExceptionType.ArgumentException));
241 // Writes out the specified namespace-qualified name by looking up the prefix that is in scope for the given namespace.
242 public virtual void WriteQualifiedName(string localName, string ns) {
243 if (ns != null && ns.Length > 0) {
244 string prefix = LookupPrefix(ns);
245 if (prefix == null) {
246 throw new ArgumentException(Res.GetString(Res.Xml_UndefNamespace, ns));
248 WriteString(prefix);
249 WriteString(":");
251 WriteString(localName);
254 // Writes out the specified value.
255 public virtual void WriteValue(object value) {
256 if (value == null) {
257 throw new ArgumentNullException("value");
259 #if SILVERLIGHT
260 WriteString(XmlUntypedStringConverter.Instance.ToString(value, null));
261 #else
262 WriteString(XmlUntypedConverter.Untyped.ToString(value, null));
263 #endif
266 // Writes out the specified value.
267 public virtual void WriteValue(string value) {
268 if (value == null) {
270 return;
273 WriteString(value);
276 // Writes out the specified value.
277 public virtual void WriteValue(bool value) {
278 WriteString(XmlConvert.ToString(value));
281 // Writes out the specified value.
282 public virtual void WriteValue(DateTime value) {
283 WriteString(XmlConvert.ToString(value, XmlDateTimeSerializationMode.RoundtripKind));
286 // Writes out the specified value.
287 public virtual void WriteValue(DateTimeOffset value) {
288 // Under Win8P, WriteValue(DateTime) will invoke this overload, but custom writers
289 // might not have implemented it. This base implementation should call WriteValue(DateTime).
290 // The following conversion results in the same string as calling ToString with DateTimeOffset.
291 if (value.Offset != TimeSpan.Zero) {
292 WriteValue(value.LocalDateTime);
294 else {
295 WriteValue(value.UtcDateTime);
299 // Writes out the specified value.
300 public virtual void WriteValue(double value) {
301 WriteString(XmlConvert.ToString(value));
304 // Writes out the specified value.
305 public virtual void WriteValue(float value) {
306 WriteString(XmlConvert.ToString(value));
309 // Writes out the specified value.
310 public virtual void WriteValue(decimal value) {
311 WriteString(XmlConvert.ToString(value));
314 // Writes out the specified value.
315 public virtual void WriteValue(int value) {
316 WriteString(XmlConvert.ToString(value));
319 // Writes out the specified value.
320 public virtual void WriteValue(long value) {
321 WriteString(XmlConvert.ToString(value));
324 // XmlReader Helper Methods
326 // Writes out all the attributes found at the current position in the specified XmlReader.
327 public virtual void WriteAttributes(XmlReader reader, bool defattr) {
328 if (null == reader) {
329 throw new ArgumentNullException("reader");
332 if (reader.NodeType == XmlNodeType.Element || reader.NodeType == XmlNodeType.XmlDeclaration) {
333 if (reader.MoveToFirstAttribute()) {
334 WriteAttributes(reader, defattr);
335 reader.MoveToElement();
338 else if (reader.NodeType != XmlNodeType.Attribute) {
339 throw new XmlException(Res.Xml_InvalidPosition, string.Empty);
341 else {
342 do {
343 // we need to check both XmlReader.IsDefault and XmlReader.SchemaInfo.IsDefault.
344 // If either of these is true and defattr=false, we should not write the attribute out
345 if (defattr || !reader.IsDefaultInternal) {
346 WriteStartAttribute(reader.Prefix, reader.LocalName, reader.NamespaceURI);
347 while (reader.ReadAttributeValue()) {
348 if (reader.NodeType == XmlNodeType.EntityReference) {
349 WriteEntityRef(reader.Name);
351 else {
352 WriteString(reader.Value);
355 WriteEndAttribute();
358 while (reader.MoveToNextAttribute());
362 // Copies the current node from the given reader to the writer (including child nodes), and if called on an element moves the XmlReader
363 // to the corresponding end element.
364 public virtual void WriteNode(XmlReader reader, bool defattr) {
365 if (null == reader) {
366 throw new ArgumentNullException("reader");
369 bool canReadChunk = reader.CanReadValueChunk;
370 int d = reader.NodeType == XmlNodeType.None ? -1 : reader.Depth;
371 do {
372 switch (reader.NodeType) {
373 case XmlNodeType.Element:
374 WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
375 WriteAttributes(reader, defattr);
376 if (reader.IsEmptyElement) {
377 WriteEndElement();
378 break;
380 break;
381 case XmlNodeType.Text:
382 if (canReadChunk) {
383 if (writeNodeBuffer == null) {
384 writeNodeBuffer = new char[WriteNodeBufferSize];
386 int read;
387 while ((read = reader.ReadValueChunk(writeNodeBuffer, 0, WriteNodeBufferSize)) > 0) {
388 this.WriteChars(writeNodeBuffer, 0, read);
391 else {
393 WriteString(reader.Value);
396 break;
397 case XmlNodeType.Whitespace:
398 case XmlNodeType.SignificantWhitespace:
400 WriteWhitespace(reader.Value);
402 break;
403 case XmlNodeType.CDATA:
404 WriteCData(reader.Value);
405 break;
406 case XmlNodeType.EntityReference:
407 WriteEntityRef(reader.Name);
408 break;
409 case XmlNodeType.XmlDeclaration:
410 case XmlNodeType.ProcessingInstruction:
411 WriteProcessingInstruction(reader.Name, reader.Value);
412 break;
413 case XmlNodeType.DocumentType:
414 WriteDocType(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value);
415 break;
417 case XmlNodeType.Comment:
418 WriteComment(reader.Value);
419 break;
420 case XmlNodeType.EndElement:
421 WriteFullEndElement();
422 break;
424 } while (reader.Read() && (d < reader.Depth || (d == reader.Depth && reader.NodeType == XmlNodeType.EndElement)));
427 #if !SILVERLIGHT // Removing dependency on XPathNavigator
428 // Copies the current node from the given XPathNavigator to the writer (including child nodes).
429 public virtual void WriteNode(XPathNavigator navigator, bool defattr) {
430 if (navigator == null) {
431 throw new ArgumentNullException("navigator");
433 int iLevel = 0;
435 navigator = navigator.Clone();
437 while (true) {
438 bool mayHaveChildren = false;
439 XPathNodeType nodeType = navigator.NodeType;
441 switch (nodeType) {
442 case XPathNodeType.Element:
443 WriteStartElement(navigator.Prefix, navigator.LocalName, navigator.NamespaceURI);
445 // Copy attributes
446 if (navigator.MoveToFirstAttribute()) {
447 do {
448 IXmlSchemaInfo schemaInfo = navigator.SchemaInfo;
449 if (defattr || (schemaInfo == null || !schemaInfo.IsDefault)) {
450 WriteStartAttribute(navigator.Prefix, navigator.LocalName, navigator.NamespaceURI);
451 // copy string value to writer
452 WriteString(navigator.Value);
453 WriteEndAttribute();
455 } while (navigator.MoveToNextAttribute());
456 navigator.MoveToParent();
459 // Copy namespaces
460 if (navigator.MoveToFirstNamespace(XPathNamespaceScope.Local)) {
461 WriteLocalNamespaces(navigator);
462 navigator.MoveToParent();
464 mayHaveChildren = true;
465 break;
466 case XPathNodeType.Attribute:
467 // do nothing on root level attribute
468 break;
469 case XPathNodeType.Text:
470 WriteString(navigator.Value);
471 break;
472 case XPathNodeType.SignificantWhitespace:
473 case XPathNodeType.Whitespace:
474 WriteWhitespace(navigator.Value);
475 break;
476 case XPathNodeType.Root:
477 mayHaveChildren = true;
478 break;
479 case XPathNodeType.Comment:
480 WriteComment(navigator.Value);
481 break;
482 case XPathNodeType.ProcessingInstruction:
483 WriteProcessingInstruction(navigator.LocalName, navigator.Value);
484 break;
485 case XPathNodeType.Namespace:
486 // do nothing on root level namespace
487 break;
488 default:
489 Debug.Assert(false);
490 break;
493 if (mayHaveChildren) {
494 // If children exist, move down to next level
495 if (navigator.MoveToFirstChild()) {
496 iLevel++;
497 continue;
499 else {
500 // EndElement
501 if (navigator.NodeType == XPathNodeType.Element) {
502 if (navigator.IsEmptyElement) {
503 WriteEndElement();
505 else {
506 WriteFullEndElement();
512 // No children
513 while (true) {
514 if (iLevel == 0) {
515 // The entire subtree has been copied
516 return;
519 if (navigator.MoveToNext()) {
520 // Found a sibling, so break to outer loop
521 break;
524 // No siblings, so move up to previous level
525 iLevel--;
526 navigator.MoveToParent();
528 // EndElement
529 if (navigator.NodeType == XPathNodeType.Element)
530 WriteFullEndElement();
534 #endif
536 // Element Helper Methods
538 // Writes out an element with the specified name containing the specified string value.
539 public void WriteElementString(string localName, String value) {
540 WriteElementString(localName, null, value);
543 // Writes out an attribute with the specified name, namespace URI and string value.
544 public void WriteElementString(string localName, String ns, String value) {
545 WriteStartElement(localName, ns);
546 if (null != value && 0 != value.Length) {
547 WriteString(value);
549 WriteEndElement();
552 // Writes out an attribute with the specified name, namespace URI, and string value.
553 public void WriteElementString(string prefix, String localName, String ns, String value) {
554 WriteStartElement(prefix, localName, ns);
555 if (null != value && 0 != value.Length) {
556 WriteString(value);
558 WriteEndElement();
561 public void Dispose() {
562 Dispose(true);
565 // Dispose the underline stream objects (calls Close on the XmlWriter)
566 protected virtual void Dispose(bool disposing) {
567 if (disposing && WriteState != WriteState.Closed) {
568 Close();
572 #if !SILVERLIGHT // Removing dependency on XPathNavigator
573 // Copy local namespaces on the navigator's current node to the raw writer. The namespaces are returned by the navigator in reversed order.
574 // The recursive call reverses them back.
575 private void WriteLocalNamespaces(XPathNavigator nsNav) {
576 string prefix = nsNav.LocalName;
577 string ns = nsNav.Value;
579 if (nsNav.MoveToNextNamespace(XPathNamespaceScope.Local)) {
580 WriteLocalNamespaces(nsNav);
583 if (prefix.Length == 0) {
584 WriteAttributeString(string.Empty, "xmlns", XmlReservedNs.NsXmlNs, ns);
586 else {
587 WriteAttributeString("xmlns", prefix, XmlReservedNs.NsXmlNs, ns);
590 #endif
593 // Static methods for creating writers
595 #if !SILVERLIGHT
596 // Creates an XmlWriter for writing into the provided file.
597 [ResourceConsumption(ResourceScope.Machine)]
598 [ResourceExposure(ResourceScope.Machine)]
599 public static XmlWriter Create(string outputFileName) {
600 return Create(outputFileName, null);
603 // Creates an XmlWriter for writing into the provided file with the specified settings.
604 [ResourceConsumption(ResourceScope.Machine)]
605 [ResourceExposure(ResourceScope.Machine)]
606 public static XmlWriter Create(string outputFileName, XmlWriterSettings settings) {
607 if (settings == null) {
608 settings = new XmlWriterSettings();
610 return settings.CreateWriter(outputFileName);
612 #endif
614 // Creates an XmlWriter for writing into the provided stream.
615 public static XmlWriter Create(Stream output) {
616 return Create(output, null);
619 // Creates an XmlWriter for writing into the provided stream with the specified settings.
620 public static XmlWriter Create(Stream output, XmlWriterSettings settings) {
621 if (settings == null) {
622 settings = new XmlWriterSettings();
624 return settings.CreateWriter(output);
627 // Creates an XmlWriter for writing into the provided TextWriter.
628 public static XmlWriter Create(TextWriter output) {
629 return Create(output, null);
632 // Creates an XmlWriter for writing into the provided TextWriter with the specified settings.
633 public static XmlWriter Create(TextWriter output, XmlWriterSettings settings) {
634 if (settings == null) {
635 settings = new XmlWriterSettings();
637 return settings.CreateWriter(output);
640 // Creates an XmlWriter for writing into the provided StringBuilder.
641 public static XmlWriter Create(StringBuilder output) {
642 return Create(output, null);
645 // Creates an XmlWriter for writing into the provided StringBuilder with the specified settings.
646 public static XmlWriter Create(StringBuilder output, XmlWriterSettings settings) {
647 if (settings == null) {
648 settings = new XmlWriterSettings();
650 if (output == null) {
651 throw new ArgumentNullException("output");
653 return settings.CreateWriter(new StringWriter(output, CultureInfo.InvariantCulture));
656 // Creates an XmlWriter wrapped around the provided XmlWriter with the default settings.
657 public static XmlWriter Create(XmlWriter output) {
658 return Create(output, null);
661 // Creates an XmlWriter wrapped around the provided XmlWriter with the specified settings.
662 public static XmlWriter Create(XmlWriter output, XmlWriterSettings settings) {
663 if (settings == null) {
664 settings = new XmlWriterSettings();
666 return settings.CreateWriter(output);